From db50b31f6f38697db704e133642ecb93903dc5aa Mon Sep 17 00:00:00 2001 From: Lasse Birnbaum Jensen <lasse@sdu.dk> Date: Sun, 20 Jan 2008 20:29:29 +0000 Subject: [PATCH] Rewrite of SAML2 HTTP Redirect request signing, now using xmlseclibs. Implemented verification of authenticationrequest, logoutrequest and logoutresponse. Moved config of signing and verification to individual metadata entries. To sign/verify on hosted SP there must be a certificate and a privatekey. The normal certificate and privatekey of the IdP are reused when signing is enabled. To verify remote SP and/or IdP the remote certificate must be present. This commit is tested to some extend - please post bugs on google code project page. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@178 44740490-163a-0410-bde0-09ae8108e29a --- config/config-template.php | 9 -- .../Bindings/SAML20/HTTPRedirect.php | 106 +++++++++++------ lib/SimpleSAML/XML/SAML20/LogoutResponse.php | 1 - metadata-templates/saml20-idp-hosted.php | 11 +- metadata-templates/saml20-idp-remote.php | 13 ++- metadata-templates/saml20-sp-hosted.php | 19 ++- metadata-templates/saml20-sp-remote.php | 9 ++ www/admin/metadata.php | 8 +- www/logout.html | 2 +- www/saml2/idp/SSOService.php | 10 +- www/saml2/idp/SingleLogoutService.php | 110 ++++++++++++------ www/saml2/sp/SingleLogoutService.php | 93 ++++++++++----- 12 files changed, 262 insertions(+), 129 deletions(-) diff --git a/config/config-template.php b/config/config-template.php index ebdd97258..dfb80660c 100644 --- a/config/config-template.php +++ b/config/config-template.php @@ -283,15 +283,6 @@ $config = array ( */ 'auth.auto.delay_login' => 0, - - /* - * This option enables signing of all messages sent with the - * HTTP-Redirect binding. The default value is false. To enable, set - * this option to true, and add a 'privatekey' element to the entity - * (IdP or SP) which is sending the message. - */ - 'binding.httpredirect.sign' => true, - ); diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php index d50144c4f..ded89bc4e 100644 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php +++ b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php @@ -15,7 +15,7 @@ require_once('SimpleSAML/Configuration.php'); require_once('SimpleSAML/Utilities.php'); require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php'); require_once('SimpleSAML/XHTML/Template.php'); - +require_once('xmlseclibs.php'); /** * Configuration of SimpleSAMLphp @@ -34,43 +34,18 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { public function signQuery($query, $md) { /* Check if signing of HTTP-Redirect messages is enabled. */ - if($this->configuration->getValue('binding.httpredirect.sign', false) !== true) { - return $query; - } - - /* Don't attempt to sign the query if no private key is set in the metadata. */ - if(!array_key_exists('privatekey', $md) || $md['privatekey'] === NULL) { + + if (!array_key_exists('request.signing', $md) || !$md['request.signing']){ return $query; } - /* Load the private key. */ - $privatekey = $this->configuration->getBaseDir() . 'cert/' . $md['privatekey']; + $privatekey = $this->configuration->getBaseDir() . '/cert/' . $md['privatekey']; if (!file_exists($privatekey)) { throw new Exception('Could not find private key file [' . $privatekey . '] which is needed to sign the request.'); } - $keydata = file_get_contents($privatekey); - if($keydata === FALSE) { - throw new Exception('Unable to load private key file: ' . $privatekey); - } - - $keyid = openssl_pkey_get_private($keydata); - if($keyid === FALSE) { - throw new Exception('OpenSSL was unable to parse the private key from the following file: ' . $privatekey); - } - - /* Make sure that the loaded key is a RSA key. */ - $keydetails = openssl_pkey_get_details($keyid); - if($keydetails === FALSE) { - throw new Exception('Unable to get key details of already loaded key.'); - } - if($keydetails['type'] !== OPENSSL_KEYTYPE_RSA) { - throw new Exception('Private key used to sign the query string isn\'t a RSA key. Key was loaded from the following file: ' . $privatekey); - } - - /* Sign the query string. According to the specification, the string which should be * signed is the concatenation of the following query parameters (in order): * - SAMLRequest/SAMLResponse @@ -83,18 +58,73 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { /* Append the signature algorithm. We always use RSA-SHA1. */ $algURI = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; $query = $query . "&" . "SigAlg=" . urlencode($algURI); + + $xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); + $xmlseckey->loadKey($privatekey,TRUE); + $signature = $xmlseckey->signData($query); + + $query = $query . "&" . "Signature=" . urlencode(base64_encode($signature)); + + return $query; + } + + public function validateQuery($issuer,$mode = 'SP',$request = 'SAMLRequest') { + + $metadataset = 'saml20-idp-remote'; + if ($mode == 'IdP') { + $metadataset = 'saml20-sp-remote'; + } - /* Sign the query string. The default hash algorithm of openssl_sign is (fortunately) SHA1. */ - if(!openssl_sign($query, $signature, $keyid)) { - throw new Exception('OpenSSL was unable to sign the query string.'); + $md = $this->metadata->getMetaData($issuer, $metadataset); + + // check wether to validate or not + if (!array_key_exists('request.signing', $md) || !$md['request.signing']){ + return $query; } - /* Free the key we used. */ - openssl_pkey_free($keyid); + if (!isset($_GET['Signature'])) { + throw new Exception('No Signature on the request, required by configuration'); + } - /* Return the signed query string. */ - $query = $query . "&" . "Signature=" . urlencode(base64_encode($signature)); - return $query; + // building query string + $query = $request.'='.urlencode($_GET[$request]); + + if($_GET['RelayState']) { + $relaystate = $_GET['RelayState']; + /* Remove any magic quotes that php may have added. */ + if(get_magic_quotes_gpc()) { + $relaystate = stripslashes($relaystate); + } + $query .= "&RelayState=" . urlencode($relaystate); + } + + $algURI = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; + + if (isset($_GET['SigAlg']) && $_GET['SigAlg'] != $algURI) { + throw new Exception('Signature must be rsa-sha1 based'); + } + + $query = $query . "&" . "SigAlg=" . urlencode($algURI); + + // check if public key of sp exists + $publickey = $this->configuration->getBaseDir() . '/cert/' . $md['certificate']; + if (!file_exists($publickey)) { + throw new Exception('Could not find private key file [' . $publickey . '] which is needed to verify the request.'); + } + + // getting signature from get arguments + $signature = base64_decode(($_GET['Signature'])); + + // verify signature using xmlseclibs + $xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'public')); + $xmlseckey->loadKey($publickey,TRUE); + + if (!$xmlseckey->verifySignature($query,$signature)) { + throw new Exception("Unable to validate Signature"); + } + + //signature ok + return true; } @@ -187,7 +217,7 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { } } else { $relaystate = NULL; - } + } $samlRequestXML = gzinflate(base64_decode( $rawRequest )); diff --git a/lib/SimpleSAML/XML/SAML20/LogoutResponse.php b/lib/SimpleSAML/XML/SAML20/LogoutResponse.php index f30f87a23..5378c7a0a 100644 --- a/lib/SimpleSAML/XML/SAML20/LogoutResponse.php +++ b/lib/SimpleSAML/XML/SAML20/LogoutResponse.php @@ -88,7 +88,6 @@ class SimpleSAML_XML_SAML20_LogoutResponse { return $issuer; } - // Not updated for response. from request. public function generate($issuer, $receiver, $inresponseto, $mode ) { if (!in_array($mode, array('SP', 'IdP'))) { diff --git a/metadata-templates/saml20-idp-hosted.php b/metadata-templates/saml20-idp-hosted.php index ced429555..cbb8d96c9 100644 --- a/metadata-templates/saml20-idp-hosted.php +++ b/metadata-templates/saml20-idp-hosted.php @@ -25,7 +25,16 @@ $metadata = array( 'base64attributes' => false, // Authentication plugin to use. login.php is the default one that uses LDAP. - 'auth' => 'auth/login.php' + 'auth' => 'auth/login.php', + + /* + * When request.signing is true the privatekey and certificate of the SP + * will be used to sign/verify all messages received/sent with the HTTPRedirect binding. + * + * The certificate and privatekey from above will be used for signing and + * verification purposes. + */ + 'request.signing' => true ) ); diff --git a/metadata-templates/saml20-idp-remote.php b/metadata-templates/saml20-idp-remote.php index b44354b37..f97c08c14 100644 --- a/metadata-templates/saml20-idp-remote.php +++ b/metadata-templates/saml20-idp-remote.php @@ -19,7 +19,18 @@ $metadata = array( 'SingleSignOnService' => 'https://idp.example.org/simplesaml/saml2/idp/SSOService.php', 'SingleLogoutService' => 'https://idp.example.org/simplesaml/saml2/idp/SingleLogoutService.php', 'certFingerprint' => '3fa158e8abfd4b5203315b08c0b791b6ee4715f6', - 'base64attributes' => true + 'base64attributes' => true, + + /* + * When request.signing is true the certificate of the IdP will be used + * to verify all messages received with the HTTPRedirect binding. + * + * The certificate from the IdP must be installed in the cert directory + * before verification can be done. + */ + 'request.signing' => false, + 'certificate' => "idp.example.org.crt", + ), diff --git a/metadata-templates/saml20-sp-hosted.php b/metadata-templates/saml20-sp-hosted.php index cf429df10..1600ce357 100644 --- a/metadata-templates/saml20-sp-hosted.php +++ b/metadata-templates/saml20-sp-hosted.php @@ -17,20 +17,17 @@ $metadata = array( 'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient', 'ForceAuthn' => 'false', + /* - * This option configures the name of a file which contains a - * RSA key for this service provider. The file must be located - * in the cert-directory of the SimpleSAMLPHP installation. - * - * This key will be used to sign all outgoing authentication- - * requests, logoutrequests and logoutresponses (everything - * that uses the HTTP-Redirect binding). - * - * To enable signing, set this option to a private key file - * and enable the 'binding.httpredirect.sign' global option. + * When request.signing is true the privatekey and certificate of the SP + * will be used to sign/verify all messages received/sent with the HTTPRedirect binding. + * + * Certificate and privatekey must be placed in the cert directory. */ + 'request.signing' => true, 'privatekey' => 'server.pem', - + 'certificate' => 'server.pem', + ) ); diff --git a/metadata-templates/saml20-sp-remote.php b/metadata-templates/saml20-sp-remote.php index 2a7ddbe68..026e6e8af 100644 --- a/metadata-templates/saml20-sp-remote.php +++ b/metadata-templates/saml20-sp-remote.php @@ -32,6 +32,15 @@ $metadata = array( 'simplesaml.attributes' => true, // 'attributemap' => 'test', // 'attributes' => array('mail') + /* + * When request.signing is true the certificate of the sp + * will be used to verify all messages received with the HTTPRedirect binding. + * + * The certificate from the SP must be installed in the cert directory + * before verification can be done. + */ + 'request.signing' => false, + 'certificate' => "saml2sp.example.org.crt", ), /* diff --git a/www/admin/metadata.php b/www/admin/metadata.php index 301aacb28..b1cdda863 100644 --- a/www/admin/metadata.php +++ b/www/admin/metadata.php @@ -25,7 +25,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'host', 'NameIDFormat', 'ForceAuthn'), - array() + array('request.signing','certificate','privatekey') ); } $et->data['metadata.saml20-sp-hosted'] = $results; @@ -35,7 +35,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'SingleSignOnService', 'SingleLogoutService', 'certFingerprint'), - array('name', 'description', 'base64attributes') + array('name', 'description', 'base64attributes','request.signing','certificate') ); } $et->data['metadata.saml20-idp-remote'] = $results; @@ -48,7 +48,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'host', 'privatekey', 'certificate', 'auth'), - array('requireconsent') + array('requireconsent','request.signing') ); } $et->data['metadata.saml20-idp-hosted'] = $results; @@ -58,7 +58,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'spNameQualifier', 'AssertionConsumerService', 'SingleLogoutService', 'NameIDFormat'), - array('base64attributes', 'attributemap', 'simplesaml.attributes', 'attributes', 'name', 'description') + array('base64attributes', 'attributemap', 'simplesaml.attributes', 'attributes', 'name', 'description','request.signing','certificate') ); } $et->data['metadata.saml20-sp-remote'] = $results; diff --git a/www/logout.html b/www/logout.html index 6f6362203..66ddd2c1e 100644 --- a/www/logout.html +++ b/www/logout.html @@ -59,7 +59,7 @@ h6 {font-size: 96%} <p>Thanks for using this service. Now you are logged out using Single Logout.</p> - <p>[ <a href="index.php">Go back to simpleSAMLphp installation page</a> ]</p></p> + <p>[ <a href="index.php">Go back to simpleSAMLphp installation page</a> ]</p> <h2>About simpleSAMLphp</h2> <p>Hey! This simpleSAMLphp thing is pretty cool, where can I read more about it? diff --git a/www/saml2/idp/SSOService.php b/www/saml2/idp/SSOService.php index 09ebe1a8f..027f04750 100644 --- a/www/saml2/idp/SSOService.php +++ b/www/saml2/idp/SSOService.php @@ -40,6 +40,11 @@ if (isset($_GET['SAMLRequest'])) { $session = $authnrequest->createSession(); $requestid = $authnrequest->getRequestID(); + + if ($binding->validateQuery($authnrequest->getIssuer(),'IdP')) { + $logger->log(LOG_INFO, $session->getTrackID(), 'SAML2.0', 'IdP.SSOService', 'AuthnRequest', $requestid, 'Valid signature found'); + } + $session->setAuthnRequest($requestid, $authnrequest); $logger->log(LOG_NOTICE, $session->getTrackID(), 'SAML2.0', 'IdP.SSOService', 'AuthnRequest', @@ -55,7 +60,7 @@ if (isset($_GET['SAMLRequest'])) { $et->data['e'] = $exception; $et->show(); - + exit(0); } } elseif(isset($_GET['RequestID'])) { @@ -85,6 +90,7 @@ if (isset($_GET['SAMLRequest'])) { $et->data['e'] = $exception; $et->show(); + exit(0); } @@ -202,4 +208,4 @@ if (!$session->isAuthenticated() ) { } -?> \ No newline at end of file +?> diff --git a/www/saml2/idp/SingleLogoutService.php b/www/saml2/idp/SingleLogoutService.php index 2fa3b21c0..3956c9c66 100644 --- a/www/saml2/idp/SingleLogoutService.php +++ b/www/saml2/idp/SingleLogoutService.php @@ -6,6 +6,7 @@ require_once('../../../www/_include.php'); require_once('SimpleSAML/Utilities.php'); require_once('SimpleSAML/Session.php'); +require_once('SimpleSAML/Logger.php'); require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php'); require_once('SimpleSAML/XML/SAML20/LogoutRequest.php'); require_once('SimpleSAML/XML/SAML20/LogoutResponse.php'); @@ -21,15 +22,36 @@ $idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted'); $session = SimpleSAML_Session::getInstance(); +$logger = new SimpleSAML_Logger(); + +$logger->log(LOG_INFO, $session->getTrackID(), 'SAML2.0', 'IdP.SingleLogoutService', 'EVENT', 'Access', + 'Accessing SAML 2.0 IdP endpoint SingleLogoutService'); /* * If we get an LogoutRequest then we initiate the logout process. */ if (isset($_GET['SAMLRequest'])) { $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - $logoutrequest = $binding->decodeLogoutRequest($_GET); + try { + $logoutrequest = $binding->decodeLogoutRequest($_GET); + + if ($binding->validateQuery($logoutrequest->getIssuer(),'IdP')) { + $logger->log(LOG_INFO, $session->getTrackID(), 'SAML2.0', 'IdP.SingleLogoutService', 'LogoutRequest', $logoutrequest->getRequestID(), 'Valid signature found'); + } + + } catch(Exception $exception) { + + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); + $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); + + } /* Check if we have a valid session. */ if($session === NULL) { /* Invalid session. To prevent the user from being unable to @@ -42,44 +64,66 @@ if (isset($_GET['SAMLRequest'])) { /* Generate the response. */ $response = new SimpleSAML_XML_SAML20_LogoutResponse($config, - $metadata); + $metadata); $responseText = $response->generate($idpentityid, $spentityid, - $logoutrequest->getRequestID(), 'IdP'); + $logoutrequest->getRequestID(), 'IdP'); /* Retrieve the relay state from the request. */ $relayState = $logoutrequest->getRelayState(); /* Send the response using the HTTP-Redirect binding. */ $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, - $metadata); + $metadata); $binding->sendMessage($responseText, $idpentityid, $spentityid, $relayState, 'SingleLogoutService', 'SAMLResponse', 'IdP'); exit; } - + $session->setAuthenticated(false); //$requestid = $authnrequest->getRequestID(); //$session->setAuthnRequest($requestid, $authnrequest); - + //echo '<pre>' . htmlentities($logoutrequest->getXML()) . '</pre>'; - + error_log('IdP LogoutService: got Logoutrequest from ' . $logoutrequest->getIssuer() . ' '); - + $session->set_sp_logout_completed($logoutrequest->getIssuer() ); $session->setLogoutRequest($logoutrequest); -/* - * We receive a Logout Response to a Logout Request that we have issued earlier. - */ + /* + * We receive a Logout Response to a Logout Request that we have issued earlier. + */ } elseif (isset($_GET['SAMLResponse'])) { $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - $loginresponse = $binding->decodeLogoutResponse($_GET); - + + try { + $loginresponse = $binding->decodeLogoutResponse($_GET); + + if ($binding->validateQuery($loginresponse->getIssuer(),'SP','SAMLResponse')) { + $logger->log(LOG_NOTICE, $trackId, 'SAML2.0', 'SP.SingleLogoutService', 'LogoutResponse', 'SingleLogoutServiceResponse','Valid signature found'); + } + + + } catch(Exception $exception) { + + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); + + $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); + + } + + + $session->set_sp_logout_completed($loginresponse->getIssuer()); - + error_log('IdP LogoutService: got LogoutResponse from ' . $loginresponse->getIssuer() . ' '); } @@ -98,12 +142,12 @@ if ($spentityid) { try { $lr = new SimpleSAML_XML_SAML20_LogoutRequest($config, $metadata); - + // ($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) { $req = $lr->generate($idpentityid, $spentityid, $session->getNameID(), $session->getNameIDFormat(), $session->getSessionIndex(), 'IdP'); - + $httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - + $relayState = SimpleSAML_Utilities::selfURL(); if (isset($_GET['RelayState'])) { $relayState = $_GET['RelayState']; @@ -112,20 +156,20 @@ if ($spentityid) { $relayState = stripslashes($relayState); } } - + //$request, $remoteentityid, $relayState = null, $endpoint = 'SingleLogoutService', $direction = 'SAMLRequest', $mode = 'SP' $httpredirect->sendMessage($req, $idpentityid, $spentityid, $relayState, 'SingleLogoutService', 'SAMLRequest', 'IdP'); - + exit(); } catch(Exception $exception) { - + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); - + $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['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); } @@ -145,16 +189,16 @@ try { } $rg = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata); - + // generate($issuer, $receiver, $inresponseto, $mode ) - + $logoutResponseXML = $rg->generate($idpentityid, $logoutrequest->getIssuer(), $logoutrequest->getRequestID(), 'IdP'); - + // echo '<pre>' . htmlentities($logoutResponseXML) . '</pre>'; // exit(); - + $httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - + $relayState = SimpleSAML_Utilities::selfURL(); if (isset($_GET['RelayState'])) { $relayState = $_GET['RelayState']; @@ -163,18 +207,18 @@ try { $relayState = stripslashes($relayState); } } - + //$request, $remoteentityid, $relayState = null, $endpoint = 'SingleLogoutService', $direction = 'SAMLRequest', $mode = 'SP' $httpredirect->sendMessage($logoutResponseXML, $idpentityid, $logoutrequest->getIssuer(), $relayState, 'SingleLogoutService', 'SAMLResponse', 'IdP'); } catch(Exception $exception) { - + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); - + $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['message'] = 'Some error occured when trying to issue the logout response, and send it to the SP.'; $et->data['e'] = $exception; - + $et->show(); } diff --git a/www/saml2/sp/SingleLogoutService.php b/www/saml2/sp/SingleLogoutService.php index 53cf3c1f1..a958c61bc 100644 --- a/www/saml2/sp/SingleLogoutService.php +++ b/www/saml2/sp/SingleLogoutService.php @@ -10,6 +10,7 @@ require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php'); require_once('SimpleSAML/XML/SAML20/LogoutRequest.php'); require_once('SimpleSAML/XML/SAML20/LogoutResponse.php'); require_once('SimpleSAML/Bindings/SAML20/HTTPPost.php'); +require_once('SimpleSAML/XHTML/Template.php'); $config = SimpleSAML_Configuration::getInstance(); $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); @@ -32,7 +33,7 @@ $logger->log(LOG_INFO, $trackId, 'SAML2.0', 'SP.SingleLogoutService', 'EVENT', ' 'Accessing SAML 2.0 SP endpoint SingleLogoutService'); // Destroy local session if exists. -if (isset($session) && $session->isAuthenticated() ) { +if (isset($session) && $session->isAuthenticated() ) { $session->setAuthenticated(false); } @@ -40,54 +41,90 @@ if (isset($session) && $session->isAuthenticated() ) { if (isset($_GET['SAMLRequest'])) { - + // Create a HTTPRedirect binding $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - - // Decode the LogoutRequest using the HTTP Redirect binding. - $logoutrequest = $binding->decodeLogoutRequest($_GET); - - // Extract some parameters from the logout request - $requestid = $logoutrequest->getRequestID(); - $requester = $logoutrequest->getIssuer(); - $relayState = $logoutrequest->getRelayState(); - - - - - - //$responder = $config->getValue('saml2-hosted-sp'); - $responder = $metadata->getMetaDataCurrentEntityID(); - - + try { + // Decode the LogoutRequest using the HTTP Redirect binding. + $logoutrequest = $binding->decodeLogoutRequest($_GET); + + if ($binding->validateQuery($logoutrequest->getIssuer(),'SP')) { + $logger->log(LOG_NOTICE, $trackId, 'SAML2.0', 'SP.SingleLogoutService', 'LogoutRequest', $requestid,'Valid signature found'); + } + + // Extract some parameters from the logout request + $requestid = $logoutrequest->getRequestID(); + $requester = $logoutrequest->getIssuer(); + $relayState = $logoutrequest->getRelayState(); + + //$responder = $config->getValue('saml2-hosted-sp'); + $responder = $metadata->getMetaDataCurrentEntityID(); + + } catch(Exception $exception) { + + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); + + $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); + + } + + + $logger->log(LOG_NOTICE, $trackId, 'SAML2.0', 'SP.SingleLogoutService', 'LogoutRequest', $requestid, 'IdP (' . $requester . ') is sending logout request to me SP (' . $responder . ')'); - + // Create a logout response $lr = new SimpleSAML_XML_SAML20_LogoutResponse($config, $metadata); $logoutResponseXML = $lr->generate($responder, $requester, $requestid, 'SP'); - - + + // Create a HTTP Redirect binding. $httpredirect = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); - - + + $logger->log(LOG_NOTICE, $trackId, 'SAML2.0', 'SP.SingleLogoutService', 'LogoutResponse', '-', 'SP me (' . $responder . ') is sending logout response to IdP (' . $requester . ')'); - + // Send the Logout response using HTTP POST binding. $httpredirect->sendMessage($logoutResponseXML, $responser, $requester, $logoutrequest->getRelayState(), 'SingleLogoutServiceResponse', 'SAMLResponse'); } elseif(isset($_GET['SAMLResponse'])) { - + + // Create a HTTPRedirect binding + $binding = new SimpleSAML_Bindings_SAML20_HTTPRedirect($config, $metadata); + try { + // Decode the LogoutResponse using the HTTP Redirect binding. + $logoutresponse = $binding->decodeLogoutResponse($_GET); + + if ($binding->validateQuery($logoutresponse->getIssuer(),'SP','SAMLResponse')) { + $logger->log(LOG_NOTICE, $trackId, 'SAML2.0', 'SP.SingleLogoutService', 'LogoutResponse', 'SingleLogoutServiceResponse','Valid signature found'); + } + + } catch(Exception $exception) { + + $et = new SimpleSAML_XHTML_Template($config, 'error.php'); + + $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); + + } if (isset($_GET['RelayState'])) { SimpleSAML_Utilities::redirect($_GET['RelayState']); } else { - + echo 'You are now successfully logged out.'; - + } } -- GitLab