diff --git a/modules/saml/lib/IdP/SAML1.php b/modules/saml/lib/IdP/SAML1.php new file mode 100644 index 0000000000000000000000000000000000000000..12b9e7a64ad68181927e46bbdb41e8dfd1941ad8 --- /dev/null +++ b/modules/saml/lib/IdP/SAML1.php @@ -0,0 +1,117 @@ +<?php + +/** + * IdP implementation for SAML 1.1 protocol. + * + * @package simpleSAMLphp + * @version $Id$ + */ +class sspmod_saml_IdP_SAML1 { + + /** + * Send a response to the SP. + * + * @param array $state The authentication state. + */ + public static function sendResponse(array $state) { + assert('isset($state["Attributes"])'); + assert('isset($state["SPMetadata"])'); + assert('isset($state["saml:shire"])'); + assert('array_key_exists("saml:target", $state)'); // Can be NULL. + + $spMetadata = $state["SPMetadata"]; + $spEntityId = $spMetadata['entityid']; + + SimpleSAML_Logger::info('Sending SAML 1.1 Response to ' . var_export($spEntityId, TRUE)); + + $attributes = $state['Attributes']; + $shire = $state['saml:shire']; + $target = $state['saml:target']; + + $idp = SimpleSAML_IdP::getByState($state); + + $idpMetadata = $idp->getConfig()->toArray(); + + $config = SimpleSAML_Configuration::getInstance(); + $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + + /* Generate and send response. */ + $ar = new SimpleSAML_XML_Shib13_AuthnResponse(); + $authnResponseXML = $ar->generate($idpMetadata, $spMetadata, $shire, $attributes); + + $httppost = new SimpleSAML_Bindings_Shib13_HTTPPost($config, $metadata); + $httppost->sendResponse($authnResponseXML, $idpMetadata, $spMetadata, $target, $shire); + } + + + /** + * Receive an authentication request. + * + * @param SimpleSAML_IdP $idp The IdP we are receiving it for. + */ + public static function receiveAuthnRequest(SimpleSAML_IdP $idp) { + + if (isset($_REQUEST['cookieTime'])) { + $cookieTime = (int)$_REQUEST['cookieTime']; + if ($cookieTime + 5 > time()) { + /* + * Less than five seconds has passed since we were + * here the last time. Cookies are probably disabled. + */ + SimpleSAML_Utilities::checkCookie(SimpleSAML_Utilities::selfURL()); + } + } + + if (!isset($_REQUEST['providerId'])) { + throw new SimpleSAML_Error_BadRequest('Missing providerId parameter.'); + } + $spEntityId = (string)$_REQUEST['providerId']; + + if (!isset($_REQUEST['shire'])) { + throw new SimpleSAML_Error_BadRequest('Missing shire parameter.'); + } + $shire = (string)$_REQUEST['shire']; + + if (isset($_REQUEST['target'])) { + $target = $_REQUEST['target']; + } else { + $target = NULL; + } + + SimpleSAML_Logger::info('Shib1.3 - IdP.SSOService: Got incoming Shib authnRequest from ' . var_export($spEntityId, TRUE) . '.'); + + $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'shib13-sp-remote'); + + $found = FALSE; + foreach ($spMetadata->getEndpoints('AssertionConsumerService') as $ep) { + if ($ep['Binding'] !== 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post') { + continue; + } + if ($ep['Location'] !== $shire) { + continue; + } + $found = TRUE; + break; + } + if (!$found) { + throw new Exception('Invalid AssertionConsumerService for SP ' . + var_export($spEntityId, TRUE) . ': ' . var_export($shire, TRUE)); + } + + $sessionLostURL = SimpleSAML_Utilities::addURLparameter( + SimpleSAML_Utilities::selfURL(), + array('cookieTime' => time())); + + $state = array( + 'Responder' => array('sspmod_saml_IdP_SAML1', 'sendResponse'), + 'SPMetadata' => $spMetadata->toArray(), + + 'saml:shire' => $shire, + 'saml:target' => $target, + ); + + $idp->handleAuthenticationRequest($state); + } + +} diff --git a/www/shib13/idp/SSOService.php b/www/shib13/idp/SSOService.php index c5683541398f8ad808ac7cb97edf2f2b70097bbf..14de0d1664c7ed260bbc0d3236d54db21badacba 100644 --- a/www/shib13/idp/SSOService.php +++ b/www/shib13/idp/SSOService.php @@ -11,206 +11,27 @@ require_once('../../../www/_include.php'); -$config = SimpleSAML_Configuration::getInstance(); -$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); -$session = SimpleSAML_Session::getInstance(); - - SimpleSAML_Logger::info('Shib1.3 - IdP.SSOService: Accessing Shibboleth 1.3 IdP endpoint SSOService'); -if (!$config->getBoolean('enable.shib13-idp', false)) - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS'); - try { - $idpmetadata = $metadata->getMetaDataCurrent('shib13-idp-hosted'); -} catch (Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception); -} - -/* - * If the shire query parameter is set, we got an incoming Authentication Request - * at this interface. - * - * In this case, what we should do is to process the request and set the neccessary information - * from the request into the session object to be used later. - * - */ -if (isset($_GET['shire'])) { - - - try { - $authnrequest = new SimpleSAML_XML_Shib13_AuthnRequest($config, $metadata); - $authnrequest->parseGet($_GET); - - $requestid = $authnrequest->getRequestID(); - - /* - * Create an assoc array of the request to store in the session cache. - */ - $requestcache = array( - 'RequestID' => $requestid, - 'Issuer' => $authnrequest->getIssuer(), - 'shire' => $authnrequest->getShire(), - 'RelayState' => $authnrequest->getRelayState(), - ); - - SimpleSAML_Logger::info('Shib1.3 - IdP.SSOService: Got incoming Shib authnRequest requestid: ' . $requestid); - - if (empty($requestcache['Issuer'])) - throw new Exception('Could not retrieve issuer of the AuthNRequest (ProviderID)'); - - } catch(Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'PROCESSAUTHNREQUEST', $exception); + $config = SimpleSAML_Configuration::getInstance(); + if (!$config->getBoolean('enable.shib13-idp', FALSE)) { + throw new SimpleSAML_Error_Error('NOACCESS'); } + $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + $idpEntityId = $metadata->getMetaDataCurrentEntityID('shib13-idp-hosted'); + $idp = SimpleSAML_IdP::getById('saml1:' . $idpEntityId); + sspmod_saml_IdP_SAML1::receiveAuthnRequest($idp); + assert('FALSE'); -/* - * If we did not get an incoming Authenticaiton Request, we need a RequestID parameter. - * - * The RequestID parameter is used to retrieve the information stored in the session object - * related to the request that was received earlier. Usually the request is processed with - * code above, then the user is redirected to some login module, and when successfully authenticated - * the user isredirected back to this endpoint, and then the user will need to have the RequestID - * parmeter attached. - */ -} elseif(isset($_GET['RequestID'])) { - - try { - - $authId = $_GET['RequestID']; - - $requestcache = $session->getAuthnRequest('shib13', $authId); - - SimpleSAML_Logger::info('Shib1.3 - IdP.SSOService: Got incoming RequestID: '. $authId); - - if (!$requestcache) { - throw new Exception('Could not retrieve cached RequestID = ' . $authId); - } +} catch(SimpleSAML_Error_Error $e) { - } catch(Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'CACHEAUTHNREQUEST', $exception); - } - -} elseif(isset($_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM])) { + $e->show(); - /* Resume from authentication processing chain. */ - $authProcId = $_REQUEST[SimpleSAML_Auth_ProcessingChain::AUTHPARAM]; - $authProcState = SimpleSAML_Auth_ProcessingChain::fetchProcessedState($authProcId); - $requestcache = $authProcState['core:shib13-idp:requestcache']; +} catch(Exception $e) { -} else { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SSOSERVICEPARAMS'); -} + $e = new SimpleSAML_Error_Error('UNHANDLEDEXCEPTION', $e); + $e->show(); -/* Make sure that the issuer is a valid SP. */ -try { - $spMetadata = $metadata->getMetaDataConfig($requestcache['Issuer'], 'shib13-sp-remote'); -} catch (Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'PROCESSAUTHNREQUEST', $exception); -} - -/* Check whether we should authenticate with an AuthSource. Any time the auth-option matches a - * valid AuthSource, we assume that this is the case. - */ -if(SimpleSAML_Auth_Source::getById($idpmetadata['auth']) !== NULL) { - /* Authenticate with an AuthSource. */ - $authSource = TRUE; - $authority = $idpmetadata['auth']; -} else { - $authSource = FALSE; - $authority = SimpleSAML_Utilities::getAuthority($idpmetadata); } - -/* - * As we have passed the code above, we have an accociated request that is already processed. - * - * Now we check whether we have a authenticated session. If we do not have an authenticated session, - * we look up in the metadata of the IdP, to see what authenticaiton module to use, then we redirect - * the user to the authentication module, to authenticate. Later the user is redirected back to this - * endpoint - then the session is authenticated and set, and the user is redirected back with a RequestID - * parameter so we can retrieve the cached information from the request. - */ -if (!$session->isValid($authority) ) { - - $authId = SimpleSAML_Utilities::generateID(); - $session->setAuthnRequest('shib13', $authId, $requestcache); - - $redirectTo = SimpleSAML_Utilities::selfURLNoQuery() . '?RequestID=' . urlencode($authId); - - if($authSource) { - /* Authenticate with an AuthSource. */ - $hints = array( - 'SPMetadata' => $spMetadata->toArray(), - 'IdPMetadata' => $idpmetadata, - ); - - SimpleSAML_Auth_Default::initLogin($idpmetadata['auth'], $redirectTo, NULL, $hints); - } else { - $authurl = '/' . $config->getBaseURL() . $idpmetadata['auth']; - - SimpleSAML_Utilities::redirect($authurl, array( - 'RelayState' => $redirectTo, - 'AuthId' => $authId, - 'protocol' => 'shib13', - )); - } -} - -/* - * We got an request, and we hav a valid session. Then we send an AuthenticationResponse back to the - * service. - */ -try { - - /* Validate the Shire the response should be sent to. */ - $shire = $requestcache['shire']; - $foundACS = FALSE; - foreach ($spMetadata->getEndpoints('AssertionConsumerService') as $acs) { - if ($acs['Binding'] !== 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post') { - continue; - } - if ($acs['Location'] !== $shire) { - continue; - } - - SimpleSAML_Logger::info('Shib1.3 - IdP.SSOService: Found AssertionConsumerService: '. $acs); - $foundACS = TRUE; - break; - } - if (!$foundACS) { - throw new Exception('Invalid AssertionConsumerService for SP ' . - var_export($spMetadata->getString('entityid'), TRUE) . ': ' . var_export($shire, TRUE)); - } - - $attributes = $session->getAttributes(); - - /* Authentication processing operations. */ - if (!isset($authProcState)) { - /* Not processed. */ - $pc = new SimpleSAML_Auth_ProcessingChain($idpmetadata, $spMetadata->toArray(), 'idp'); - - $authProcState = array( - 'core:shib13-idp:requestcache' => $requestcache, - 'ReturnURL' => SimpleSAML_Utilities::selfURLNoQuery(), - 'Attributes' => $attributes, - 'Destination' => $spMetadata->toArray(), - 'Source' => $idpmetadata, - ); - - $pc->processState($authProcState); - } - - $attributes = $authProcState['Attributes']; - - /* Generate and send response. */ - $ar = new SimpleSAML_XML_Shib13_AuthnResponse(); - $authnResponseXML = $ar->generate($idpmetadata, $spMetadata->toArray(), $shire, $attributes); - - $httppost = new SimpleSAML_Bindings_Shib13_HTTPPost($config, $metadata); - $httppost->sendResponse($authnResponseXML, $idpmetadata, $spMetadata->toArray(), $requestcache['RelayState'], $shire); - -} catch(Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception); -} - -?> \ No newline at end of file