diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php deleted file mode 100644 index b0a840aaa5004c775325bd755aa2acaf839a44a5..0000000000000000000000000000000000000000 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php +++ /dev/null @@ -1,238 +0,0 @@ -<?php - -/** - * Implementation of the SAML 2.0 HTTP-POST binding. - * - * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no> - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_Bindings_SAML20_HTTPPost { - - private $configuration = null; - private $metadata = null; - - function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore) { - $this->configuration = $configuration; - $this->metadata = $metadatastore; - } - - - public function sendResponseUnsigned($response, $idpentityid, $spentityid, $relayState = null, $endpoint = 'AssertionConsumerService') { - - SimpleSAML_Utilities::validateXMLDocument($response, 'saml20'); - - $idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted'); - $spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote'); - - $destination = $spmd[$endpoint]; - - echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> - <head> - <meta http-equiv="content-type" content="text/html; charset=utf-8"> - <title>Send SAML 2.0 Authentication Response</title> - </head> - <body> - <h1>Send SAML 2.0 Authentication Response</h1> - - <form style="border: 1px solid #777; margin: 2em; padding: 2em" method="post" action="' . $destination . '"> - <input type="hidden" name="SAMLResponse" value="' . base64_encode($response) . '" /> - <input type="hidden" name="RelayState" value="' . $relayState. '"> - <input type="submit" value="Submit the SAML 1.1 Response" /> - </form> - - <ul> - <li>From IdP: <tt>' . $idpentityid . '</tt></li> - <li>To SP: <tt>' . $spentityid . '</tt></li> - <li>SP Assertion Consumer Service URL: <tt>' . $destination . '</tt></li> - <li>RelayState: <tt>' . $relayState . '</tt></li> - </ul> - - <p>SAML Message: <pre>' . htmlentities($response) . '</pre> - - - </body> - </html>'; - } - - public function sendResponse($response, $idmetaindex, $spentityid, $relayState = null) { - - $idpmd = $this->metadata->getMetaData($idmetaindex, 'saml20-idp-hosted'); - $spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote'); - - $destination = $spmd['AssertionConsumerService']; - - $privatekey = SimpleSAML_Utilities::loadPrivateKey($idpmd, TRUE); - $publickey = SimpleSAML_Utilities::loadPublicKey($idpmd, TRUE); - - $signer = new SimpleSAML_XML_Signer(array( - 'privatekey_array' => $privatekey, - 'publickey_array' => $publickey, - 'id' => 'ID', - )); - - try { - $responsedom = new DOMDocument(); - $responsedom->loadXML(str_replace("\n", "", str_replace ("\r", "", $response))); - } catch (Exception $e) { - throw new Exception("foo"); - } - - $responseroot = $responsedom->getElementsByTagName('Response')->item(0); - $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0); - - - /* Determine what we should sign - either the Response element or the Assertion. The default - * is to sign the Assertion, but that can be overridden by the 'signresponse' option in the - * SP metadata or 'saml20.signresponse' in the global configuration. - */ - $signResponse = FALSE; - if(array_key_exists('signresponse', $spmd) && $spmd['signresponse'] !== NULL) { - $signResponse = $spmd['signresponse']; - if(!is_bool($signResponse)) { - throw new Exception('Expected the \'signresponse\' option in the metadata of the' . - ' SP \'' . $spmd['entityid'] . '\' to be a boolean value.'); - } - } else { - $signResponse = $this->configuration->getBoolean('saml20.signresponse', FALSE); - } - - /* Check if we have an assertion to sign. Force to sign the response if not. */ - if($firstassertionroot === NULL) { - $signResponse = TRUE; - } - - if(!$signResponse) { - /* Sign the assertion - this must be done before encrypting the assertion. */ - - /* We insert the signature before the saml2:Subject element. */ - $subjectElements = SimpleSAML_Utilities::getDOMChildren( - $firstassertionroot, 'Subject', '@saml2'); - assert('count($subjectElements) === 1'); - - $signer->sign($firstassertionroot, $firstassertionroot, $subjectElements[0]); - } - - /* if the response status is not Success (eg. NoPassive) there is no assertions (firstassertionroot == null) to encrypt */ - if (isset($spmd['assertion.encryption']) && $spmd['assertion.encryption'] && $firstassertionroot != null) { - $encryptedassertion = $responsedom->createElement("saml:EncryptedAssertion"); - $encryptedassertion->setAttribute("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion"); - - $firstassertionroot->parentNode->replaceChild($encryptedassertion, $firstassertionroot); - $encryptedassertion->appendChild($firstassertionroot); - $firstassertionroot->setAttribute("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion"); - $firstassertionroot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); - - $enc = new XMLSecEnc(); - $enc->setNode($firstassertionroot); - $enc->type = XMLSecEnc::Element; - - $objKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); - if (isset($spmd['sharedkey'])) { - $objKey->loadkey($spmd['sharedkey']); - } else { - $key = $objKey->generateSessionKey(); - $objKey->loadKey($key); - - if (!isset($spmd['certificate'])) { - throw new Exception("Public key for encrypting assertion needed, but not specified for saml20-sp-remote id: " . $spentityid); - } - - $sp_publiccert = @file_get_contents($this->configuration->getPathValue('certdir') . $spmd['certificate']); - - if ($sp_publiccert === FALSE) { - throw new Exception("Public key for encrypting assertion specified but not found for saml20-sp-remote id: " . $spentityid . " Filename: " . $spmd['certificate']); - } - - $keyKey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'public')); - - $keyKey->loadKey($sp_publiccert); - - $enc->encryptKey($keyKey, $objKey); - } - $encNode = $enc->encryptNode($objKey); # replacing the unencrypted node - - } - - if($signResponse) { - /* Sign the response - this must be done after encrypting the assertion. */ - - /* We insert the signature before the saml2p:Status element. */ - $statusElements = SimpleSAML_Utilities::getDOMChildren($responseroot, 'Status', '@saml2p'); - assert('count($statusElements) === 1'); - - $signer->sign($responseroot, $responseroot, $statusElements[0]); - } - - - $response = $responsedom->saveXML(); - - SimpleSAML_Utilities::validateXMLDocument($response, 'saml20'); - - # openssl genrsa -des3 -out server.key 1024 - # openssl rsa -in server.key -out server.pem - # openssl req -new -key server.key -out server.csr - # openssl x509 -req -days 60 -in server.csr -signkey server.key -out server.crt - - if ($this->configuration->getValue('debug')) { - - $p = new SimpleSAML_XHTML_Template($this->configuration, 'post-debug.php'); - - $p->data['header'] = 'SAML Response Debug-mode'; - $p->data['RelayStateName'] = 'RelayState'; - $p->data['RelayState'] = $relayState; - $p->data['destination'] = $destination; - $p->data['response'] = str_replace("\n", "", base64_encode($response)); - $p->data['responseHTML'] = htmlspecialchars(SimpleSAML_Utilities::formatXMLString($response)); - - $p->show(); - - - } else { - - $data = array('SAMLResponse' => base64_encode($response)); - if ($relayState !== NULL) { - $data['RelayState'] = $relayState; - } - - SimpleSAML_Utilities::postRedirect($destination, $data); - } - - - } - - public function decodeResponse($post) { - if (!isset($post["SAMLResponse"])) throw new Exception('Could not get SAMLResponse from Browser/POST. May be there is some redirection related problem on your server? In example apache redirecting the POST to http to a GET on https.'); - - $rawResponse = $post["SAMLResponse"]; - $relaystate = $post["RelayState"]; - - - - $samlResponseXML = base64_decode( $rawResponse ); - - SimpleSAML_Utilities::validateXMLDocument($samlResponseXML, 'saml20'); - - //error_log("Response is: " . $samlResponseXML); - - $samlResponse = new SimpleSAML_XML_SAML20_AuthnResponse($this->configuration, $this->metadata); - - $samlResponse->setXML($samlResponseXML); - - if (isset($relaystate)) { - $samlResponse->setRelayState($relaystate); - } - - #echo("Authn response = " . $samlResponse ); - - return $samlResponse; - - } - - - -} - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php deleted file mode 100644 index 23e6bcc93d1ccf4056ec37b7ddc3bf2f3d0de715..0000000000000000000000000000000000000000 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php +++ /dev/null @@ -1,373 +0,0 @@ -<?php - -/** - * Implementation of the SAML 2.0 HTTP-REDIRECT binding. - * - * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no> - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_Bindings_SAML20_HTTPRedirect { - - private $configuration = null; - private $metadata = null; - - function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore) { - $this->configuration = $configuration; - $this->metadata = $metadatastore; - } - - - /** - * Sign a HTTP-Redirect query string. - * - * @param string $query The query string. - * @param array $md The metadata of the sender. - * @param array $targetmd The metadata of the recipient. - * @return string The signed query. - */ - public function signQuery($query, $md, $targetmd) { - assert('is_string($query)'); - assert('is_array($md)'); - assert('is_array($targetmd)'); - - /* Check if signing of HTTP-Redirect messages is enabled. */ - if (array_key_exists('redirect.sign', $targetmd)) { - $sign = (bool)$targetmd['redirect.sign']; - } elseif (array_key_exists('redirect.sign', $md)) { - $sign = (bool)$md['redirect.sign']; - } elseif (array_key_exists('request.signing', $md)) { - SimpleSAML_Logger::warning('Found deprecated \'request.signing\' metadata' . - ' option for entity ' . var_export($md['entityid'], TRUE) . '.' . - ' Please replace with \'redirect.sign\' instead.'); - $sign = (bool)$md['request.signing']; - } else { - $sign = FALSE; - } - - if (!$sign) { - /* Signing of queries disabled. */ - return $query; - } - - - /* Load the private key. */ - $privatekey = SimpleSAML_Utilities::loadPrivateKey($md, TRUE); - - /* 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 - * - RelayState (if present) - * - SigAlg - * - * We assume that the query string now contains only the two first parameters. - */ - - /* 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')); - - /* Set the passphrase which should be used to open the key, if this attribute is - * set in the metadata. - */ - if(array_key_exists('password', $privatekey)) { - $xmlseckey->passphrase = $privatekey['password']; - } - - $xmlseckey->loadKey($privatekey['PEM']); - $signature = $xmlseckey->signData($query); - - $query = $query . "&" . "Signature=" . urlencode(base64_encode($signature)); - - return $query; - } - - - /** - * Validate query string. - * - * This function validates the signature on the query string of the current request. - * - * @param string $issuer The issuer of this query string. - * @param string $mode Whether we are running as an SP or an IdP. - * @param string $request The query parameter which contains the request/response we should validate. - * @return bool FALSE if the query string wasn't validated, TRUE if it validate. An exception will be - * thrown if the validation fails. - */ - public function validateQuery($issuer, $mode = 'SP', $request = 'SAMLRequest') { - assert('is_string($issuer)'); - assert('$mode === "SP" || $mode === "IdP"'); - assert('$request === "SAMLRequest" || $request === "SAMLResponse"'); - - if ($mode == 'IdP') { - $issuerSet = 'saml20-sp-remote'; - $recipientSet = 'saml20-idp-hosted'; - } else { - $issuerSet = 'saml20-idp-remote'; - $recipientSet = 'saml20-sp-hosted'; - } - SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Looking up metadata issuer:' . $issuer . ' in set '. $issuerSet); - $md = $this->metadata->getMetaData($issuer, $issuerSet); - - $recipientMetadata = $this->metadata->getMetaDataCurrent($recipientSet); - - // check whether to validate or not - if (array_key_exists('redirect.validate', $md)) { - $validate = (bool)$md['redirect.validate']; - } elseif (array_key_exists('redirect.validate', $recipientMetadata)) { - $validate = (bool)$recipientMetadata['redirect.validate']; - } elseif (array_key_exists('request.signing', $md)) { - SimpleSAML_Logger::warning('Found deprecated \'request.signing\' metadata' . - ' option for entity ' . var_export($issuer, TRUE) . '.' . - ' Please replace with \'redirect.validate\' instead.'); - $validate = (bool)$md['request.signing']; - } else { - $validate = FALSE; - } - - if (!$validate) { - return false; - } - - if (!isset($_GET['Signature'])) { - throw new Exception('No Signature on the request, required by configuration'); - } - - SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): All required paramaters received.'); - - // building query string - $query = $request.'='.urlencode($_GET[$request]); - - if(array_key_exists('RelayState', $_GET)) { - $relaystate = $_GET['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); - - SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Built query: ' . $query); - SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Sig Alg: ' . $algURI); - - - $publickey = SimpleSAML_Utilities::loadPublicKey($md, TRUE); - if (!array_key_exists('PEM', $publickey)) { - throw new Exception('We need a full public key to validate HTTP-Redirect signatures. A fingerprint is not enough.'); - } - - // getting signature from get arguments - $signature = @base64_decode($_GET['Signature']); - if (!$signature) { - throw new Exception('Error base64 decoding signature parameter.'); - } - - // verify signature using xmlseclibs - $xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'public')); - $xmlseckey->loadKey($publickey['PEM']); - - if (!$xmlseckey->verifySignature($query,$signature)) { - throw new Exception("Unable to validate Signature"); - } - - //signature ok - return true; - } - - - public function getRedirectURL($request, $localentityid, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnService', $direction = 'SAMLRequest', $mode = 'SP') { - - if (!in_array($mode, array('SP', 'IdP'))) { - throw new Exception('mode parameter of sendMessage() must be either SP or IdP'); - } - $metadataset = 'saml20-idp-remote'; - if ($mode == 'IdP') { - $metadataset = 'saml20-sp-remote'; - } - - $md = $this->metadata->getMetaData($remoteentityid, $metadataset); - - $realendpoint = $endpoint; - if ($endpoint == 'SingleLogoutServiceResponse' && !isset($md[$endpoint])) - $realendpoint = 'SingleLogoutService'; - - $idpTargetUrl = $md[$realendpoint]; - - if (!isset($idpTargetUrl) or $idpTargetUrl == '') { - throw new Exception('Could not find endpoint [' .$endpoint . '] in metadata for [' . $remoteentityid . '] (looking in ' . $metadataset . ')'); - } - - $request = urlencode( base64_encode( gzdeflate( $request ) )); - $request = $direction . "=" . $request; - if (isset($relayState)) { - $request .= "&RelayState=" . urlencode($relayState); - } - - $metadataset = 'saml20-sp-hosted'; - if ($mode == 'IdP') { - $metadataset = 'saml20-idp-hosted'; - } - $localmd = $this->metadata->getMetaData($localentityid, $metadataset); - $request = $this->signQuery($request, $localmd, $md); - $redirectURL = $idpTargetUrl . "?" . $request; - - return $redirectURL; - - } - # $request, $localentityid, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnService', $direction = 'SAMLRequest', $mode = 'SP' - public function sendMessage($request, $localentityid, $remoteentityid, $relayState = null, $endpoint = 'SingleSignOnService', $direction = 'SAMLRequest', $mode = 'SP') { - - SimpleSAML_Utilities::validateXMLDocument($request, 'saml20'); - - $redirectURL = $this->getRedirectURL($request, $localentityid, $remoteentityid, $relayState, $endpoint, $direction, $mode); - - if ($this->configuration->getValue('debug')) { - - $p = new SimpleSAML_XHTML_Template($this->configuration, 'httpredirect-debug.php'); - - $p->data['header'] = 'HTTP-REDIRECT Debug'; - $p->data['url'] = $redirectURL; - $p->data['message'] = htmlspecialchars(SimpleSAML_Utilities::formatXMLString($request)); - - $p->show(); - - - } else { - - SimpleSAML_Utilities::redirect($redirectURL); - - } - - } - - - - public function decodeRequest($get) { - if (!isset($get['SAMLRequest'])) { - throw new Exception('SAMLRequest parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)'); - } - $rawRequest = $get["SAMLRequest"]; - - /* Check if the service provider has included a RelayState - * parameter with the request. This parameter should be - * included in the response to the SP after authentication. - */ - if(array_key_exists('RelayState', $get)) { - $relaystate = $get['RelayState']; - } else { - $relaystate = NULL; - } - - $decodedRequest = @base64_decode($rawRequest); - if (!$decodedRequest) { - throw new Exception('Could not base64 decode SAMLRequest GET parameter'); - } - - $samlRequestXML = @gzinflate($decodedRequest); - if (!$samlRequestXML) { - $error = error_get_last(); - throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message'] ); - } - - SimpleSAML_Utilities::validateXMLDocument($samlRequestXML, 'saml20'); - - $samlRequest = new SimpleSAML_XML_SAML20_AuthnRequest($this->configuration, $this->metadata); - - $samlRequest->setXML($samlRequestXML); - - if (!is_null($relaystate)) { - $samlRequest->setRelayState($relaystate); - } - - return $samlRequest; - - } - - public function decodeLogoutRequest($get) { - if (!isset($get['SAMLRequest'])) { - throw new Exception('SAMLRequest parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)'); - } - $rawRequest = $get["SAMLRequest"]; - - /* Check if a RelayState was provided with the request. */ - if(array_key_exists('RelayState', $get)) { - $relaystate = $get['RelayState']; - } else { - $relaystate = NULL; - } - - $decodedRequest = @base64_decode($rawRequest); - if (!$decodedRequest) { - throw new Exception('Could not base64 decode SAMLRequest GET parameter'); - } - - $samlRequestXML = @gzinflate($decodedRequest); - if (!$samlRequestXML) { - $error = error_get_last(); - throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message'] ); - } - - SimpleSAML_Utilities::validateXMLDocument($samlRequestXML, 'saml20'); - - $samlRequest = new SimpleSAML_XML_SAML20_LogoutRequest($this->configuration, $this->metadata); - - $samlRequest->setXML($samlRequestXML); - - if (isset($relaystate)) { - $samlRequest->setRelayState($relaystate); - } - - #echo("Authn response = " . $samlResponse ); - - return $samlRequest; - } - - public function decodeLogoutResponse($get) { - if (!isset($get['SAMLResponse'])) { - throw new Exception('SAMLResponse parameter not set in paramter (on SAML 2.0 HTTP Redirect binding endpoint)'); - } - $rawRequest = $get["SAMLResponse"]; - - /* Check if a RelayState was provided with the request. */ - if(array_key_exists('RelayState', $get)) { - $relaystate = $get['RelayState']; - } else { - $relaystate = NULL; - } - - $decodedRequest = @base64_decode($rawRequest); - if (!$decodedRequest) { - throw new Exception('Could not base64 decode SAMLRequest GET parameter'); - } - - $samlRequestXML = @gzinflate($decodedRequest); - if (!$samlRequestXML) { - $error = error_get_last(); - throw new Exception('Could not gzinflate base64 decoded SAMLRequest: ' . $error['message'] ); - } - - SimpleSAML_Utilities::validateXMLDocument($samlRequestXML, 'saml20'); - - - $samlRequest = new SimpleSAML_XML_SAML20_LogoutResponse($this->configuration, $this->metadata); - - $samlRequest->setXML($samlRequestXML); - - if (isset($relaystate)) { - $samlRequest->setRelayState($relaystate); - } - - #echo("Authn response = " . $samlResponse ); - - return $samlRequest; - } - -} - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/XML/SAML20/AuthnRequest.php b/lib/SimpleSAML/XML/SAML20/AuthnRequest.php deleted file mode 100644 index 261d7dfcc88d5740ed7952900ff5dd25f1dabb15..0000000000000000000000000000000000000000 --- a/lib/SimpleSAML/XML/SAML20/AuthnRequest.php +++ /dev/null @@ -1,323 +0,0 @@ -<?php - -/** - * The Shibboleth 1.3 Authentication Request. Not part of SAML 1.1, - * but an extension using query paramters no XML. - * - * @author Andreas Aakre Solberg, UNINETT AS. <andreas.solberg@uninett.no> - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_XML_SAML20_AuthnRequest { - - private $configuration = null; - private $metadata = 'default.php'; - - private $message = null; - private $dom; - private $relayState = null; - private $isPassive = null; - - - const PROTOCOL = 'saml2'; - - /** - * This variable holds the generated request id for this request. - */ - private $id = null; - - - function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore) { - $this->configuration = $configuration; - $this->metadata = $metadatastore; - - /* Generate request id. */ - $this->id = SimpleSAML_Utilities::generateID(); - } - - public function setXML($xml) { - $this->message = $xml; - } - - public function getXML() { - return $this->message; - } - - public function setRelayState($relayState) { - $this->relayState = $relayState; - } - - public function getRelayState() { - return $this->relayState; - } - - public function getDOM() { - if (isset($this->message) ) { - - /* if (isset($this->dom) && $this->dom != null ) { - return $this->dom; - } */ - - $token = new DOMDocument(); - $token->loadXML(str_replace ("\r", "", $this->message)); - if (empty($token)) { - throw new Exception("Unable to load token"); - } - $this->dom = $token; - return $this->dom; - - } - - return null; - } - - - public function getIssuer() { - $dom = $this->getDOM(); - $issuer = null; - - if (!$dom instanceof DOMDocument) { - throw new Exception("Could not get message DOM in AuthnRequest object"); - } - - //print_r($dom->saveXML()); - - if ($issuerNodes = $dom->getElementsByTagName('Issuer')) { - if ($issuerNodes->length > 0) { - $issuer = trim($issuerNodes->item(0)->textContent); - } - } - return $issuer; - } - - public function getRequestID() { - $dom = $this->getDOM(); - $requestid = null; - - if (empty($dom)) { - throw new Exception("Could not get message DOM in AuthnRequest object"); - } - - $requestelement = $dom->getElementsByTagName('AuthnRequest')->item(0); - $requestid = $requestelement->getAttribute('ID'); - return $requestid; - /* - if ($issuerNodes = $dom->getElementsByTagName('Issuer')) { - if ($issuerNodes->length > 0) { - $requestid = $issuerNodes->item(0)->textContent; - } - } - return $requestid; - */ - } - - - /** - * This function sets the IsPassive flag - * - */ - public function setIsPassive($isPassive) { - $this->isPassive = $isPassive ? 'true' : 'false'; - } - - /** - * This function retrieves the IsPassive flag from this authentication request. - * - * @return The IsPassive flag from this authentication request. - */ - public function getIsPassive() { - $dom = $this->getDOM(); - if (empty($dom)) { - throw new Exception("Could not get message DOM in AuthnRequest object"); - } - - $root = $dom->documentElement; - - if(!$root->hasAttribute('IsPassive')) { - /* ForceAuthn defaults to false. */ - return FALSE; - } - - $ispas = $root->getAttribute('IsPassive'); - try{ - return $this->isSamlBoolTrue($ispas); - }catch(Exception $e){ - // ... I don't understand ... - // return FALSE; - throw new Exception('Invalid value of IsPassive attribute in SAML2 AuthnRequest.'); - } - } - - - /** - * This function retrieves the ForceAuthn flag from this authentication request. - * - * @return The ForceAuthn flag from this authentication request. - */ - public function getForceAuthn() { - $dom = $this->getDOM(); - if (empty($dom)) { - throw new Exception("Could not get message DOM in AuthnRequest object"); - } - - $root = $dom->documentElement; - - if(!$root->hasAttribute('ForceAuthn')) { - /* ForceAuthn defaults to false. */ - return FALSE; - } - - $fa = $root->getAttribute('ForceAuthn'); - try{ - return $this->isSamlBoolTrue($fa); - } catch(Exception $e){ - // ... I don't understand ... - // return FALSE; - throw new Exception('Invalid value of ForceAuthn attribute in SAML2 AuthnRequest.'); - } - } - - - - /** - * Generate a new SAML 2.0 Authentication Request - * - * @param $spentityid SP Entity ID - * @param $destination SingleSignOnService endpoint - */ - public function generate($spentityid, $destination) { - $md = $this->metadata->getMetaData($spentityid); - - $issueInstant = SimpleSAML_Utilities::generateTimestamp(); - - $assertionConsumerServiceURL = $this->metadata->getGenerated('AssertionConsumerService', 'saml20-sp-hosted'); - - /* - * Process the SAML 2.0 SP hosted metadata parameter: NameIDFormat - */ - $nameidformat = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'; - $includeNameIDPolicy = true; - if (array_key_exists('NameIDFormat', $md)) { - if (is_null($md['NameIDFormat'])) { - $includeNameIDPolicy = false; - } elseif (!is_string($md['NameIDFormat'])) { - throw new Exception('SAML 2.0 SP hosted metadata parameter [NameIDFormat] must be a string.'); - } else { - $nameidformat = $md['NameIDFormat']; - } - } - if ($includeNameIDPolicy) { - $nameIDPolicy = $this->generateNameIDPolicy($nameidformat); - } - - - /* - * Process the SAML 2.0 SP hosted metadata parameter: ForceAuthn - */ - $forceauthn = 'false'; - if (isset($md['ForceAuthn'])) { - if (is_bool($md['ForceAuthn'])) { - $forceauthn = ($md['ForceAuthn'] ? 'true' : 'false'); - } else { - throw new Exception('Illegal format of the ForceAuthn parameter in the SAML 2.0 SP hosted metadata for entity [' . $spentityid . ']. This value should be set to a PHP boolean value.'); - } - } - - /* - * Process the SAML 2.0 SP hosted metadata parameter: AuthnContextClassRef - */ - $requestauthncontext = ''; - if (!empty($md['AuthnContextClassRef'])) { - if (!is_string($md['AuthnContextClassRef'])) { - throw new Exception('SAML 2.0 SP hosted metadata parameter [AuthnContextClassRef] must be a string.'); - } - - $requestauthncontext = '<samlp:RequestedAuthnContext Comparison="exact"> - <saml:AuthnContextClassRef>' . $md['AuthnContextClassRef'] . '</saml:AuthnContextClassRef> - </samlp:RequestedAuthnContext>'; - } - - - /* Check the metadata for isPassive if $this->isPassive === NULL. */ - if($this->isPassive === NULL) { - /* - * Process the SAML 2.0 SP hosted metadata parameter: IsPassive - */ - if (isset($md['IsPassive'])) { - if (is_bool($md['IsPassive'])) { - $this->isPassive = ($md['IsPassive'] ? 'true' : 'false'); - } else { - throw new Exception('Illegal format of the IsPassive parameter in' . - ' the SAML 2.0 SP hosted metadata for entity [' . $spentityid . - ']. This value should be set to a PHP boolean value.'); - } - } else { - /* The default is off. */ - $this->isPassive = 'false'; - } - } - - - /* - * Create the complete SAML 2.0 Authentication Request - */ - $authnRequest = '<samlp:AuthnRequest - xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" - ID="' . $this->id . '" Version="2.0" - IssueInstant="' . $issueInstant . '" ForceAuthn="' . $forceauthn . '" IsPassive="' . $this->isPassive . '" - Destination="' . htmlspecialchars($destination) . '" - ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" - AssertionConsumerServiceURL="' . htmlspecialchars($assertionConsumerServiceURL) . '"> - <saml:Issuer >' . htmlspecialchars($spentityid) . '</saml:Issuer> - ' . $nameIDPolicy . ' - ' . $requestauthncontext . ' -</samlp:AuthnRequest> -'; - - return $authnRequest; - } - - /** - * Generate a NameIDPoliy element - * - * @param $nameidformat NameIDFormat. - */ - public function generateNameIDPolicy($nameidformat) { - return '<samlp:NameIDPolicy - Format="' . htmlspecialchars($nameidformat) . '" - AllowCreate="true" />'; - } - - - /** - * Retrieves the request id we used for the generated authentication request. - * - * @return The request id of the generated authentication request. - */ - public function getGeneratedID() { - return $this->id; - } - - - /** - * Check if a saml attribute value is a legal bool and if it is true or false. - * SAML legal bool values is true/false or 1/0. - * - * @throws Exception when no legal bool value is found - * @param string $boolSaml - * @return bool TRUE or FALSE - */ - private function isSamlBoolTrue($boolSaml){ - $boolSaml = strtolower($boolSaml); - if($boolSaml === 'true' || $boolSaml === '1') { - return TRUE; - } elseif($boolSaml === 'false' || $boolSaml === '0') { - return FALSE; - } else { - throw new Exception('Invalid bool value of attribute in SAML2 AuthnRequest.'); - } - } - -} - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/XML/SAML20/AuthnResponse.php b/lib/SimpleSAML/XML/SAML20/AuthnResponse.php deleted file mode 100644 index 0c38b82a589810611c38c71ed243afd82dc17e62..0000000000000000000000000000000000000000 --- a/lib/SimpleSAML/XML/SAML20/AuthnResponse.php +++ /dev/null @@ -1,981 +0,0 @@ -<?php - -/** - * An SAML 2.0 Authentication Response - * - * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no> - * @author Olav Morken, UNINETT AS - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_XML_SAML20_AuthnResponse extends SimpleSAML_XML_AuthnResponse { - - - const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0'; - - const TRANSIENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'; - const PERSISTENT = 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'; - const EMAIL = 'urn:oasis:names:tc:SAML:2.0:nameid-format:email'; - - /* Namespaces used in the XML representation of this object. - * TODO: Move these constants into a generic SAML2-class? - */ - const SAML2_ASSERT_NS = 'urn:oasis:names:tc:SAML:2.0:assertion'; - const SAML2_PROTOCOL_NS = 'urn:oasis:names:tc:SAML:2.0:protocol'; - - - /** - * This variable contains an XML validator for this message. - */ - private $validator = NULL; - - - /** - * This varaible contains the entitiyid of the IdP which issued this message. - */ - private $issuer = NULL; - - - /** - * This variable contains the NameID of this subject. It is an associative array with - * two keys: - * - 'Format' The type of the NameID. - * - 'value' Tha value of the NameID. - * - * This variable will be set by the processSubject function. A exception will be thrown if the response - * contains two different NameIDs. - */ - private $nameid = NULL; - - - /** - * This variable contains the SessionIndex, as set by a AuthnStatement element in an assertion. - */ - private $sessionIndex = NULL; - - - /** - * This associative array contains the attribute we extract from the response. - */ - private $attributes = array(); - - - function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore) { - $this->configuration = $configuration; - $this->metadata = $metadatastore; - } - - - /* The following methods aren't used anymore. They are included because it is required by inheritance. - * TODO: Remove them. - */ - public function validate() { throw new Exception('TODO!'); } - public function createSession() { throw new Exception('TODO!'); } - - - /** - * This function runs an xPath query on this authentication response. - * - * @param $query The query which should be run. - * @param $node The node which this query is relative to. If this node is NULL (the default) - * then the query will be relative to the root of the response. - * @return Whatever DOMXPath::query returns. - */ - private function doXPathQuery($query, $node = NULL) { - assert('is_string($query)'); - - $dom = $this->getDOM(); - assert('$dom instanceof DOMDocument'); - - if($node === NULL) { - $node = $dom->documentElement; - } - - assert('$node instanceof DOMNode'); - - $xPath = new DOMXpath($dom); - $xPath->registerNamespace("saml", self::SAML2_ASSERT_NS); - $xPath->registerNamespace("samlp", self::SAML2_PROTOCOL_NS); - $xPath->registerNamespace("ds", 'http://www.w3.org/2000/09/xmldsig#'); - - return $xPath->query($query, $node); - } - - - /** - * This function checks if the user has added the given id to 'saml2.relaxvalidation' - * in the saml2-idp-remote configuration. - * - * @param $id The id which identifies a part of the verification which may be relaxed. - * @return TRUE if this id is added to the list, FALSE if not. - */ - private function isValidationRelaxed($id) { - - assert('is_string($id)'); - assert('$this->issuer != NULL'); - - /* Get the metadata of the issuer. */ - $md = $this->metadata->getMetaData($this->issuer, 'saml20-idp-remote'); - - if(!array_key_exists('saml2.relaxvalidation', $md)) { - /* The user hasn't added a saml2.relaxvalidation option. */ - return FALSE; - } - - $rv = $md['saml2.relaxvalidation']; - if(!is_array($rv)) { - throw new Exception('saml2.relaxvalidation must be an array.'); - } - - return in_array($id, $rv, TRUE); - } - - - /** - * Retrieve the response status as an error object. - * - * @return sspmod_saml2_Error The status code of the response. - */ - public function getStatus() { - - $status = $this->doXPathQuery('/samlp:Response/samlp:Status')->item(0); - if ($status === NULL) { - throw new SimpleSAML_Error_Exception('Unable to determine the status of this SAML2 AuthnResponse message.: ' . $this->getXML()); - } - - $statusCode = $this->doXPathQuery('samlp:StatusCode', $status)->item(0); - if ($statusCode === NULL) { - throw new SimpleSAML_Error_Exception('Missing StatusCode element in Status element.'); - } - - $subStatus = $this->doXPathQuery('samlp:StatusCode', $statusCode)->item(0); - $message = $this->doXPathQuery('samlp:StatusMessage', $status)->item(0); - - $statusCode = $statusCode->getAttribute('Value'); - if ($subStatus !== NULL) { - $subStatus = $subStatus->getAttribute('Value'); - } - if ($message !== NULL) { - $message = SimpleSAML_Utilities::getDOMText($message); - } - - return new sspmod_saml2_Error($statusCode, $subStatus, $message); - } - - - /** - * This function finds the status of this response. - */ - public function findstatus() { - - $status = $this->doXPathQuery('/samlp:Response/samlp:Status/samlp:StatusCode')->item(0); - if($status != NULL) { - return $status->getAttribute('Value'); - } - throw new Exception('Unable to determine the status of this SAML2 AuthnResponse message.: ' . $this->getXML()); - } - - /** - * This function finds the issuer of this response. It will first search the Response element, - * and if it isn't found there, it will search all Assertion elements. - */ - public function findIssuer() { - - /* First check the Response element. */ - $issuer = $this->doXPathQuery('/samlp:Response/saml:Issuer')->item(0); - if($issuer !== NULL) { - return $issuer->textContent; - } - - /* Then we search the Assertion elements. */ - $issuers = $this->doXPathQuery('/samlp:Response/saml:Assertion/saml:Issuer'); - - if($issuers->length === 0) { - throw new Exception('Unable to determine the issuer of this SAML2 AuthnResponse message.'); - } - - /* Since all Issuer elements should be equal in this version of simpleSAMLphp, we pick - * the first Issuer element we find. - */ - return $issuers->item(0)->textContent; - } - - - /** - * This function decrypts the Assertion in the AuthnResponse - * It throws an exception if the encryptAssertion for the remote idp is true and - * the assertion is not encrypted - * To Do: handle multible assertions - */ - private function decryptAssertion() { - - $dom = $this->getDOM(); - $encryptedassertion = $this->doXPathQuery('/samlp:Response/saml:EncryptedAssertion')->item(0); - $objenc = new XMLSecEnc(); - $encData = $objenc->locateEncryptedData($dom); - if ($encData) { - $spmd = $this->metadata->getMetaDataCurrent('saml20-sp-hosted'); - $spid = $this->metadata->getMetaDataCurrentEntityID('saml20-sp-hosted'); - $objenc->setNode($encData); - $objenc->type = $encData->getAttribute("Type"); - - $key = NULL; - $objKey = $objenc->locateKey($encData); - if ($objKey) { - if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { - if ($objKeyInfo->isEncrypted) { - $objencKey = $objKeyInfo->encryptedCtx; - $privatekey = SimpleSAML_Utilities::loadPrivateKey($spmd, TRUE); - if(array_key_exists('password', $privatekey)) { - $objKeyInfo->passphrase = $privatekey['password']; - } - $objKeyInfo->loadKey($privatekey['PEM']); - $key = $objencKey->decryptKey($objKeyInfo); - } else { - $idpmd = $this->metadata->getMetaData($this->issuer, 'saml20-idp-remote'); - if (!isset( $idpmd['sharedkey'])) { - throw new Exception("Shared key for decrypting assertion needed, but not specified for saml20-idp-remote id: " . $this->issuer); - } - $key = $idpmd['sharedkey']; - } - } - } - - if (empty($objKey) || empty($key)) { - throw new Exception("Error loading key to handle Decryption: >" . var_export($objKey, true)); - } - $objKey->loadkey($key); - - $decrypted = $objenc->decryptNode($objKey, false); - - $newdoc = new DOMDocument(); - $newdoc->loadXML('<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'.$decrypted.'</root>'); - $importEnc = $encData->ownerDocument->importNode($newdoc->documentElement->firstChild, TRUE); - $encryptedassertion->parentNode->replaceChild($importEnc, $encryptedassertion); - } else { - $md = $this->metadata->getMetaData($this->issuer, 'saml20-idp-remote'); - if (isset($md['assertion.encryption']) && $md['assertion.encryption']) { - throw new Exception('Received unencrypted assertion from [' . $this->issuer . '] contrary to its metadata attribute [assertion.encryption]: ' . $md['assertion.encryption']); - } - } - } - - /** - * Validate the signature in the given node. - * - * The node should either be a samlp:Response node, or a saml:Assertion node. - * An exception will be thrown if an error occurs during validation. - * - * @param $node The node which contains the ds:Signature element. - */ - private function validateSignature($node) { - - /* Get the metadata of the issuer. */ - $md = $this->metadata->getMetaData($this->issuer, 'saml20-idp-remote'); - - /* Load public key / certificate / certificate fingerprints. */ - $publickey = SimpleSAML_Utilities::loadPublicKey($md); - - /* Validate the signature. */ - $this->validator = new SimpleSAML_XML_Validator($node, 'ID', $publickey); - - if (!$publickey) { - /* No validation of the certificate performed by the validator if $publickey isn't set. */ - if(array_key_exists('caFile', $md)) { - - /* Validation against a CA file. */ - $this->validator->validateCA($this->configuration->getPathValue('certdir') . $md['caFile']); - } else { - - /* Misconfigured - neither publickey, certFingerprint or caFile given. */ - throw new Exception('Misconfigured saml20-idp-remote ' . $this->issuer . ':' . - ' Neither publickey, certFingerprint or caFile given.'); - } - } - } - - - /** - * This function processes a Subject node. It will throw - * an Exception if the subject cannot be confirmed. On successful verification, - * the data stored about this subject will be saved. - */ - private function processSubject($subject) { - - /* We currently require urn:oasis:names:tc:SAML:2.0:cm:bearer subject confirmation. */ - $bearerValidated = false; - - /* Iterate over the SubjectConfirmation nodes, looking for it. */ - foreach($this->doXPathQuery('saml:SubjectConfirmation', $subject) as $subjectConfirmation) { - $method = $subjectConfirmation->getAttributeNode('Method'); - if($method === NULL) { - throw new Exception('SubjectConfirmation is missing the required Method attribute.'); - } - if($method->value !== 'urn:oasis:names:tc:SAML:2.0:cm:bearer') { - throw new Exception('Unhandled SubjectConfirmationData: ' . $method->value); - } - - foreach ($this->doXPathQuery('saml:SubjectConfirmationData', $subjectConfirmation) - as $subjectConfirmationData) { - - $recipient = $subjectConfirmationData->getAttributeNode('Recipient'); - if ($recipient !== NULL) { - /* The Recipient attribute contains the address this assertion should - * be delivered to. Verify that it matches the current address. - */ - $recipient = $recipient->value; - $currentURL = SimpleSAML_Utilities::selfURL(); - - if ($recipient !== $currentURL) { - throw new Exception('Recipient in assertion doesn\'t match the ' . - ' current URL. Recipient is "' . $recipient . - '", current URL is "' . $currentURL . '".'); - } - } - - /* TODO: Verify the rest of the subject. Missing are: - * - NotBefore & NotOnOrAfter - * - InResponseTo - * - Address - */ - } - } - - - /* We expect the subject node to contain a NameID element which identifies this subject. */ - $nameid = $this->doXPathQuery('saml:NameID', $subject)->item(0); - if($nameid === NULL) { - throw new Exception('Could not find the NameID node in a Subject node.'); - } - - $format = $nameid->getAttribute('Format'); - $value = $nameid->textContent; - - if($this->nameid === NULL) { - /* We haven't saved a nameID earlier. Save it now. */ - $this->nameid = array('Format' => $format, 'value' => $value); - return; - } - - /* We have saved a nameID earlier. Verify that this nameID is equal. */ - if($this->nameid['Format'] !== $format || $this->nameid['value'] !== $value) { - throw new Exception('Multiple assertions with different nameIDs is unsupported by simpleSAMLphp'); - } - } - - - /** - * This function processes a Conditions node. It will throw an exception if any of the conditions - * are invalid. - */ - private function processConditions($conditions) { - - /* First verify the NotBefore and NotOnOrAfter attributes if they are present. */ - $notBefore = $conditions->getAttribute("NotBefore"); - $notOnOrAfter = $conditions->getAttribute("NotOnOrAfter"); - if (! SimpleSAML_Utilities::checkDateConditions($notBefore, $notOnOrAfter)) { - throw new Exception('Date check failed (between ' . $notBefore . ' and ' . $notOnOrAfter . ').' . - ' Check if the clocks on the SP and IdP are synchronized. Alternatively' . - ' you can get this message, when you move back in history or refresh an old page.'); - } - - - if($this->doXPathQuery('Condition', $conditions)->length > 0) { - if(!$this->isValidationRelaxed('unknowncondition')) { - throw new Exception('A Conditions node in a SAML2 AuthnResponse contained a' . - ' Condition node. This is unsupported by simpleSAMLphp. To disable this' . - ' check, add \'unknowncondition\' to the \'saml2.relaxvalidation\' list in' . - ' \'saml2-idp-remote\'.'); - } - } - - - $spEntityId = $this->metadata->getMetaDataCurrentEntityID('saml20-sp-hosted'); - - /* The specification says that every AudienceRestriction element must be valid, but only one - * Audience element in each AudienceRestriction element must be valid. - */ - foreach($this->doXPathQuery('AudienceRestriction', $conditions) as $ar) { - - $validAudience = false; - foreach($this->doXPathQuery('Audience', $ar) as $a) { - if($a->textContent === $spEntityId) { - $validAudience = true; - } - } - if(!$validAudience) { - throw new Exception('Could not verify audience of SAML2 AuthnResponse.'); - } - } - - /* We ignore OneTimeUse and ProxyRestriction conditions. */ - } - - - /** - * This function processes a AuthnStatement node. It will throw an exception if the statement is - * invalid. - */ - private function processAuthnStatement($authnStatement) { - /* Extract the SessionIndex. */ - $sessionIndex = $authnStatement->getAttributeNode('SessionIndex'); - if($sessionIndex !== NULL) { - $sessionIndex = $sessionIndex->value; - if($this->sessionIndex === NULL) { - $this->sessionIndex = $sessionIndex; - } elseif($this->sessionIndex !== $sessionIndex) { - throw new Exception('Got two different session indexes in a SAML2 AuthnResponse.'); - } - } - } - - - /** - * This function processes a AttributeStatement node. - */ - private function processAttributeStatement($attributeStatement) { - - $md = $this->metadata->getMetadata($this->issuer, 'saml20-idp-remote'); - $base64 = isset($md['base64attributes']) ? $md['base64attributes'] : false; - - foreach($this->doXPathQuery('saml:Attribute/saml:AttributeValue', $attributeStatement) as $attribute) { - - $name = $attribute->parentNode->getAttribute('Name'); - $value = $attribute->textContent; - - if(!array_key_exists($name, $this->attributes)) { - $this->attributes[$name] = array(); - } - - if ($base64) { - - foreach(explode('_', $value) AS $v) { - $this->attributes[$name][] = base64_decode($v); - } - - } else { - $this->attributes[$name][] = $value; - } - } - } - - - /** - * This function processes a Assertion node. It will throw an exception if the assertion is invalid. - */ - private function processAssertion($assertion) { - - /* Make sure that the assertion is signed. */ - if(!$this->validator->isNodeValidated($assertion)) { - throw new Exception('A SAML2 AuthnResponse contained an Assertion which isn\'t verified by' . - ' the signature.'); - } - - $subject = $this->doXPathQuery('saml:Subject', $assertion)->item(0); - if($subject === NULL) { - if(!$this->isValidationRelaxed('nosubject')) { - throw new Exception('Could not find required Subject information in a SAML2' . - ' AuthnResponse. To disable this check, add \'nosubject\' to the' . - ' \'saml2.relaxvalidation\' list in \'saml2-idp-remote\'.'); - } - } else { - $this->processSubject($subject); - } - - $conditions = $this->doXPathQuery('saml:Conditions', $assertion)->item(0); - if($conditions === NULL) { - if(!$this->isValidationRelaxed('noconditions')) { - throw new Exception('Could not find required Conditions node in a SAML2' . - ' AuthnResponse. To disable this check, add \'noconditions\' to the' . - ' \'saml2.relaxvalidation\' list in \'saml2-idp-remote\'.'); - } - } else { - $this->processConditions($conditions); - } - - $authnStatement = $this->doXPathQuery('saml:AuthnStatement', $assertion)->item(0); - if($authnStatement === NULL) { - if(!$this->isValidationRelaxed('noauthnstatement')) { - throw new Exception('Could not find required AuthnStatement node in a SAML2' . - ' AuthnResponse. To disable this check, add \'noauthnstatement\' to the' . - ' \'saml2.relaxvalidation\' list in \'saml2-idp-remote\'.'); - } - } else { - $this->processAuthnStatement($authnStatement); - } - - $attributeStatement = $this->doXPathQuery('saml:AttributeStatement', $assertion)->item(0); - if($attributeStatement === NULL) { - if(!$this->isValidationRelaxed('noattributestatement')) { - throw new Exception('Could not find required AttributeStatement in a SAML2' . - ' AuthnResponse. To disable this check, add \'noattributestatement\' to the' . - ' \'saml2.relaxvalidation\' list in \'saml2-idp-remote\'.'); - } - } else { - $this->processAttributeStatement($attributeStatement); - } - } - - - /** - * This function processes a response message and adds information from it to the - * current session if it is valid. - * - * An exception will be thrown on a processing error. If the status code is something - * else than [...]:Success, FALSE will be returned, and no futher processing will occur. - * - * @return TRUE on success. FALSE on an error response. The SAML 2.0 status code can - * be retrieved with the findstatus() function. - */ - public function process() { - $status = $this->findstatus(); - if ($status == 'urn:oasis:names:tc:SAML:2.0:status:Success' ) { - /* Find the issuer of this response. */ - $this->issuer = $this->findIssuer(); - - /* Check for signature in the saml:Response-element, and validate it if present. */ - $signature = $this->doXPathQuery('/samlp:Response/ds:Signature'); - if($signature->length > 0) { - $this->validateSignature($signature->item(0)->parentNode); - } - - $this->decryptAssertion(); - - /* Check for signature in the saml:Assertion-element(s), and validate it if present. */ - $signature = $this->doXPathQuery('/samlp:Response/saml:Assertion/ds:Signature'); - if($signature->length > 0) { - $this->validateSignature($signature->item(0)->parentNode); - } - - /* Process all assertions. */ - $assertions = $this->doXPathQuery('/samlp:Response/saml:Assertion'); - foreach($assertions as $assertion) { - $this->processAssertion($assertion); - } - - if($this->nameid === NULL) { - throw new Exception('No nameID found in AuthnResponse.'); - } - - return TRUE; - } else { - /* A different status code. */ - return FALSE; - } - } - - - /** - * This function retrieves the ID of the request this response is a - * response to. This ID is stored in the InResponseTo attribute of the - * top level DOM element. - * - * @return The ID of the request this response is a response to, or NULL if - * we don't know. - */ - public function getInResponseTo() { - $dom = $this->getDOM(); - if($dom === NULL) { - return NULL; - } - - assert('$dom instanceof DOMDocument'); - - $xPath = new DOMXpath($dom); - $xPath->registerNamespace('samlp', self::SAML2_PROTOCOL_NS); - - $query = 'string(/samlp:Response/@InResponseTo)'; - $result = $xPath->evaluate($query); - if($result === '') { - return NULL; - } - - return $result; - } - - - /** - * Retrieve the attributes. - * - * This function should only be called after a successful call to the process-function. - * - * @return array The attributes. - */ - public function getAttributes() { - return $this->attributes; - } - - - /** - * Retrieve the NameID. - * - * The NameID will be returned as an associative array with two elements: - * - 'Format' The format of the NameID. - * - 'value' The valud of the NameID. - * - * This function should only be called after a successful call to the process-function. - * - * @return array The NameID. - */ - public function getNameID() { - assert('is_array($this->nameid)'); - assert('array_key_exists("Format", $this->nameid)'); - assert('array_key_exists("value", $this->nameid)'); - - return $this->nameid; - } - - - /** - * Retrieve the session index. - * - * This function retrieves the SessionIndex of this authentication response. - * - * This function should only be called after a successful call to the process-function. - * - * @return string The SessionIndex of this response. - */ - public function getSessionIndex() { - assert('is_string($this->sessionIndex)'); - - return $this->sessionIndex; - } - - - /** - * Retrieve the issuer. - * - * This function retrieves the Issuer of this authentication response. - * - * This function should only be called after a successful call to the process-function. - * - * @return string The entity id of the issuer of this response. - */ - public function getIssuer() { - assert('is_string($this->issuer)'); - - return $this->issuer; - } - - - /** - * This function generates an AuthenticationResponse - * - * @param $idpentityid entityid of IdP - * @param $spentityid entityid of SP - * @param $inresponseto the ID of the request, that these message is an response to. - * @param $nameid the NameID of the user (an array) - * @param $attributes A two level array of multivalued attributes, where the first level - * index is the attribute name. - * - * @return AuthenticationResponse as string - */ - public function generate($idpentityid, $spentityid, $inresponseto, $nameid, $attributes, $status = 'Success', $sessionDuration = 3600) { - - assert('is_string($status) || $status instanceof sspmod_saml2_Error'); - if (is_string($status)) { - if ($status === 'Success') { - /* Not really an error, but it makes the code simpler. */ - $status = new sspmod_saml2_Error(SAML2_Const::STATUS_SUCCESS); - } else { - $status = new sspmod_saml2_Error( - SAML2_Const::STATUS_RESPONDER, - 'urn:oasis:names:tc:SAML:2.0:status:' . $status - ); - } - } - - /** - * Retrieving metadata for the two specific entity IDs. - */ - $idpmd = $this->metadata->getMetaData($idpentityid, 'saml20-idp-hosted'); - $spmd = $this->metadata->getMetaData($spentityid, 'saml20-sp-remote'); - -# echo '<pre>'; print_r($idpmd); exit; - - $issuer = $idpentityid; - $destination = $spmd['AssertionConsumerService']; - - /** - * Generating IDs and timestamps. - */ - $id = SimpleSAML_Utilities::generateID(); - $issueInstant = SimpleSAML_Utilities::generateTimestamp(); - - // 30 seconds timeskew back in time to allow differing clocks. - $notBefore = SimpleSAML_Utilities::generateTimestamp(time() - 30); - // How long is the timeframe which which the consumer may consume the assertion - $assertionExpire = SimpleSAML_Utilities::generateTimestamp(time() + 60 * 5);# 5 minutes - // What is the max time frame which the consumer is allowed to hold a securtity context valid. - $sessionExpire = SimpleSAML_Utilities::generateTimestamp(time() + $sessionDuration); - - - - $assertionid = SimpleSAML_Utilities::generateID(); - - $session = SimpleSAML_Session::getInstance(); - $sessionindex = $session->getSessionIndex(); - - - /** - * Handling attributes. - */ - - $base64 = isset($spmd['base64attributes']) ? $spmd['base64attributes'] : false; - $nameidformat = isset($spmd['NameIDFormat']) ? $spmd['NameIDFormat'] : 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'; - $spnamequalifier = isset($spmd['SPNameQualifier']) ? $spmd['SPNameQualifier'] : $spmd['entityid']; - - // Attribute Name Format handling. Priority is 1) SP metadata 2) IdP metadata 3) default setting - $attributeNameFormat = 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic'; - if (isset($spmd['AttributeNameFormat'])) - $attributeNameFormat = $spmd['AttributeNameFormat']; - elseif (isset($idpmd['AttributeNameFormat'])) - $attributeNameFormat = $idpmd['AttributeNameFormat']; - - $sendattributes = isset($spmd['simplesaml.attributes']) ? $spmd['simplesaml.attributes'] : true; - $attributestatement = ''; - if ($sendattributes && !is_null($attributes)) { - $encodings = self::getAttributeEncodings($spmd, $attributes); - $encodedattributes = ''; - foreach ($attributes AS $name => $values) { - $encodedattributes .= self::enc_attribute($name, $values, $encodings, $attributeNameFormat); - } - $attributestatement = '<saml:AttributeStatement>' . $encodedattributes . '</saml:AttributeStatement>'; - } - - - - /** - * Handling NameID - */ - $nameIdValue = self::getNameIDValue($nameidformat, $idpmd, $spmd, $attributes); - - if (!empty($nameIdValue)) { - $nameIdData = array('Format' => $nameidformat, 'value' => $nameIdValue); - $session->setSessionNameId('saml20-sp-remote', $spentityid, $nameIdData); - $nameid = $this->generateNameID($nameidformat, $nameIdValue, $spnamequalifier); - } else { - $nameid = ''; - } - - - $inresponsetoText = ''; - if (!empty($inresponseto)) $inresponsetoText = 'InResponseTo="' . htmlspecialchars($inresponseto). '" '; - - $assertion = ""; - if ($status->getStatus() === SAML2_Const::STATUS_SUCCESS) { - $assertion = '<saml:Assertion Version="2.0" - ID="' . $assertionid . '" IssueInstant="' . $issueInstant . '"> - <saml:Issuer>' . htmlspecialchars($issuer) . '</saml:Issuer> - <saml:Subject> - ' . $nameid . ' - <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> - <saml:SubjectConfirmationData NotOnOrAfter="' . $assertionExpire . '" - ' . $inresponsetoText . ' - Recipient="' . htmlspecialchars($destination) . '"/> - </saml:SubjectConfirmation> - </saml:Subject> - <saml:Conditions NotBefore="' . $notBefore. '" NotOnOrAfter="' . $sessionExpire. '"> - <saml:AudienceRestriction> - <saml:Audience>' . htmlspecialchars($spentityid) . '</saml:Audience> - </saml:AudienceRestriction> - </saml:Conditions> - <saml:AuthnStatement AuthnInstant="' . $issueInstant . '" - SessionIndex="' . htmlspecialchars($sessionindex) . '"> - <saml:AuthnContext> - <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> - </saml:AuthnContext> - </saml:AuthnStatement> - ' . $attributestatement. ' - </saml:Assertion>'; - } - $statusElement = self::generateStatus($status); - - /** - * Generating the response. - */ - $authnResponse = '<samlp:Response - xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" - xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" - xmlns:xs="http://www.w3.org/2001/XMLSchema" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - ID="' . $id . '" - ' . $inresponsetoText . ' Version="2.0" - IssueInstant="' . $issueInstant . '" - Destination="' . htmlspecialchars($destination) . '"> - <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . htmlspecialchars($issuer) . '</saml:Issuer> - ' . $statusElement . $assertion . - '</samlp:Response>'; - - return $authnResponse; - } - - - private static function getAttributeEncodings($spmd, $attributes) { - $defaultEnc = 'string'; - if (isset($spmd['base64attributes']) && $spmd['base64attributes']) { - $defaultEnc = 'base64'; - } - if (isset($spmd['base64attributes']) || !isset($spmd['attributeencodings'])) { - $enc = array(); - foreach ($attributes AS $name => $values) { - $enc[$name] = $defaultEnc; - } - return $enc; - } elseif (isset($spmd['attributeencodings'])) { - $enc = array(); - foreach ($attributes AS $name => $values) { - if (isset($spmd['attributeencodings'][$name])) { - $enc[$name] = $spmd['attributeencodings'][$name]; - } else { - $enc[$name] = $defaultEnc; - } - } - return $enc; - } - } - - - private function generateNameID($type = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient', - $value = 'anonymous', $spnamequalifier = null) { - - $spnamequalifiertext = ''; - if (!empty($spnamequalifier)) { - $spnamequalifiertext = ' SPNameQualifier="' . htmlspecialchars($spnamequalifier) . '"'; - } - - if ($value == null) { - throw new Exception("NameID value is empty probably because of a configuration error (ie. the attribute that was configured as the simplesaml.nameidattribute setting was not found)."); - } - - if ($type == self::EMAIL) { - return '<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"' . - $spnamequalifiertext . '>' . htmlspecialchars($value) . '</saml:NameID>'; - - } else { - return '<saml:NameID Format="' . $type . '"' . - $spnamequalifiertext. '>' . htmlspecialchars($value). '</saml:NameID>'; - } - - } - - - /** - * Retrieve/generate NameID value. - * - * This function attempts to find the value which should be used for the NameID attribute. - * - * @param string $format NameID format. - * @param array $idpmd Service provider metadata. - * @param array $spmd Service provider metadata. - * @param array|NULL $attributes The attributes of the user. - * @return string|NULL NameID value, or NULL if we are unable to generate a value. - */ - private static function getNameIDValue($format, $idpmd, $spmd, $attributes) { - assert('is_string($format)'); - assert('is_array($idpmd)'); - assert('is_array($spmd)'); - assert('is_null($attributes) || is_array($attributes)'); - - if ($format === self::TRANSIENT) { - return SimpleSAML_Utilities::generateID(); - } - - if (is_null($attributes)) { - SimpleSAML_Logger::warning('Unable to generate NameID Value without attributes.'); - return NULL; - } - - - $attribute = NULL; - - if (array_key_exists('simplesaml.nameidattribute', $idpmd)) { - $attribute = $idpmd['simplesaml.nameidattribute']; - } elseif (array_key_exists('simplesaml.nameidattribute', $spmd)) { - $attribute = $spmd['simplesaml.nameidattribute']; - } else { - SimpleSAML_Logger::error('simplesaml.nameidattribute not set in either SP metadata or IdP metadata'); - return NULL; - } - - if (!array_key_exists($attribute, $attributes)) { - SimpleSAML_Logger::error('Unable to add NameID: Missing ' . var_export($attribute, TRUE) . - ' in the attributes of the user.'); - return NULL; - } - - return $attributes[$spmd['simplesaml.nameidattribute']][0]; - } - - - /** - * This function converts an array of attribute values into an - * encoded saml:Attribute element which should go into the - * AuthnResponse. The data can optionally be base64 encoded. - * - * @param $name Name of this attribute. - * @param $values Array with the values of this attribute. - * @param $base64 Enable base64 encoding of attribute values. - * @param $attributeNameFormat Which attribute name format to use. (See SAML 2.0 Spec for details) - * - * @return String containing the encoded saml:attribute value for this - * attribute. - */ - private static function enc_attribute($name, $values, $encodings, $attributeNameFormat) { - assert(is_array($values)); - - // Default: urn:oasis:names:tc:SAML:2.0:attrname-format:basic - $ret = '<saml:Attribute NameFormat="' . htmlspecialchars($attributeNameFormat) . '" Name="' . htmlspecialchars($name) . '">'; - - foreach($values as $value) { - $xsiType = ''; - switch ($encodings[$name]) { - case 'string': - $text = htmlspecialchars($value); - $xsiType = ' xsi:type="xs:string"'; - break; - case 'base64': - $text = base64_encode($value); - $xsiType = ' xsi:type="xs:string"'; - break; - case 'raw': - $text = $value; - break; - default: - throw new Exception("Unknown encoding for attribute $name: $encodings[$name]"); - } - - $ret .= '<saml:AttributeValue' . $xsiType . '>' . $text . '</saml:AttributeValue>'; - } - - $ret .= '</saml:Attribute>'; - - return $ret; - } - - - /** - * Generate a SAML 2 StatusCode element from an instance of sspmod_saml2_Error. - * - * @param sspmod_saml2_Error $status The status code. - * @return string The StatusCode element. - */ - private static function generateStatus(sspmod_saml2_Error $status) { - - $statusElement = '<samlp:Status>'; - $statusElement .= '<samlp:StatusCode Value="' . htmlspecialchars($status->getStatus()) . '">'; - if ($status->getSubStatus() !== NULL) { - $statusElement .= '<samlp:StatusCode Value="' . htmlspecialchars($status->getSubstatus()) . '"/>'; - } - $statusElement .= '</samlp:StatusCode>'; - if ($status->getStatusMessage() !== NULL) { - $statusElement .= '<samlp:StatusMessage>' . htmlspecialchars($status->getStatusMessage()) . '</samlp:StatusMessage>'; - } - $statusElement .= '</samlp:Status>'; - - return $statusElement; - } - -} - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/XML/SAML20/LogoutRequest.php b/lib/SimpleSAML/XML/SAML20/LogoutRequest.php deleted file mode 100644 index 629b03d000f34f5492a4ace5d28da61221a59a99..0000000000000000000000000000000000000000 --- a/lib/SimpleSAML/XML/SAML20/LogoutRequest.php +++ /dev/null @@ -1,167 +0,0 @@ -<?php - -/** - * Implementation of the SAML 2.0 LogoutRequest message. - * - * @author Andreas Ĺkre Solberg, UNINETT AS. <andreas.solberg@uninett.no> - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_XML_SAML20_LogoutRequest { - - private $configuration = null; - private $metadata = null; - - private $message = null; - private $dom; - private $relayState = null; - - - const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0'; - - - /** - * This variable holds the generated request id for this request. - */ - private $id = null; - - - function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore) { - $this->configuration = $configuration; - $this->metadata = $metadatastore; - - /* Generate request id. */ - $this->id = SimpleSAML_Utilities::generateID(); - } - - public function setXML($xml) { - $this->message = $xml; - } - - public function getXML() { - return $this->message; - } - - public function setRelayState($relayState) { - $this->relayState = $relayState; - } - - public function getRelayState() { - return $this->relayState; - } - - public function getDOM() { - if (isset($this->message) ) { - - /* if (isset($this->dom) && $this->dom != null ) { - return $this->dom; - } */ - - $token = new DOMDocument(); - $token->loadXML(str_replace ("\r", "", $this->message)); - if (empty($token)) { - throw new Exception("Unable to load token"); - } - $this->dom = $token; - return $this->dom; - - } - - return null; - } - - - public function getIssuer() { - $dom = $this->getDOM(); - $issuer = null; - - if (!$dom instanceof DOMDocument) { - throw new Exception("Could not get message DOM in AuthnRequest object"); - } - - //print_r($dom->saveXML()); - - if ($issuerNodes = $dom->getElementsByTagName('Issuer')) { - if ($issuerNodes->length > 0) { - $issuer = $issuerNodes->item(0)->textContent; - } - } - return $issuer; - } - - public function getRequestID() { - $dom = $this->getDOM(); - $requestid = null; - - if (empty($dom)) { - throw new Exception("Could not get message DOM in AuthnRequest object"); - } - - $requestelement = $dom->getElementsByTagName('LogoutRequest')->item(0); - $requestid = $requestelement->getAttribute('ID'); - return $requestid; - /* - if ($issuerNodes = $dom->getElementsByTagName('Issuer')) { - if ($issuerNodes->length > 0) { - $requestid = $issuerNodes->item(0)->textContent; - } - } - return $requestid; - */ - } - - - - public function generate($issuer, $receiver, $nameid, $sessionindex, $mode) { - - if (!in_array($mode, array('SP', 'IdP'))) { - throw new Exception('mode parameter of generate() must be either SP or IdP'); - } - if ($mode == 'IdP') { - $issuerset = 'saml20-idp-hosted'; - $receiverset = 'saml20-sp-remote'; - } else { - $issuerset = 'saml20-sp-hosted'; - $receiverset = 'saml20-idp-remote'; - } - - $issuermd = $this->metadata->getMetaData($issuer, $issuerset); - $receivermd = $this->metadata->getMetaData($receiver, $receiverset); - - if ($mode == 'IdP') { - $spnamequalifier = isset($receivermd['SPNameQualifier']) ? $receivermd['SPNameQualifier'] : $receivermd['entityid']; - } else { - $spnamequalifier = isset($issuermd['SPNameQualifier']) ? $issuermd['SPNameQualifier'] : $issuermd['entityid']; - } - - $issueInstant = SimpleSAML_Utilities::generateTimestamp(); - - $destination = $receivermd['SingleLogoutService']; - - $logoutRequest = '<samlp:LogoutRequest - xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" - xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" - ID="' . $this->id . '" Version="2.0" - Destination="' . htmlspecialchars($destination) . '" - IssueInstant="' . $issueInstant . '"> - <saml:Issuer >' . htmlspecialchars($issuer) . '</saml:Issuer> - <saml:NameID Format="' . htmlspecialchars($nameid['Format']) . '" SPNameQualifier="' . htmlspecialchars($spnamequalifier) . '">' . htmlspecialchars($nameid['value']) . '</saml:NameID> - <samlp:SessionIndex>' . htmlspecialchars($sessionindex) . '</samlp:SessionIndex> -</samlp:LogoutRequest> -'; - - return $logoutRequest; - } - - /** - * This function retrieves the request id we used for the generated logout request. - * - * @return The request id of the generated logout request. - */ - public function getGeneratedID() { - return $this->id; - } - -} - -?> \ No newline at end of file diff --git a/lib/SimpleSAML/XML/SAML20/LogoutResponse.php b/lib/SimpleSAML/XML/SAML20/LogoutResponse.php deleted file mode 100644 index 0ce4586c7e5267ade2f3eb307f2803115b59acc1..0000000000000000000000000000000000000000 --- a/lib/SimpleSAML/XML/SAML20/LogoutResponse.php +++ /dev/null @@ -1,144 +0,0 @@ -<?php - -/** - * Implementation of the SAML 2.0 LogoutResponse message. - * - * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no> - * @package simpleSAMLphp - * @version $Id$ - */ -class SimpleSAML_XML_SAML20_LogoutResponse { - - private $configuration = null; - private $metadata = null; - - private $message = null; - private $dom; - private $relayState = null; - - const PROTOCOL = 'urn:oasis:names:tc:SAML:2.0'; - - function __construct(SimpleSAML_Configuration $configuration, SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore) { - $this->configuration = $configuration; - $this->metadata = $metadatastore; - } - - public function setXML($xml) { - $this->message = $xml; - } - - public function getXML() { - return $this->message; - } - - public function setRelayState($relayState) { - $this->relayState = $relayState; - } - - public function getRelayState() { - return $this->relayState; - } - - public function getDOM() { - if (isset($this->message) ) { - - /* - if (isset($this->dom)) { - return $this->dom; - } - */ - - $token = new DOMDocument(); - $token->loadXML(str_replace ("\r", "", $this->message)); - if (empty($token)) { - throw new Exception("Unable to load token"); - } - $this->dom = $token; - return $this->dom; - - } - - return null; - } - - - - public function getIssuer() { - $dom = $this->getDOM(); - $issuer = null; - if ($issuerNodes = $dom->getElementsByTagName('Issuer')) { - if ($issuerNodes->length > 0) { - $issuer = $issuerNodes->item(0)->textContent; - } - } - return $issuer; - } - - - /** - * This function retrieves the InResponseTo attribute value from the logout response. - * - * @return The InResponseTo attribute value from the logout response. - */ - public function getInResponseTo() { - $dom = $this->getDOM(); - - $responseElement = $dom->getElementsByTagName('LogoutResponse')->item(0); - $inResponseTo = $responseElement->getAttribute('InResponseTo'); - - if(empty($inResponseTo)) { - throw new Exception('Empty InResponseTo attribute on SAML2 logout response.'); - } - - return $inResponseTo; - } - - - // Not updated for response. from request. - public function generate($issuer, $receiver, $inresponseto, $mode ) { - if (!in_array($mode, array('SP', 'IdP'))) { - throw new Exception('mode parameter of generate() must be either SP or IdP'); - } - if ($mode == 'IdP') { - $issuerset = 'saml20-idp-hosted'; - $receiverset = 'saml20-sp-remote'; - } else { - $issuerset = 'saml20-sp-hosted'; - $receiverset = 'saml20-idp-remote'; - } - - - //echo 'idp:' . $idpentityid . ' sp:' . $spentityid .' inresponseto:' . $inresponseto . ' namid:' . $nameid; - - $issuermd = $this->metadata->getMetaData($issuer, $issuerset); - $receivermd = $this->metadata->getMetaData($receiver, $receiverset); - - $id = SimpleSAML_Utilities::generateID(); - $issueInstant = SimpleSAML_Utilities::generateTimestamp(); - - $destination = $receivermd['SingleLogoutService']; - if (isset($receivermd['SingleLogoutServiceResponse'])) { - $destination = $receivermd['SingleLogoutServiceResponse']; - } - - $samlResponse = '<samlp:LogoutResponse - xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" - xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" - ID="' . $id . '" Version="2.0" - IssueInstant="' . $issueInstant . '" - Destination="'. htmlspecialchars($destination). '" - InResponseTo="' . htmlspecialchars($inresponseto) . '"> - <saml:Issuer>' . htmlspecialchars($issuer) . '</saml:Issuer> - <samlp:Status> - <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"> </samlp:StatusCode> - <samlp:StatusMessage>Successfully logged out from service ' . htmlspecialchars($issuer) . '</samlp:StatusMessage> - </samlp:Status> -</samlp:LogoutResponse> -'; - - return $samlResponse; - } - -} - -?> \ No newline at end of file