Skip to content
Snippets Groups Projects
Commit 140bb89f authored by Andreas Åkre Solberg's avatar Andreas Åkre Solberg
Browse files

Improved SLO error handling, and implemented IdP initiated SLO (to be used...

Improved SLO error handling, and implemented IdP initiated SLO (to be used with google apps for education)

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@357 44740490-163a-0410-bde0-09ae8108e29a
parent ab0b6530
No related branches found
No related tags found
No related merge requests found
...@@ -13,6 +13,10 @@ $lang = array( ...@@ -13,6 +13,10 @@ $lang = array(
'title_GENERATEAUTHNRESPONSE' => 'Could not create authentication response', 'title_GENERATEAUTHNRESPONSE' => 'Could not create authentication response',
'descr_GENERATEAUTHNRESPONSE' => 'When this identity provider tried to create an authentication response, an error occured.', 'descr_GENERATEAUTHNRESPONSE' => 'When this identity provider tried to create an authentication response, an error occured.',
'title_GENERATELOGOUTRESPONSE' => 'Could not create logout response',
'descr_GENERATELOGOUTRESPONSE' => 'When this SAML entity tried to create an logout response, an error occured.',
'title_LDAPERROR' => 'LDAP Error', 'title_LDAPERROR' => 'LDAP Error',
'descr_LDAPERROR' => 'LDAP is the user database, and when you try to login, we need to contact an LDAP database. When we tried it this time an error occured.', 'descr_LDAPERROR' => 'LDAP is the user database, and when you try to login, we need to contact an LDAP database. When we tried it this time an error occured.',
...@@ -20,6 +24,9 @@ $lang = array( ...@@ -20,6 +24,9 @@ $lang = array(
'title_LOGOUTREQUEST' => 'Error processing Logout Request', 'title_LOGOUTREQUEST' => 'Error processing Logout Request',
'descr_LOGOUTREQUEST' => 'An error occured when trying to process the Logout Request.', 'descr_LOGOUTREQUEST' => 'An error occured when trying to process the Logout Request.',
'title_GENERATELOGOUTREQUEST' => 'Could not create logout request',
'descr_GENERATELOGOUTREQUEST' => 'When this SAML entity tried to create an logout request, an error occured.',
'title_LOGOUTRESPONSE' => 'Error processing Logout Response', 'title_LOGOUTRESPONSE' => 'Error processing Logout Response',
'descr_LOGOUTRESPONSE' => 'An error occured when trying to process the Logout Response.', 'descr_LOGOUTRESPONSE' => 'An error occured when trying to process the Logout Response.',
......
...@@ -67,7 +67,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { ...@@ -67,7 +67,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect {
if ($mode == 'IdP') { if ($mode == 'IdP') {
$metadataset = 'saml20-sp-remote'; $metadataset = 'saml20-sp-remote';
} }
SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Looking up metadata issuer:' . $issuer . ' in set '. $metadataset);
$md = $this->metadata->getMetaData($issuer, $metadataset); $md = $this->metadata->getMetaData($issuer, $metadataset);
// check wether to validate or not // check wether to validate or not
......
...@@ -39,6 +39,7 @@ try { ...@@ -39,6 +39,7 @@ try {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
} }
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got IdP entity id: ' . $idpentityid);
/** /**
* If we get an incomming LogoutRequest then we initiate the logout process. * If we get an incomming LogoutRequest then we initiate the logout process.
...@@ -48,6 +49,8 @@ try { ...@@ -48,6 +49,8 @@ try {
*/ */
if (isset($_GET['SAMLRequest'])) { if (isset($_GET['SAMLRequest'])) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got SAML reuqest');
$binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
try { try {
...@@ -58,16 +61,9 @@ if (isset($_GET['SAMLRequest'])) { ...@@ -58,16 +61,9 @@ if (isset($_GET['SAMLRequest'])) {
} }
} catch(Exception $exception) { } catch(Exception $exception) {
$et = new SimpleSAML_XHTML_Template($config, 'error.php'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTREQUEST', $exception);
$et->data['header'] = 'Error in received logout request';
$et->data['message'] = 'An error occured when trying to read logout request.';
$et->data['e'] = $exception;
$et->show();
exit(0);
} }
// Extract some parameters from the logout request // Extract some parameters from the logout request
...@@ -125,6 +121,8 @@ if (isset($_GET['SAMLRequest'])) { ...@@ -125,6 +121,8 @@ if (isset($_GET['SAMLRequest'])) {
$requestcache['RelayState'] = $relaystate; $requestcache['RelayState'] = $relaystate;
$session->setLogoutRequest($requestcache); $session->setLogoutRequest($requestcache);
SimpleSAML_Logger::debug('SAML2.0 - IDP.SingleLogoutService: Setting cached request with issuer ' . $logoutrequest->getIssuer());
$session->set_sp_logout_completed($logoutrequest->getIssuer() ); $session->set_sp_logout_completed($logoutrequest->getIssuer() );
...@@ -133,26 +131,23 @@ if (isset($_GET['SAMLRequest'])) { ...@@ -133,26 +131,23 @@ if (isset($_GET['SAMLRequest'])) {
*/ */
} elseif (isset($_GET['SAMLResponse'])) { } elseif (isset($_GET['SAMLResponse'])) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got SAML response');
$binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
try { try {
$loginresponse = $binding->decodeLogoutResponse($_GET); $loginresponse = $binding->decodeLogoutResponse($_GET);
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: SAML response parsed. Issuer is: ' . $loginresponse->getIssuer());
if ($binding->validateQuery($loginresponse->getIssuer(),'SP','SAMLResponse')) { if ($binding->validateQuery($loginresponse->getIssuer(),'IdP','SAMLResponse')) {
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Valid signature found'); SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Valid signature found');
} }
} catch(Exception $exception) { } catch(Exception $exception) {
$et = new SimpleSAML_XHTML_Template($config, 'error.php'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTRESPONSE', $exception);
$et->data['header'] = 'Error in received logout response';
$et->data['message'] = 'An error occured when trying to read logout response.';
$et->data['e'] = $exception;
$et->show();
exit(0);
} }
...@@ -163,6 +158,7 @@ if (isset($_GET['SAMLRequest'])) { ...@@ -163,6 +158,7 @@ if (isset($_GET['SAMLRequest'])) {
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: got LogoutResponse from ' . $loginresponse->getIssuer()); SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: got LogoutResponse from ' . $loginresponse->getIssuer());
} else { } else {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: No request or response...');
/** /**
* This error message was removed 2008-02-27, because it interrupts with bridged SLO. * This error message was removed 2008-02-27, because it interrupts with bridged SLO.
* *
...@@ -170,15 +166,38 @@ if (isset($_GET['SAMLRequest'])) { ...@@ -170,15 +166,38 @@ if (isset($_GET['SAMLRequest'])) {
*/ */
} }
$lookformore = true;
$spentityid = null;
do {
/* Dump the current sessions (for debugging). */
$session->dump_sp_sessions();
/* Dump the current sessions (for debugging). */ /*
$session->dump_sp_sessions(); * We proceed to send logout requests to all remaining SPs.
*/
$spentityid = $session->get_next_sp_logout();
// If there are no more SPs left, then we will not look for more SPs.
if (empty($spentityid)) $lookformore = false;
try {
$spmetadata = $metadata->getMetadata($spentityid, 'saml20-sp-remote');
} catch (Exception $e) {
continue;
}
// If the SP we found have an SingleLogout endpoint then we will use it, and
// hence we do not need to look for more yet.
if (array_key_exists('SingleLogoutService', $spmetadata) &&
!empty($spmetadata['SingleLogoutService']) ) $lookformore = false;
if ($lookformore)
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Will not logout from ' . $spentityid . ' looking for more SPs');
} while ($lookformore);
/*
* We proceed to send logout requests to all remaining SPs.
*/
$spentityid = $session->get_next_sp_logout();
if ($spentityid) { if ($spentityid) {
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Logout next SP ' . $spentityid); SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Logout next SP ' . $spentityid);
...@@ -203,14 +222,8 @@ if ($spentityid) { ...@@ -203,14 +222,8 @@ if ($spentityid) {
} catch(Exception $exception) { } catch(Exception $exception) {
$et = new SimpleSAML_XHTML_Template($config, 'error.php'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATELOGOUTREQUEST', $exception);
$et->data['header'] = 'Error sending logout request to service';
$et->data['message'] = 'Some error occured when trying to issue the logout response, and send it to the SP.';
$et->data['e'] = $exception;
$et->show();
exit(0);
} }
...@@ -252,6 +265,7 @@ try { ...@@ -252,6 +265,7 @@ try {
throw new Exception('Could not get reference to the logout request.'); throw new Exception('Could not get reference to the logout request.');
} }
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Found request cache with these keys: ' . join(',', array_keys($requestcache)));
/** /**
* Clean up session object to save storage. * Clean up session object to save storage.
...@@ -265,32 +279,44 @@ try { ...@@ -265,32 +279,44 @@ try {
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size after cleaning: ' . $session->getSize()); SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size after cleaning: ' . $session->getSize());
/** /*
* Create a Logot Response. * Check if the Single Logout procedure is initated by an SP (alternatively IdP initiated SLO
*/ */
$rg = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata); if (array_key_exists('Issuer', $requestcache)) {
// generate($issuer, $receiver, $inresponseto, $mode ) /**
$logoutResponseXML = $rg->generate($idpentityid, $requestcache['Issuer'], $requestcache['RequestID'], 'IdP'); * Create a Logot Response.
*/
// Create a HTTP-REDIRECT Binding. $rg = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata);
$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
// generate($issuer, $receiver, $inresponseto, $mode )
// Find the relaystate if cached. $logoutResponseXML = $rg->generate($idpentityid, $requestcache['Issuer'], $requestcache['RequestID'], 'IdP');
$relayState = isset($requestcache['RelayState']) ? $requestcache['RelayState'] : null;
// Create a HTTP-REDIRECT Binding.
$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
// Find the relaystate if cached.
$relayState = isset($requestcache['RelayState']) ? $requestcache['RelayState'] : null;
// Parameters: $request, $remoteentityid, $relayState = null, $endpoint = 'SingleLogoutService', $direction = 'SAMLRequest', $mode = 'SP'
$httpredirect->sendMessage($logoutResponseXML, $idpentityid, $requestcache['Issuer'], $relayState, 'SingleLogoutService', 'SAMLResponse', 'IdP');
exit;
} elseif (array_key_exists('RelayState', $requestcache)) {
// Parameters: $request, $remoteentityid, $relayState = null, $endpoint = 'SingleLogoutService', $direction = 'SAMLRequest', $mode = 'SP' SimpleSAML_Utilities::redirect($requestcache['RelayState']);
$httpredirect->sendMessage($logoutResponseXML, $idpentityid, $requestcache['Issuer'], $relayState, 'SingleLogoutService', 'SAMLResponse', 'IdP'); exit;
} else {
echo 'You are logged out'; exit;
}
} catch(Exception $exception) { } catch(Exception $exception) {
$et = new SimpleSAML_XHTML_Template($config, 'error.php'); SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATELOGOUTRESPONSE', $exception);
$et->data['header'] = 'Error sending response to service';
$et->data['message'] = 'Some error occured when trying to issue the logout response, and send it to the SP.';
$et->data['e'] = $exception;
$et->show();
} }
?>
\ No newline at end of file
<?php
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . '../../../www/_include.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Utilities.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Session.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Logger.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandler.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XML/SAML20/LogoutRequest.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XML/SAML20/LogoutResponse.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Bindings/SAML20/HTTPRedirect.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XHTML/Template.php');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
SimpleSAML_Logger::info('SAML2.0 - IdP.initSLO: Accessing SAML 2.0 IdP endpoint init Single Logout');
if (!$config->getValue('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError(isset($session) ? $session->getTrackID() : null, 'NOACCESS');
try {
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
} catch (Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
}
/**
* If we get an incomming LogoutRequest then we initiate the logout process.
* in this case an SAML 2.0 SP is sending an request, which also is referred to as
* SP initiated Single Logout.
*
*/
if (isset($_GET['RelayState'])) {
$relaystate = $_GET['RelayState'];
/**
* No session exists. Just go to the RelayState.
*/
if($session === NULL) {
SimpleSAML_Logger::info('SAML2.0 - IdP.initSLO: Did not find a session here, so we redirect to the RelayState');
SimpleSAML_Utilities::redirect($relaystate);
exit;
}
// Set local IdP session to invalid.
$session->setAuthenticated(false, $session->getAuthority() );
/*
* Create an assoc array of the request to store in the session cache.
*/
$requestcache = array(
'RelayState' => $relaystate
);
$session->setLogoutRequest($requestcache);
SimpleSAML_Logger::debug('SAML2.0 - IDP.initSSO: Setting cached request with relay state ' . $relaystate);
//$session->set_sp_logout_completed($logoutrequest->getIssuer() );
}
$lookformore = true;
$spentityid = null;
do {
/* Dump the current sessions (for debugging). */
$session->dump_sp_sessions();
/*
* We proceed to send logout requests to all remaining SPs.
*/
$spentityid = $session->get_next_sp_logout();
// If there are no more SPs left, then we will not look for more SPs.
if (empty($spentityid)) $lookformore = false;
try {
$spmetadata = $metadata->getMetadata($spentityid, 'saml20-sp-remote');
} catch (Exception $e) {
continue;
}
// If the SP we found have an SingleLogout endpoint then we will use it, and
// hence we do not need to look for more yet.
if (array_key_exists('SingleLogoutService', $spmetadata) &&
!empty($spmetadata['SingleLogoutService']) ) $lookformore = false;
if ($lookformore)
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Will not logout from ' . $spentityid . ' looking for more SPs');
} while ($lookformore);
/*
* We proceed to send logout requests to the first remaining SP.
*/
$spentityid = $session->get_next_sp_logout();
if ($spentityid) {
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Logout next SP ' . $spentityid);
try {
$lr = new SimpleSAML_XML_SAML20_LogoutRequest($config, $metadata);
// ($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) {
$req = $lr->generate($idpentityid, $spentityid, $session->getNameID(), $session->getSessionIndex(), 'IdP');
$httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata);
$relayState = SimpleSAML_Utilities::selfURL();
if (isset($_GET['RelayState'])) {
$relayState = $_GET['RelayState'];
}
//$request, $remoteentityid, $relayState = null, $endpoint = 'SingleLogoutService', $direction = 'SAMLRequest', $mode = 'SP'
$httpredirect->sendMessage($req, $idpentityid, $spentityid, $relayState, 'SingleLogoutService', 'SAMLRequest', 'IdP');
exit();
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATELOGOUTREQUEST', $exception);
}
}
if ($config->getValue('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: LogoutService: All SPs done ');
if (isset($_GET['RelayState'])) {
$relayState = $_GET['RelayState'];
SimpleSAML_Utilities::redirect($relayState);
} else {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NORELAYSTATE');
}
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