Skip to content
Snippets Groups Projects
Commit 83087121 authored by Jaime Perez Crespo's avatar Jaime Perez Crespo
Browse files

Reformat the code of the SAML2 ACS interface.

parent 18213a63
No related branches found
No related tags found
No related merge requests found
...@@ -25,170 +25,177 @@ try { ...@@ -25,170 +25,177 @@ try {
} }
if ($b instanceof SAML2_HTTPArtifact) { if ($b instanceof SAML2_HTTPArtifact) {
$b->setSPMetadata($spMetadata); $b->setSPMetadata($spMetadata);
} }
$response = $b->receive(); $response = $b->receive();
if (!($response instanceof SAML2_Response)) { if (!($response instanceof SAML2_Response)) {
throw new SimpleSAML_Error_BadRequest('Invalid message received to AssertionConsumerService endpoint.'); throw new SimpleSAML_Error_BadRequest('Invalid message received to AssertionConsumerService endpoint.');
} }
$idp = $response->getIssuer(); $idp = $response->getIssuer();
if ($idp === NULL) { if ($idp === null) {
/* No Issuer in the response. Look for an unencrypted assertion with an issuer. */ // no Issuer in the response. Look for an unencrypted assertion with an issuer
foreach ($response->getAssertions() as $a) { foreach ($response->getAssertions() as $a) {
if ($a instanceof SAML2_Assertion) { if ($a instanceof SAML2_Assertion) {
/* We found an unencrypted assertion - there should be an issuer here. */ // we found an unencrypted assertion, there should be an issuer here
$idp = $a->getIssuer(); $idp = $a->getIssuer();
break; break;
} }
} }
if ($idp === NULL) { if ($idp === null) {
/* No issuer found in the assertions. */ // no issuer found in the assertions
throw new Exception('Missing <saml:Issuer> in message delivered to AssertionConsumerService.'); throw new Exception('Missing <saml:Issuer> in message delivered to AssertionConsumerService.');
} }
} }
$session = SimpleSAML_Session::getSessionFromRequest(); $session = SimpleSAML_Session::getSessionFromRequest();
$prevAuth = $session->getAuthData($sourceId, 'saml:sp:prevAuth'); $prevAuth = $session->getAuthData($sourceId, 'saml:sp:prevAuth');
if ($prevAuth !== NULL && $prevAuth['id'] === $response->getId() && $prevAuth['issuer'] === $idp) { if ($prevAuth !== null && $prevAuth['id'] === $response->getId() && $prevAuth['issuer'] === $idp) {
/* OK, it looks like this message has the same issuer /* OK, it looks like this message has the same issuer
* and ID as the SP session we already have active. We * and ID as the SP session we already have active. We
* therefore assume that the user has somehow triggered * therefore assume that the user has somehow triggered
* a resend of the message. * a resend of the message.
* In that case we may as well just redo the previous redirect * In that case we may as well just redo the previous redirect
* instead of displaying a confusing error message. * instead of displaying a confusing error message.
*/ */
SimpleSAML_Logger::info('Duplicate SAML 2 response detected - ignoring the response and redirecting the user to the correct page.'); SimpleSAML_Logger::info(
if (isset($prevAuth['redirect'])) { 'Duplicate SAML 2 response detected - ignoring the response and redirecting the user to the correct page.'
\SimpleSAML\Utils\HTTP::redirectTrustedURL($prevAuth['redirect']); );
} if (isset($prevAuth['redirect'])) {
\SimpleSAML\Utils\HTTP::redirectTrustedURL($prevAuth['redirect']);
SimpleSAML_Logger::info('No RelayState or ReturnURL available, cannot redirect.'); }
throw new SimpleSAML_Error_Exception('Duplicate assertion received.');
SimpleSAML_Logger::info('No RelayState or ReturnURL available, cannot redirect.');
throw new SimpleSAML_Error_Exception('Duplicate assertion received.');
} }
$idpMetadata = array(); $idpMetadata = array();
$stateId = $response->getInResponseTo(); $stateId = $response->getInResponseTo();
if (!empty($stateId)) { if (!empty($stateId)) {
/* This is a response to a request we sent earlier. */ // this is a response to a request we sent earlier
$state = SimpleSAML_Auth_State::loadState($stateId, 'saml:sp:sso'); $state = SimpleSAML_Auth_State::loadState($stateId, 'saml:sp:sso');
/* Check that the authentication source is correct. */ // check that the authentication source is correct
assert('array_key_exists("saml:sp:AuthId", $state)'); assert('array_key_exists("saml:sp:AuthId", $state)');
if ($state['saml:sp:AuthId'] !== $sourceId) { if ($state['saml:sp:AuthId'] !== $sourceId) {
throw new SimpleSAML_Error_Exception('The authentication source id in the URL does not match the authentication source which sent the request.'); throw new SimpleSAML_Error_Exception(
} 'The authentication source id in the URL does not match the authentication source which sent the request.'
);
/* Check that the issuer is the one we are expecting. */ }
assert('array_key_exists("ExpectedIssuer", $state)');
if ($state['ExpectedIssuer'] !== $idp) { // check that the issuer is the one we are expecting
$idpMetadata = $source->getIdPMetadata($idp); assert('array_key_exists("ExpectedIssuer", $state)');
$idplist = $idpMetadata->getArrayize('IDPList', array()); if ($state['ExpectedIssuer'] !== $idp) {
if (!in_array($state['ExpectedIssuer'], $idplist)) { $idpMetadata = $source->getIdPMetadata($idp);
throw new SimpleSAML_Error_Exception('The issuer of the response does not match to the identity provider we sent the request to.'); $idplist = $idpMetadata->getArrayize('IDPList', array());
} if (!in_array($state['ExpectedIssuer'], $idplist)) {
} throw new SimpleSAML_Error_Exception(
'The issuer of the response does not match to the identity provider we sent the request to.'
);
}
}
} else { } else {
/* This is an unsolicited response. */ // this is an unsolicited response
$state = array( $state = array(
'saml:sp:isUnsolicited' => TRUE, 'saml:sp:isUnsolicited' => true,
'saml:sp:AuthId' => $sourceId, 'saml:sp:AuthId' => $sourceId,
'saml:sp:RelayState' => \SimpleSAML\Utils\HTTP::checkURLAllowed($spMetadata->getString( 'saml:sp:RelayState' => \SimpleSAML\Utils\HTTP::checkURLAllowed(
'RelayState', $spMetadata->getString(
$response->getRelayState() 'RelayState',
) $response->getRelayState()
), )
); ),
);
} }
SimpleSAML_Logger::debug('Received SAML2 Response from ' . var_export($idp, TRUE) . '.'); SimpleSAML_Logger::debug('Received SAML2 Response from '.var_export($idp, true).'.');
if (empty($idpMetadata)) { if (empty($idpMetadata)) {
$idpMetadata = $source->getIdPmetadata($idp); $idpMetadata = $source->getIdPmetadata($idp);
} }
try { try {
$assertions = sspmod_saml_Message::processResponse($spMetadata, $idpMetadata, $response); $assertions = sspmod_saml_Message::processResponse($spMetadata, $idpMetadata, $response);
} catch (sspmod_saml_Error $e) { } catch (sspmod_saml_Error $e) {
/* The status of the response wasn't "success". */ // the status of the response wasn't "success"
$e = $e->toException(); $e = $e->toException();
SimpleSAML_Auth_State::throwException($state, $e); SimpleSAML_Auth_State::throwException($state, $e);
} }
$authenticatingAuthority = NULL; $authenticatingAuthority = null;
$nameId = NULL; $nameId = null;
$sessionIndex = NULL; $sessionIndex = null;
$expire = NULL; $expire = null;
$attributes = array(); $attributes = array();
$foundAuthnStatement = FALSE; $foundAuthnStatement = false;
foreach ($assertions as $assertion) { foreach ($assertions as $assertion) {
/* Check for duplicate assertion (replay attack). */ // check for duplicate assertion (replay attack)
$store = SimpleSAML_Store::getInstance(); $store = SimpleSAML_Store::getInstance();
if ($store !== FALSE) { if ($store !== false) {
$aID = $assertion->getId(); $aID = $assertion->getId();
if ($store->get('saml.AssertionReceived', $aID) !== NULL) { if ($store->get('saml.AssertionReceived', $aID) !== null) {
$e = new SimpleSAML_Error_Exception('Received duplicate assertion.'); $e = new SimpleSAML_Error_Exception('Received duplicate assertion.');
SimpleSAML_Auth_State::throwException($state, $e); SimpleSAML_Auth_State::throwException($state, $e);
} }
$notOnOrAfter = $assertion->getNotOnOrAfter(); $notOnOrAfter = $assertion->getNotOnOrAfter();
if ($notOnOrAfter === NULL) { if ($notOnOrAfter === null) {
$notOnOrAfter = time() + 24*60*60; $notOnOrAfter = time() + 24 * 60 * 60;
} else { } else {
$notOnOrAfter += 60; /* We allow 60 seconds clock skew, so add it here also. */ $notOnOrAfter += 60; // we allow 60 seconds clock skew, so add it here also
} }
$store->set('saml.AssertionReceived', $aID, TRUE, $notOnOrAfter); $store->set('saml.AssertionReceived', $aID, true, $notOnOrAfter);
} }
if ($authenticatingAuthority === NULL) { if ($authenticatingAuthority === null) {
$authenticatingAuthority = $assertion->getAuthenticatingAuthority(); $authenticatingAuthority = $assertion->getAuthenticatingAuthority();
} }
if ($nameId === NULL) { if ($nameId === null) {
$nameId = $assertion->getNameId(); $nameId = $assertion->getNameId();
} }
if ($sessionIndex === NULL) { if ($sessionIndex === null) {
$sessionIndex = $assertion->getSessionIndex(); $sessionIndex = $assertion->getSessionIndex();
} }
if ($expire === NULL) { if ($expire === null) {
$expire = $assertion->getSessionNotOnOrAfter(); $expire = $assertion->getSessionNotOnOrAfter();
} }
$attributes = array_merge($attributes, $assertion->getAttributes()); $attributes = array_merge($attributes, $assertion->getAttributes());
if ($assertion->getAuthnInstant() !== NULL) { if ($assertion->getAuthnInstant() !== null) {
/* Assertion contains AuthnStatement, since AuthnInstant is a required attribute. */ // assertion contains AuthnStatement, since AuthnInstant is a required attribute
$foundAuthnStatement = TRUE; $foundAuthnStatement = true;
} }
} }
if (!$foundAuthnStatement) { if (!$foundAuthnStatement) {
$e = new SimpleSAML_Error_Exception('No AuthnStatement found in assertion(s).'); $e = new SimpleSAML_Error_Exception('No AuthnStatement found in assertion(s).');
SimpleSAML_Auth_State::throwException($state, $e); SimpleSAML_Auth_State::throwException($state, $e);
} }
if ($expire !== NULL) { if ($expire !== null) {
$logoutExpire = $expire; $logoutExpire = $expire;
} else { } else {
/* Just expire the logout associtaion 24 hours into the future. */ // just expire the logout association 24 hours into the future
$logoutExpire = time() + 24*60*60; $logoutExpire = time() + 24 * 60 * 60;
} }
/* Register this session in the logout store. */ // register this session in the logout store
sspmod_saml_SP_LogoutStore::addSession($sourceId, $nameId, $sessionIndex, $logoutExpire); sspmod_saml_SP_LogoutStore::addSession($sourceId, $nameId, $sessionIndex, $logoutExpire);
/* We need to save the NameID and SessionIndex for logout. */ // we need to save the NameID and SessionIndex for logout
$logoutState = array( $logoutState = array(
'saml:logout:Type' => 'saml2', 'saml:logout:Type' => 'saml2',
'saml:logout:IdP' => $idp, 'saml:logout:IdP' => $idp,
'saml:logout:NameID' => $nameId, 'saml:logout:NameID' => $nameId,
'saml:logout:SessionIndex' => $sessionIndex, 'saml:logout:SessionIndex' => $sessionIndex,
); );
$state['LogoutState'] = $logoutState; $state['LogoutState'] = $logoutState;
$state['saml:AuthenticatingAuthority'] = $authenticatingAuthority; $state['saml:AuthenticatingAuthority'] = $authenticatingAuthority;
$state['saml:AuthenticatingAuthority'][] = $idp; $state['saml:AuthenticatingAuthority'][] = $idp;
...@@ -201,19 +208,19 @@ $state['PersistentAuthData'][] = 'saml:sp:SessionIndex'; ...@@ -201,19 +208,19 @@ $state['PersistentAuthData'][] = 'saml:sp:SessionIndex';
$state['saml:sp:AuthnContext'] = $assertion->getAuthnContext(); $state['saml:sp:AuthnContext'] = $assertion->getAuthnContext();
$state['PersistentAuthData'][] = 'saml:sp:AuthnContext'; $state['PersistentAuthData'][] = 'saml:sp:AuthnContext';
if ($expire !== NULL) { if ($expire !== null) {
$state['Expire'] = $expire; $state['Expire'] = $expire;
} }
// note some information about the authentication, in case we receive the same response again // note some information about the authentication, in case we receive the same response again
$state['saml:sp:prevAuth'] = array( $state['saml:sp:prevAuth'] = array(
'id' => $response->getId(), 'id' => $response->getId(),
'issuer' => $idp, 'issuer' => $idp,
); );
if (isset($state['SimpleSAML_Auth_Default.ReturnURL'])) { if (isset($state['SimpleSAML_Auth_Default.ReturnURL'])) {
$state['saml:sp:prevAuth']['redirect'] = $state['SimpleSAML_Auth_Default.ReturnURL']; $state['saml:sp:prevAuth']['redirect'] = $state['SimpleSAML_Auth_Default.ReturnURL'];
} elseif (isset($state['saml:sp:RelayState'])) { } elseif (isset($state['saml:sp:RelayState'])) {
$state['saml:sp:prevAuth']['redirect'] = $state['saml:sp:RelayState']; $state['saml:sp:prevAuth']['redirect'] = $state['saml:sp:RelayState'];
} }
$state['PersistentAuthData'][] = 'saml:sp:prevAuth'; $state['PersistentAuthData'][] = 'saml:sp:prevAuth';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment