diff --git a/lib/SimpleSAML/Error/NoAvailableIDP.php b/lib/SimpleSAML/Error/NoAvailableIDP.php new file mode 100644 index 0000000000000000000000000000000000000000..d3c99dc237a44161718e2b31a6e2fe8d23b289b5 --- /dev/null +++ b/lib/SimpleSAML/Error/NoAvailableIDP.php @@ -0,0 +1,15 @@ +<?php +/** + * Simple exception to model the NoAvailableIDP SAML error. + * + * @author Jaime PĂ©rez Crespo, UNINETT AS <jaime.perez@uninett.no> + * @package SimpleSAMLphp + */ + +namespace SimpleSAML\Error; + + +class NoAvailableIDP extends \SimpleSAML_Error_Exception +{ + +} \ No newline at end of file diff --git a/lib/SimpleSAML/Error/NoSupportedIDP.php b/lib/SimpleSAML/Error/NoSupportedIDP.php new file mode 100644 index 0000000000000000000000000000000000000000..0ef97ed2acfbafe4d15acc7c765e5f0b44f12947 --- /dev/null +++ b/lib/SimpleSAML/Error/NoSupportedIDP.php @@ -0,0 +1,15 @@ +<?php +/** + * Simple exception to model the NoSupportedIDP SAML error. + * + * @author Jaime PĂ©rez Crespo, UNINETT AS <jaime.perez@uninett.no> + * @package SimpleSAMLphp + */ + +namespace SimpleSAML\Error; + + +class NoSupportedIDP extends \SimpleSAML_Error_Exception +{ + +} \ No newline at end of file diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php index 4a091fdb56d0b39c3d28b830f8321ca7fe4c030f..99827f59c17eb476b19607afdf4c3121b94a5154 100644 --- a/modules/saml/lib/Auth/Source/SP.php +++ b/modules/saml/lib/Auth/Source/SP.php @@ -385,8 +385,23 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source { $idp = (string)$state['saml:idp']; } - if ($idp === NULL && isset($state['saml:IDPList']) && sizeof($state['saml:IDPList']) == 1) { - $idp = $state['saml:IDPList'][0]; + if (isset($state['saml:IDPList']) && sizeof($state['saml:IDPList']) > 0) { + // we have a SAML IDPList (we are a proxy): filter the list of IdPs available + $mdh = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + $known_idps = $mdh->getList(); + $intersection = array_intersect($state['saml:IDPList'], array_keys($known_idps)); + + if (empty($intersection)) { // all requested IdPs are unknown + throw new SimpleSAML\Error\NoSupportedIDP('None of the IdPs requested are supported by this proxy.'); + } + + if (!is_null($idp) && !in_array($idp, $intersection)) { // the IdP is enforced but not in the IDPList + throw new SimpleSAML\Error\NoAvailableIDP('None of the IdPs requested are available to this proxy.'); + } + + if (is_null($idp) && sizeof($intersection) === 1) { // only one IdP requested or valid + $idp = current($state['saml:IDPList']); + } } if ($idp === NULL) { @@ -422,9 +437,30 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source { { /* * The user has an existing, valid session. However, the SP provided a list of IdPs it accepts for - * authentication, and the IdP the existing session is related to is not in that list. We need to - * inform the user, and ask whether we should logout before starting the authentication process again - * with a different IdP, or cancel the current SSO attempt. + * authentication, and the IdP the existing session is related to is not in that list. + * + * First, check if we recognize any of the IdPs requested. + */ + + $mdh = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + $known_idps = $mdh->getList(); + $intersection = array_intersect($state['saml:IDPList'], array_keys($known_idps)); + + if (empty($intersection)) { // all requested IdPs are unknown + throw new SimpleSAML\Error\NoSupportedIDP('None of the IdPs requested are supported by this proxy.'); + } + + /* + * We have at least one IdP in the IDPList that we recognize, and it's not the one currently in use. Let's + * see if this proxy enforces the use of one single IdP. + */ + if (!is_null($this->idp) && !in_array($this->idp, $intersection)) { // an IdP is enforced but not requested + throw new SimpleSAML\Error\NoAvailableIDP('None of the IdPs requested are available to this proxy.'); + } + + /* + * We need to inform the user, and ask whether we should logout before starting the authentication process + * again with a different IdP, or cancel the current SSO attempt. */ SimpleSAML\Logger::warning( "Reauthentication after logout is needed. The IdP '${state['saml:sp:IdP']}' is not in the IDPList ". diff --git a/modules/saml/lib/Error.php b/modules/saml/lib/Error.php index 78799a2cd7b41bcb6af2b870f1fadeb844e0e25f..8cf0fb15ff2d68dad44ab7b9071c82eaf3163835 100644 --- a/modules/saml/lib/Error.php +++ b/modules/saml/lib/Error.php @@ -117,8 +117,21 @@ class sspmod_saml_Error extends SimpleSAML_Error_Exception { \SAML2\Constants::STATUS_PROXY_COUNT_EXCEEDED, $exception->getMessage(), $exception - ); - + ); + } elseif ($exception instanceof SimpleSAML\Error\NoAvailableIDP) { + $e = new self( + \SAML2\Constants::STATUS_RESPONDER, + \SAML2\Constants::STATUS_NO_AVAILABLE_IDP, + $exception->getMessage(), + $exception + ); + } elseif ($exception instanceof SimpleSAML\Error\NoSupportedIDP) { + $e = new self( + \SAML2\Constants::STATUS_RESPONDER, + \SAML2\Constants::STATUS_NO_SUPPORTED_IDP, + $exception->getMessage(), + $exception + ); } else { $e = new self( \SAML2\Constants::STATUS_RESPONDER, diff --git a/modules/saml/www/proxy/invalid_session.php b/modules/saml/www/proxy/invalid_session.php index ac38a65d7aa83e783b9d0e571e400daefcd486d0..5369ace8a3bc68a0f92c6b1396fe3802397f7db2 100644 --- a/modules/saml/www/proxy/invalid_session.php +++ b/modules/saml/www/proxy/invalid_session.php @@ -28,8 +28,8 @@ try { if (isset($_POST['cancel'])) { // the user does not want to logout, cancel login - $e = new SimpleSAML_Error_Exception('User refused to reauthenticate with any of the IdPs requested.'); - sspmod_saml_IdP_SAML2::handleAuthError($e, $state); + $e = new \SimpleSAML\Error\NoAvailableIDP('User refused to reauthenticate with any of the IdPs requested.'); + SimpleSAML_Auth_State::throwException($state, $e); } if (isset($_POST['continue'])) {