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