From a3ff374f9470520c0c9ac7ba2ae5db485417d626 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Fri, 15 Jan 2010 10:10:50 +0000 Subject: [PATCH] Add support for sending responses with the HTTP-Artifact binding. This patch implements support for sending responses to authentication requests via the HTTP-Artifact binding. To enable, add 'saml20.sendartifact' => TRUE in saml20-idp-hosted metadata. The IdP should then send HTTP-Artifact responses to SPs that request it. Note that this requires a working memcache server. Thanks to Danny Bollaert for implementing support for this. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2121 44740490-163a-0410-bde0-09ae8108e29a --- docs/simplesamlphp-reference-idp-hosted.txt | 6 ++ lib/SAML2/ArtifactResolve.php | 62 ++++++++++++++++++ lib/SAML2/ArtifactResponse.php | 69 +++++++++++++++++++++ lib/SAML2/Binding.php | 6 ++ lib/SAML2/Const.php | 10 +++ lib/SAML2/HTTPArtifact.php | 64 +++++++++++++++++++ lib/SAML2/Message.php | 4 ++ lib/SAML2/SOAP.php | 55 ++++++++++++++++ lib/SAML2/Utils.php | 1 + lib/SimpleSAML/Configuration.php | 2 + lib/SimpleSAML/Metadata/SAMLBuilder.php | 4 ++ modules/saml/lib/IdP/SAML2.php | 50 +++++++++++++-- www/saml2/idp/ArtifactResolutionService.php | 42 +++++++++++++ www/saml2/idp/metadata.php | 31 +++++---- 14 files changed, 390 insertions(+), 16 deletions(-) create mode 100644 lib/SAML2/ArtifactResolve.php create mode 100644 lib/SAML2/ArtifactResponse.php create mode 100644 lib/SAML2/HTTPArtifact.php create mode 100644 lib/SAML2/SOAP.php create mode 100644 www/saml2/idp/ArtifactResolutionService.php diff --git a/docs/simplesamlphp-reference-idp-hosted.txt b/docs/simplesamlphp-reference-idp-hosted.txt index 7d904a710..1c1973808 100644 --- a/docs/simplesamlphp-reference-idp-hosted.txt +++ b/docs/simplesamlphp-reference-idp-hosted.txt @@ -143,6 +143,12 @@ The following SAML 2.0 options are available: configure your webserver to deliver this URL to the correct PHP page. +`saml20.sendartifact` +: Set to `TRUE` to enable the IdP to send responses with the HTTP-Artifact binding. + Defaults to `FALSE`. + +: Note that this requires a configured memcache server. + `saml20.sign.response` : Whether `<samlp:Response> messages should be signed. Defaults to `TRUE`. diff --git a/lib/SAML2/ArtifactResolve.php b/lib/SAML2/ArtifactResolve.php new file mode 100644 index 000000000..c7de093ba --- /dev/null +++ b/lib/SAML2/ArtifactResolve.php @@ -0,0 +1,62 @@ +<?php +/** + * The Artifact is part of the SAML 2.0 IdP code, and it builds an artifact object. + * I am using strings, because I find them easier to work with. + * I want to use this, to be consistent with the other saml2_requests + * + * @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be> + * @package simpleSAMLphp + * @version $Id$ + */ +class SAML2_ArtifactResolve extends SAML2_Request { + + + private $artifact; + + + + public function __construct(DOMElement $xml = NULL) { + parent::__construct('ArtifactResolve', $xml); + + if(!is_null($xml)){ + $results = SAML2_Utils::xpQuery($xml, './saml_protocol:Artifact'); + $this->artifact = $results[0]->textContent; + } + + } + + + /** + * Retrieve the Artifact in this response. + * + * @return string artifact. + */ + public function getArtifact() { + return $this->artifact; + } + + + /** + * Set the artifact that should be included in this response. + * + * @param String The $artifact. + */ + public function setArtifact($artifact) { + + $this->artifact = $artifact; + } + + /** + * Convert the response message to an XML element. + * + * @return DOMElement This response. + */ + public function toUnsignedXML() { + + throw new Exception('Not SUPPORTED'); + } + + + + +} diff --git a/lib/SAML2/ArtifactResponse.php b/lib/SAML2/ArtifactResponse.php new file mode 100644 index 000000000..7d4fe5e90 --- /dev/null +++ b/lib/SAML2/ArtifactResponse.php @@ -0,0 +1,69 @@ +<?php + +/** + * The SAML2_ArtifactResponse, is the response to the SAML2_ArtifactResolve. + * + * @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be> + * @package simpleSAMLphp + * @version $Id$ + */ +class SAML2_ArtifactResponse extends SAML2_StatusResponse { + + + /** + * @var any contains saml2message XML + */ + private $any; + + + public function __construct(DOMElement $xml = NULL) { + parent::__construct('ArtifactResponse', $xml); + + if(!is_null($xml)){ + + $status = SAML2_Utils::xpQuery($xml, './saml_protocol:Status'); + assert('!empty($status)'); /* Will have failed during StatusResponse parsing. */ + + $status = $status[0]; + + for ($any = $status->nextSibling; $any !== NULL; $any = $any->nextSibling) { + if ($any instanceof DOMElement) { + $this->any = $any; + break; + } + /* Ignore comments and text nodes. */ + } + } + + } + + + public function setAny(DOMElement $any) { + assert('!is_null($any)'); + $this->any = $any; + } + + + public function getAny() { + return $this->any; + } + + + /** + * Convert the response message to an XML element. + * + * @return DOMElement This response. + */ + public function toUnsignedXML() { + + $root = parent::toUnsignedXML(); + if (isset($this->any)) { + $node = $root->ownerDocument->importNode($this->any, TRUE); + $root->appendChild($node); + + } + + return $root; + } + +} diff --git a/lib/SAML2/Binding.php b/lib/SAML2/Binding.php index 0dc960c42..50fd2ccde 100644 --- a/lib/SAML2/Binding.php +++ b/lib/SAML2/Binding.php @@ -32,6 +32,8 @@ abstract class SAML2_Binding { return new SAML2_HTTPPost(); case SAML2_Const::BINDING_HTTP_REDIRECT: return new SAML2_HTTPRedirect(); + case SAML2_Const::BINDING_HTTP_ARTIFACT: + return new SAML2_HTTPArtifact(); default: throw new Exception('Unsupported binding: ' . var_export($urn, TRUE)); } @@ -53,12 +55,16 @@ abstract class SAML2_Binding { case 'GET': if (array_key_exists('SAMLRequest', $_REQUEST) || array_key_exists('SAMLResponse', $_REQUEST)) { return new SAML2_HTTPRedirect(); + } elseif (array_key_exists('SAMLart', $_REQUEST) ){ + return new SAML2_HTTPArtifact(); } break; case 'POST': if (array_key_exists('SAMLRequest', $_REQUEST) || array_key_exists('SAMLResponse', $_REQUEST)) { return new SAML2_HTTPPost(); + } elseif (array_key_exits('CONTENT_TYPE', $_SERVER) && $_SERVER['CONTENT_TYPE'] === 'text/xml'){ + return new SAML2_SOAP(); } break; } diff --git a/lib/SAML2/Const.php b/lib/SAML2/Const.php index 6f1494e69..79f03a642 100644 --- a/lib/SAML2/Const.php +++ b/lib/SAML2/Const.php @@ -29,6 +29,11 @@ class SAML2_Const { */ const BINDING_HTTP_REDIRECT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'; + /** + * The URN for the HTTP-ARTIFACT binding. + */ + const BINDING_HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'; + /** * The URN for the SOAP binding. */ @@ -68,6 +73,11 @@ class SAML2_Const { const NAMEID_ENCRYPTED = 'urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted'; + /** + * The namespace for the SOAP protocol. + */ + const NS_SOAP = 'http://schemas.xmlsoap.org/soap/envelope/'; + /** * The namespace for the SAML 2 protocol. */ diff --git a/lib/SAML2/HTTPArtifact.php b/lib/SAML2/HTTPArtifact.php new file mode 100644 index 000000000..0251a69ea --- /dev/null +++ b/lib/SAML2/HTTPArtifact.php @@ -0,0 +1,64 @@ +<?php + + +/** + * Class which implements the HTTP-Redirect binding. + * + * @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be> + * @package simpleSAMLphp + * @version $Id$ + */ +class SAML2_HTTPArtifact extends SAML2_Binding { + + /** + * Create the redirect URL for a message. + * + * @param SAML2_Message $message The message. + * @return string The URL the user should be redirected to in order to send a message. + */ + public function getRedirectURL(SAML2_Message $message) { + + $generatedId = pack('H*', ((string) SimpleSAML_Utilities::stringToHex(SimpleSAML_Utilities::generateRandomBytes(20)))); + $artifact = base64_encode("\x00\x04\x00\x00" . sha1($message->getIssuer(), TRUE) . $generatedId) ; + $artifactData = $message->toUnsignedXML(); + $artifactDataString = $artifactData->ownerDocument->saveXML($artifactData); + SimpleSAML_Memcache::set('artifact:' . $artifact, $artifactDataString); + $params = array( + 'SAMLart' => $artifact, + ); + $relayState = $message->getRelayState(); + if ($relayState !== NULL) { + $params['RelayState'] = $relayState; + } + + return SimpleSAML_Utilities::addURLparameter($message->getDestination(), $params); + } + + + /** + * Send a SAML 2 message using the HTTP-Redirect binding. + * + * Note: This function never returns. + * + * @param SAML2_Message $message The message we should send. + */ + public function send(SAML2_Message $message) { + + $destination = $this->getRedirectURL($message); + SimpleSAML_Utilities::redirect($destination); + } + + + /** + * Receive a SAMLart. + * + * Throws an exception if it is unable receive the message. + * + * @return SAML2_Message The received message. + */ + public function receive() { + + throw new Exception('Receiving SAML2 Artifact messages not supported.'); + } + +} diff --git a/lib/SAML2/Message.php b/lib/SAML2/Message.php index b54087eca..f17e89826 100644 --- a/lib/SAML2/Message.php +++ b/lib/SAML2/Message.php @@ -471,6 +471,10 @@ abstract class SAML2_Message implements SAML2_SignedElement { return new SAML2_LogoutRequest($xml); case 'Response': return new SAML2_Response($xml); + case 'ArtifactResponse': + return new SAML2_ArtifactResponse($xml); + case 'ArtifactResolve': + return new SAML2_ArtifactResolve($xml); default: throw new Exception('Unknown SAML message: ' . var_export($xml->localName, TRUE)); } diff --git a/lib/SAML2/SOAP.php b/lib/SAML2/SOAP.php new file mode 100644 index 000000000..00c46fa64 --- /dev/null +++ b/lib/SAML2/SOAP.php @@ -0,0 +1,55 @@ +<?php + +/** + * Class which implements the SOAP binding. + * + * @package simpleSAMLphp + * @version $Id$ + */ +class SAML2_SOAP extends SAML2_Binding { + + /** + * Send a SAML 2 message using the SOAP binding. + * + * Note: This function never returns. + * + * @param SAML2_Message $message The message we should send. + */ + public function send(SAML2_Message $message) { + header('Content-Type: text/xml',true); + $outputFromIdp = '<?xml version="1.0" encoding="UTF-8"?>'; + $outputFromIdp .= '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'; + $outputFromIdp .= '<SOAP-ENV:Body>'; + $xmlMessage = $message->toUnsignedXML(); + $tempOutputFromIdp = $xmlMessage->ownerDocument->saveXML($xmlMessage); + $outputFromIdp .= $tempOutputFromIdp; + $outputFromIdp .= '</SOAP-ENV:Body>'; + $outputFromIdp .= '</SOAP-ENV:Envelope>'; + print($outputFromIdp); + exit(0); + } + + + /** + * Receive a SAML 2 message sent using the HTTP-POST binding. + * + * Throws an exception if it is unable receive the message. + * + * @return SAML2_Message The received message. + */ + public function receive() { + + $postText = file_get_contents('php://input'); + + if(empty($postText)){ + throw new SimpleSAML_Error_BadRequest('Invalid message received to AssertionConsumerService endpoint.'); + } + + $document = new DOMDocument(); + $document->loadXML($postText); + $xml = $document->firstChild; + $results = SAML2_Utils::xpQuery($xml, '/soap-env:Envelope/soap-env:Body/*[1]'); + return SAML2_Message::fromXML($results[0]); + } + +} diff --git a/lib/SAML2/Utils.php b/lib/SAML2/Utils.php index 7f1aaa63d..5a5df7466 100644 --- a/lib/SAML2/Utils.php +++ b/lib/SAML2/Utils.php @@ -115,6 +115,7 @@ class SAML2_Utils { if ($xpCache === NULL || !$xpCache->document->isSameNode($node->ownerDocument)) { $xpCache = new DOMXPath($node->ownerDocument); + $xpCache->registerNamespace('soap-env', SAML2_Const::NS_SOAP); $xpCache->registerNamespace('saml_protocol', SAML2_Const::NS_SAMLP); $xpCache->registerNamespace('saml_assertion', SAML2_Const::NS_SAML); $xpCache->registerNamespace('ds', XMLSecurityDSig::XMLDSIGNS); diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php index a388fc7c0..ba36047a9 100644 --- a/lib/SimpleSAML/Configuration.php +++ b/lib/SimpleSAML/Configuration.php @@ -860,6 +860,8 @@ class SimpleSAML_Configuration { return SAML2_Const::BINDING_HTTP_REDIRECT; case 'saml20-sp-remote:AssertionConsumerService': return SAML2_Const::BINDING_HTTP_POST; + case 'saml20-idp-remote:ArtifactResolutionService': + return SAML2_Const::BINDING_SOAP; case 'shib13-idp-remote:SingleSignOnService': return 'urn:mace:shibboleth:1.0:profiles:AuthnRequest'; case 'shib13-sp-remote:AssertionConsumerService': diff --git a/lib/SimpleSAML/Metadata/SAMLBuilder.php b/lib/SimpleSAML/Metadata/SAMLBuilder.php index 5a274e6b6..70dfd6111 100644 --- a/lib/SimpleSAML/Metadata/SAMLBuilder.php +++ b/lib/SimpleSAML/Metadata/SAMLBuilder.php @@ -396,6 +396,10 @@ class SimpleSAML_Metadata_SAMLBuilder { $e->appendChild($t); } + if ($metadata->hasValue('ArtifactResolutionService')){ + $this->addEndpoints($e, 'ArtifactResolutionService', $metadata->getEndpoints('ArtifactResolutionService')); + } + $this->addEndpoints($e, 'SingleSignOnService', $metadata->getEndpoints('SingleSignOnService')); $this->entityDescriptor->appendChild($e); diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php index 8fd3bfeea..746bf94e3 100644 --- a/modules/saml/lib/IdP/SAML2.php +++ b/modules/saml/lib/IdP/SAML2.php @@ -32,6 +32,16 @@ class sspmod_saml_IdP_SAML2 { $relayState = $state['saml:RelayState']; $consumerURL = $state['saml:ConsumerURL']; + if (isset($state['saml:Binding'])) { + $protocolBinding = $state['saml:Binding']; + } else { + /* + * To allow for upgrading while people are logging in. + * Should be removed in 1.7. + */ + $protocolBinding = SAML2_Const::BINDING_HTTP_POST; + } + $idp = SimpleSAML_IdP::getByState($state); $idpMetadata = $idp->getConfig(); @@ -56,7 +66,7 @@ class sspmod_saml_IdP_SAML2 { $session->setSessionNameId('saml20-sp-remote', $spEntityId, $nameId); /* Send the response. */ - $binding = new SAML2_HTTPPost(); + $binding = SAML2_Binding::getBinding($protocolBinding); $binding->setDestination(sspmod_SAML2_Message::getDebugDestination()); $binding->send($ar); } @@ -83,6 +93,16 @@ class sspmod_saml_IdP_SAML2 { $relayState = $state['saml:RelayState']; $consumerURL = $state['saml:ConsumerURL']; + if (isset($state['saml:Binding'])) { + $protocolBinding = $state['saml:Binding']; + } else { + /* + * To allow for upgrading while people are logging in. + * Should be removed in 1.7. + */ + $protocolBinding = SAML2_Const::BINDING_HTTP_POST; + } + $idp = SimpleSAML_IdP::getByState($state); $idpMetadata = $idp->getConfig(); @@ -102,7 +122,7 @@ class sspmod_saml_IdP_SAML2 { 'Message' => $error->getStatusMessage(), )); - $binding = new SAML2_HTTPPost(); + $binding = SAML2_Binding::getBinding($protocolBinding); $binding->setDestination(sspmod_SAML2_Message::getDebugDestination()); $binding->send($ar); } @@ -118,6 +138,11 @@ class sspmod_saml_IdP_SAML2 { $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $idpMetadata = $idp->getConfig(); + $supportedBindings = array(SAML2_Const::BINDING_HTTP_POST); + if ($idpMetadata->getBoolean('saml20.sendartifact', FALSE)) { + $supportedBindings[] = SAML2_Const::BINDING_HTTP_ARTIFACT; + } + if (isset($_REQUEST['spentityid'])) { /* IdP initiated authentication. */ @@ -141,6 +166,11 @@ class sspmod_saml_IdP_SAML2 { $relayState = NULL; } + if (isset($_REQUEST['binding'])){ + $protocolBinding = (string)$_REQUEST['binding']; + } else { + $protocolBinding = NULL; + } $requestId = NULL; $IDPList = array(); $forceAuthn = FALSE; @@ -171,6 +201,7 @@ class sspmod_saml_IdP_SAML2 { $requestId = $requestCache['RequestID']; $forceAuthn = $requestCache['ForceAuthn']; $isPassive = $requestCache['IsPassive']; + $protocolBinding = SAML2_Const::BINDING_HTTP_POST; /* HTTP-POST was the only supported binding before 1.6. */ if (isset($requestCache['IDPList'])) { $IDPList = $requestCache['IDPList']; @@ -208,15 +239,23 @@ class sspmod_saml_IdP_SAML2 { $forceAuthn = $request->getForceAuthn(); $isPassive = $request->getIsPassive(); $consumerURL = $request->getAssertionConsumerServiceURL(); + $protocolBinding = $request->getProtocolBinding(); SimpleSAML_Logger::info('SAML2.0 - IdP.SSOService: Incomming Authentication request: '. var_export($spEntityId, TRUE)); } + if ($protocolBinding === NULL || !in_array($protocolBinding, $supportedBindings, TRUE)) { + /* + * No binding specified or unsupported binding requested - default to HTTP-POST. + * TODO: Select any supported binding based on default endpoint? + */ + $protocolBinding = SAML2_Const::BINDING_HTTP_POST; + } if ($consumerURL !== NULL) { $found = FALSE; foreach ($spMetadata->getEndpoints('AssertionConsumerService') as $ep) { - if ($ep['Binding'] !== SAML2_Const::BINDING_HTTP_POST) { + if ($ep['Binding'] !== $protocolBinding) { continue; } if ($ep['Location'] !== $consumerURL) { @@ -235,7 +274,7 @@ class sspmod_saml_IdP_SAML2 { } if ($consumerURL === NULL) { /* Not specified or invalid. Use default. */ - $consumerURL = $spMetadata->getDefaultEndpoint('AssertionConsumerService', array(SAML2_Const::BINDING_HTTP_POST)); + $consumerURL = $spMetadata->getDefaultEndpoint('AssertionConsumerService', array($protocolBinding)); $consumerURL = $consumerURL['Location']; } @@ -248,7 +287,7 @@ class sspmod_saml_IdP_SAML2 { $sessionLostParams = array( 'spentityid' => $spEntityId, 'cookieTime' => time(), - ); + ); if ($relayState !== NULL) { $sessionLostParams['RelayState'] = $relayState; } @@ -269,6 +308,7 @@ class sspmod_saml_IdP_SAML2 { 'ForceAuthn' => $forceAuthn, 'isPassive' => $isPassive, 'saml:ConsumerURL' => $consumerURL, + 'saml:Binding' => $protocolBinding, ); $idp->handleAuthenticationRequest($state); diff --git a/www/saml2/idp/ArtifactResolutionService.php b/www/saml2/idp/ArtifactResolutionService.php new file mode 100644 index 000000000..b1f10d8c6 --- /dev/null +++ b/www/saml2/idp/ArtifactResolutionService.php @@ -0,0 +1,42 @@ +<?php + +/** + * The ArtifactResolutionService receives the samlart from the sp. + * And when the artifact is found, it sends a SAML2_ArtifactResponse. + * + * @author Danny Bollaert, UGent AS. <danny.bollaert@ugent.be> + * @package simpleSAMLphp + * @version $Id$ + */ + +require_once('../../_include.php'); + +$config = SimpleSAML_Configuration::getInstance(); +if (!$config->getBoolean('enable.saml20-idp', FALSE)) { + throw new SimpleSAML_Error_Error('NOACCESS'); +} + +$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); +$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted'); +$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted'); + +if (!$idpMetadata->getBoolean('saml20.sendartifact', FALSE)) { + throw new SimpleSAML_Error_Error('NOACCESS'); +} + +$binding = new SAML2_SOAP(); +$request = $binding->receive(); +if (!($request instanceof SAML2_ArtifactResolve)) { + throw new Exception('Message received on ArtifactResolutionService wasn\'t a ArtifactResolve request.'); +} +$artifact = $request->getArtifact(); +$responseData = SimpleSAML_Memcache::get('artifact:' . $artifact); +$document = new DOMDocument(); +$document->loadXML($responseData); +$responseXML = $document->firstChild; +$artifactResponse = new SAML2_ArtifactResponse(); + +$artifactResponse->setIssuer($idpEntityId); +$artifactResponse->setInResponseTo($request->getId()); +$artifactResponse->setAny($responseXML); +$binding->send($artifactResponse); diff --git a/www/saml2/idp/metadata.php b/www/saml2/idp/metadata.php index 3f172bd67..9c8dba5ee 100644 --- a/www/saml2/idp/metadata.php +++ b/www/saml2/idp/metadata.php @@ -27,10 +27,10 @@ try { /* Only one valid certificate. */ $certFingerprint = $certFingerprint[0]; } - + $logouttype = 'traditional'; if (array_key_exists('logouttype', $idpmeta)) $logouttype = $idpmeta['logouttype']; - + $urlSLO = $metadata->getGenerated('SingleLogoutService', 'saml20-idp-hosted', array('logouttype' => $logouttype)); $urlSLOr = $metadata->getGenerated('SingleLogoutServiceResponse', 'saml20-idp-hosted', array('logouttype' => $logouttype)); @@ -47,6 +47,15 @@ try { unset($metaArray['SingleLogoutServiceResponse']); } + if (isset($idpmeta['saml20.sendartifact']) && $idpmeta['saml20.sendartifact'] === TRUE) { + /* Artifact sending enabled. */ + $metaArray['ArtifactResolutionService'][] = array( + 'index' => 0, + 'Location' => SimpleSAML_Utilities::getBaseURL() . 'saml2/idp/ArtifactResolutionService.php', + 'Binding' => SAML2_Const::BINDING_SOAP, + ); + } + if (array_key_exists('NameIDFormat', $idpmeta)) { $metaArray['NameIDFormat'] = $idpmeta['NameIDFormat']; } else { @@ -74,7 +83,7 @@ try { $metaBuilder->addContact('technical', array( 'emailAddress' => $config->getString('technicalcontact_email', NULL), 'name' => $config->getString('technicalcontact_name', NULL), - )); + )); $metaxml = $metaBuilder->getEntityDescriptorText(); /* Sign the metadata if enabled. */ @@ -82,30 +91,30 @@ try { if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') { $defaultidp = $config->getString('default-saml20-idp', NULL); - + $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin'); - - + + $t->data['header'] = 'saml20-idp'; $t->data['metaurl'] = SimpleSAML_Utilities::selfURLNoQuery(); $t->data['metadata'] = htmlentities($metaxml); $t->data['metadataflat'] = htmlentities($metaflat); $t->data['defaultidp'] = $defaultidp; $t->show(); - + } else { - + header('Content-Type: application/xml'); - + echo $metaxml; exit(0); } - + } catch(Exception $exception) { - + SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception); } -- GitLab