From c31ae004bb4dd37775f72623153764cfca94cb33 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Mon, 13 Jul 2009 06:19:12 +0000 Subject: [PATCH] saml2/SSOService: Handle exceptions. This patch uses the recently added infrastructure for passing exceptions from authentication modules and filters. Exceptions will be passed to the service provider. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1577 44740490-163a-0410-bde0-09ae8108e29a --- www/saml2/idp/SSOService.php | 121 +++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 35 deletions(-) diff --git a/www/saml2/idp/SSOService.php b/www/saml2/idp/SSOService.php index ada15ff81..a96b466d5 100644 --- a/www/saml2/idp/SSOService.php +++ b/www/saml2/idp/SSOService.php @@ -34,6 +34,57 @@ if (!$config->getValue('enable.saml20-idp', false)) SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS'); +/** + * Helper function for handling exception/errors. + * + * This function will send an error response to the SP which contacted this IdP. + * + * @param Exception $exception The exception. + */ +function handleError(Exception $exception) { + + global $requestcache, $config, $metadata, $idpentityid; + assert('is_array($requestcache)'); + + assert('array_key_exists("Issuer", $requestcache)'); + $issuer = $requestcache['Issuer']; + + if (array_key_exists('RequestID', $requestcache)) { + $requestID = $requestcache['RequestID']; + } else { + $requestID = NULL; + } + + if (array_key_exists('RelayState', $requestcache)) { + $relayState = $requestcache['RelayState']; + } else { + $relayState = NULL; + } + + $error = sspmod_saml2_Error::fromException($exception); + + SimpleSAML_Logger::warning('Returning error to sp: ' . var_export($issuer, TRUE)); + $error->logWarning(); + + try { + + /* Generate an SAML 2.0 AuthNResponse message + * With statusCode: urn:oasis:names:tc:SAML:2.0:status:NoPassive + */ + $ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata); + $authnResponseXML = $ar->generate($idpentityid, $issuer, $requestID, NULL, NULL, $error, $config->getValue('session.duration', 3600) ); + + /* Sending the AuthNResponse using HTTP-Post SAML 2.0 binding. */ + $httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); + $httppost->sendResponse($authnResponseXML, $idpentityid, $issuer, $relayState); + exit(); + } catch(Exception $e) { + SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $e); + } + +} + + /* * Initiate some variables */ @@ -118,6 +169,36 @@ if (isset($_GET['SAMLRequest'])) { SimpleSAML_Utilities::fatalError($session->getTrackID(), 'PROCESSAUTHNREQUEST', $exception); } +} elseif(isset($_REQUEST[SimpleSAML_Auth_State::EXCEPTION_PARAM])) { + /* + * We have received an exception. It can either be from the authentication module, + * or from the authentication processing filters. + */ + + $state = SimpleSAML_Auth_State::loadExceptionState(); + if (array_key_exists('core:saml20-idp:requestcache', $state)) { + /* This was from a processing chain. */ + $requestcache = $state['core:saml20-idp:requestcache']; + + } elseif (array_key_exists('RequestID', $_REQUEST)) { + /* This was from an authentication module. */ + $authId = $_REQUEST['RequestId']; + $requestcache = $session->getAuthnRequest('saml2', $authId); + if (!$requestcache) { + throw new Exception('Could not retrieve saved request while handling exceptions. RequestId=' . var_export($authId, TRUE)); + } + + } else { + /* We have no idea where this comes from. We have received a bad request. */ + throw new Exception('Bad request to exception handing code.'); + } + + assert('array_key_exists(SimpleSAML_Auth_State::EXCEPTION_DATA, $state)'); + $exception = $state[SimpleSAML_Auth_State::EXCEPTION_DATA]; + + handleError($exception); + + /* * If we did not get an incoming Authenticaiton Request, we need a RequestID parameter. * @@ -228,7 +309,7 @@ if($needAuth && !$isPassive) { SimpleSAML_Auth_State::RESTART => $sessionLostURL, ); - SimpleSAML_Auth_Default::initLogin($idpmetadata['auth'], $redirectTo, NULL, $hints); + SimpleSAML_Auth_Default::initLogin($idpmetadata['auth'], $redirectTo, $redirectTo, $hints); } else { $authurl = '/' . $config->getBaseURL() . $idpmetadata['auth']; @@ -244,20 +325,7 @@ if($needAuth && !$isPassive) { * the user didn't have a valid session. */ - try { - - /* Generate an SAML 2.0 AuthNResponse message - * With statusCode: urn:oasis:names:tc:SAML:2.0:status:NoPassive - */ - $ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata); - $authnResponseXML = $ar->generate($idpentityid, $requestcache['Issuer'], $requestcache['RequestID'], NULL, NULL, 'NoPassive', $config->getValue('session.duration', 3600) ); - - /* Sending the AuthNResponse using HTTP-Post SAML 2.0 binding. */ - $httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); - $httppost->sendResponse($authnResponseXML, $idpentityid, $requestcache['Issuer'], $requestcache['RelayState']); - } catch(Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception); - } + handleError(new SimpleSAML_Error_NoPassive('Passive authentication requested, but no session available.')); /** * We got an request, and we have a valid session. Then we send an AuthnResponse back to the @@ -291,6 +359,7 @@ if($needAuth && !$isPassive) { 'Destination' => $spmetadata, 'Source' => $idpmetadata, 'isPassive' => $isPassive, + SimpleSAML_Auth_State::EXCEPTION_HANDLER_URL => SimpleSAML_Utilities::selfURLNoQuery(), ); /* @@ -305,26 +374,8 @@ if($needAuth && !$isPassive) { try { $pc->processState($authProcState); - } catch (SimpleSAML_Error_NoPassive $e) { - /* Any user interaction is considered harmfull if isPassive is set to TRUE - even - * giving consent. - * If the user is authenticated but a processing filter needs user interaction - * we expect a SimpleSAML_Error_NoPassive exception to be thrown. We then send - * back the proper respons. - */ - try { - /* Generate an SAML 2.0 AuthNResponse message - * With statusCode: urn:oasis:names:tc:SAML:2.0:status:NoPassive - */ - $ar = new SimpleSAML_XML_SAML20_AuthnResponse($config, $metadata); - $authnResponseXML = $ar->generate($idpentityid, $requestcache['Issuer'], $requestcache['RequestID'], NULL, NULL, 'NoPassive', $config->getValue('session.duration', 3600)); - - /* Sending the AuthNResponse using HTTP-Post SAML 2.0 binding. */ - $httppost = new SimpleSAML_Bindings_SAML20_HTTPPost($config, $metadata); - $httppost->sendResponse($authnResponseXML, $idpentityid, $requestcache['Issuer'], $requestcache['RelayState']); - } catch(Exception $exception) { - SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATEAUTHNRESPONSE', $exception); - } + } catch (Exception $e) { + handleException($e); } $requestcache['AuthProcState'] = $authProcState; -- GitLab