From 6b91de0e6ba015ce0ac02709b3832f963469ba5e Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Mon, 3 Aug 2009 12:47:48 +0000 Subject: [PATCH] saml2: Use SAML library for handling logout messages from IdP. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1609 44740490-163a-0410-bde0-09ae8108e29a --- modules/saml2/lib/Message.php | 52 +++++++++++++++++++++++++++ modules/saml2/www/sp/logout.php | 63 ++++++++++++++++----------------- 2 files changed, 82 insertions(+), 33 deletions(-) diff --git a/modules/saml2/lib/Message.php b/modules/saml2/lib/Message.php index 1f8c9a39a..b80a55a97 100644 --- a/modules/saml2/lib/Message.php +++ b/modules/saml2/lib/Message.php @@ -181,6 +181,34 @@ class sspmod_saml2_Message { } + /** + * Check signature on a SAML2 message if enabled. + * + * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender. + * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient. + * @param SAML2_Message $message The message we should check the signature on. + */ + public static function validateMessage( + SimpleSAML_Configuration $srcMetadata, + SimpleSAML_Configuration $dstMetadata, + SAML2_Message $message + ) { + + $enabled = $srcMetadata->getBoolean('redirect.validate', NULL); + if ($enabled === NULL) { + $enabled = $dstMetadata->getBoolean('redirect.validate', FALSE); + } + + if (!$enabled) { + return; + } + + if (!self::checkSign($srcMetadata, $message)) { + throw new SimpleSAML_Error_Exception('Validation of received messages enabled, but no signature found on message.'); + } + } + + /** * Decrypt an assertion. * @@ -293,6 +321,30 @@ class sspmod_saml2_Message { } + /** + * Build a logout response based on information in the metadata. + * + * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender. + * @param SimpleSAML_Configuration $dstpMetadata The metadata of the recipient. + */ + public static function buildLogoutResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata) { + + $lr = new SAML2_LogoutResponse(); + + $lr->setIssuer($srcMetadata->getString('entityid')); + + $dst = $dstMetadata->getString('SingleLogoutServiceResponse', NULL); + if ($dst === NULL) { + $dst = $dstMetadata->getString('SingleLogoutService'); + } + $lr->setDestination($dst); + + self::addSign($srcMetadata, $dstMetadata, $lr); + + return $lr; + } + + /** * Process a response message. * diff --git a/modules/saml2/www/sp/logout.php b/modules/saml2/www/sp/logout.php index 75d0fa413..43448c362 100644 --- a/modules/saml2/www/sp/logout.php +++ b/modules/saml2/www/sp/logout.php @@ -17,57 +17,54 @@ if ($source === NULL) { throw new Exception('Could not find authentication source with id ' . $sourceId); } +$binding = SAML2_Binding::getCurrentBinding(); +$message = $binding->receive(); -$config = SimpleSAML_Configuration::getInstance(); -$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); +$idpEntityId = $message->getIssuer(); +if ($idpEntityId === NULL) { + /* Without an issuer we have no way to respond to the message. */ + throw new SimpleSAML_Error_BadRequest('Received message on logout endpoint without issuer.'); +} -if (array_key_exists('SAMLResponse', $_GET)) { +$spEntityId = $source->getEntityId(); - $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - $response = $binding->decodeLogoutResponse($_GET); +$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); +$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-remote'); +$spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-hosted'); - if ($binding->validateQuery($response->getIssuer(), 'SP', 'SAMLResponse')) { - SimpleSAML_Logger::debug('module/saml2/sp/logout: Valid signature found on response'); - } +sspmod_saml2_Message::validateMessage($idpMetadata, $spMetadata, $message); - if (!array_key_exists('RelayState', $_REQUEST)) { +if ($message instanceof SAML2_LogoutResponse) { + + $relayState = $message->getRelayState(); + if ($relayState === NULL) { + /* Somehow, our RelayState has been lost. */ throw new SimpleSAML_Error_BadRequest('Missing RelayState in logout response.'); } - $stateId = $_REQUEST['RelayState']; - $state = SimpleSAML_Auth_State::loadState($_REQUEST['RelayState'], sspmod_saml2_Auth_Source_SP::STAGE_LOGOUTSENT); - - - SimpleSAML_Auth_Source::completeLogout($state); - -} elseif (array_key_exists('SAMLRequest', $_GET)) { - - $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - - $request = $binding->decodeLogoutRequest($_GET); - - $requestId = $request->getRequestID(); - $idpEntityId = $request->getIssuer(); - $relayState = $request->getRelayState(); - - if ($binding->validateQuery($idpEntityId, 'SP')) { - SimpleSAML_Logger::debug('module/saml2/sp/logout: Valid signature found on request'); + if (!$message->isSuccess()) { + SimpleSAML_Logger::warning('Unsuccessful logout. Status was: ' . sspmod_saml2_Message::getResponseError($message)); } + $state = SimpleSAML_Auth_State::loadState($relayState, sspmod_saml2_Auth_Source_SP::STAGE_LOGOUTSENT); + SimpleSAML_Auth_Source::completeLogout($state); - $spEntityId = $source->getEntityId(); +} elseif ($message instanceof SAML2_LogoutRequest) { - SimpleSAML_Logger::debug('module/saml2/sp/logout: Request from ' . $idpEntityId . ' with request id ' . $requestId); + SimpleSAML_Logger::debug('module/saml2/sp/logout: Request from ' . $idpEntityId); SimpleSAML_Logger::stats('saml20-idp-SLO idpinit ' . $spEntityId . ' ' . $idpEntityId); /* Notify source of logout, so that it may call logout callbacks. */ $source->onLogout($idpEntityId); /* Create an send response. */ - $lr = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata); - $responseXML = $lr->generate($spEntityId, $idpEntityId, $requestId, 'SP'); - $binding->sendMessage($responseXML, $spEntityId, $idpEntityId, $relayState, 'SingleLogoutServiceResponse', 'SAMLResponse'); + $lr = sspmod_saml2_Message::buildLogoutResponse($spMetadata, $idpMetadata); + $lr->setRelayState($message->getRelayState()); + $lr->setInResponseTo($message->getId()); + $binding = new SAML2_HTTPRedirect(); + $binding->setDestination(sspmod_SAML2_Message::getDebugDestination()); + $binding->send($lr); } else { - throw new SimpleSAML_Error_BadRequest('Missing request or response to logout endpoint'); + throw new SimpleSAML_Error_BadRequest('Unknown message received on logout endpoint: ' . get_class($message)); } -- GitLab