Complete bugfix for issue #561. HTTP-Post supported for SLO not initiated by the SP. Working for both traditional logout and iframe version.
git-svn-id: http://simplesamlphp.googlecode.com/svn/trunk@3262 44740490-163a-0410-bde0-09ae8108e29a
This commit is contained in:
parent
4b88d23d59
commit
76d9c5e50d
|
@ -29,8 +29,7 @@ class SimpleSAML_IdP_LogoutTraditional extends SimpleSAML_IdP_LogoutHandler {
|
|||
|
||||
try {
|
||||
$idp = SimpleSAML_IdP::getByState($association);
|
||||
$url = call_user_func(array($association['Handler'], 'getLogoutURL'), $idp, $association, $relayState);
|
||||
SimpleSAML_Utilities::redirect($url);
|
||||
call_user_func(array($association['Handler'], 'sendLogoutRequest'), $idp, $association, $relayState);
|
||||
} catch (Exception $e) {
|
||||
SimpleSAML_Logger::warning('Unable to initialize logout to ' . var_export($id, TRUE) . '.');
|
||||
$this->idp->terminateAssociation($id);
|
||||
|
|
|
@ -74,7 +74,10 @@ if ($type === 'embed') {
|
|||
} else {
|
||||
$this->includeAtTemplateBase('includes/header.php');
|
||||
}
|
||||
|
||||
?>
|
||||
<div id="wrap">
|
||||
<div id="content">
|
||||
<?php
|
||||
if ($from !== NULL) {
|
||||
|
||||
echo('<div><img style="float: left; margin-right: 12px" src="/' . $this->data['baseurlpath'] . 'resources/icons/checkmark.48x48.png" alt="Successful logout" />');
|
||||
|
@ -167,7 +170,6 @@ echo('<form method="post" action="logout-iframe-done.php" id="failed-form" targe
|
|||
echo('<input type="hidden" name="id" value="' . $id . '" />');
|
||||
echo('<input type="submit" name="continue" value="' . $this->t('{logout:return}'). '" />');
|
||||
echo('</form>');
|
||||
|
||||
echo('</div>');
|
||||
|
||||
if ($nProgress == 0 && $nFailed == 0) {
|
||||
|
@ -203,10 +205,14 @@ if ($type === 'js') {
|
|||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</div>
|
||||
<!-- #content -->
|
||||
<?php
|
||||
if ($type === 'embed') {
|
||||
$this->includeAtTemplateBase('includes/footer-embed.php');
|
||||
} else {
|
||||
$this->includeAtTemplateBase('includes/footer.php');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<!-- #wrap -->
|
||||
|
|
|
@ -83,7 +83,8 @@ if ($type === 'js' || $type === 'nojs') {
|
|||
|
||||
try {
|
||||
$assocIdP = SimpleSAML_IdP::getByState($sp);
|
||||
$url = call_user_func(array($sp['Handler'], 'getLogoutURL'), $assocIdP, $sp, NULL);
|
||||
$params = array('id' => $id, 'sp' => $sp['id'], 'type' => $type);
|
||||
$url = SimpleSAML_Module::getModuleURL('core/idp/performlogout.php', $params);
|
||||
$sp['core:Logout-IFrame:URL'] = $url;
|
||||
} catch (Exception $e) {
|
||||
$sp['core:Logout-IFrame:State'] = 'failed';
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
if (!isset($_REQUEST['id'])) {
|
||||
throw new SimpleSAML_Error_BadRequest('Missing id-parameter.');
|
||||
}
|
||||
$id = (string)$_REQUEST['id'];
|
||||
if (!isset($_REQUEST['sp'])) {
|
||||
throw new SimpleSAML_Error_BadRequest('Missing sp-parameter.');
|
||||
}
|
||||
$sp = urldecode($_REQUEST['sp']);
|
||||
$type = @(string)$_REQUEST['type'];
|
||||
|
||||
$state = SimpleSAML_Auth_State::loadState($id, 'core:Logout-IFrame');
|
||||
$idp = SimpleSAML_IdP::getByState($state);
|
||||
|
||||
$associations = $state['core:Logout-IFrame:Associations'];
|
||||
if (!isset($associations[$sp])) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$association = $associations[$sp];
|
||||
|
||||
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
|
||||
$idpMetadata = $idp->getConfig();
|
||||
$spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
|
||||
|
||||
$lr = sspmod_saml_Message::buildLogoutRequest($idpMetadata, $spMetadata);
|
||||
$lr->setSessionIndex($association['saml:SessionIndex']);
|
||||
$lr->setNameId($association['saml:NameID']);
|
||||
|
||||
$assertionLifetime = $spMetadata->getInteger('assertion.lifetime', NULL);
|
||||
if ($assertionLifetime === NULL) {
|
||||
$assertionLifetime = $idpMetadata->getInteger('assertion.lifetime', 300);
|
||||
}
|
||||
$lr->setNotOnOrAfter(time() + $assertionLifetime);
|
||||
|
||||
$encryptNameId = $spMetadata->getBoolean('nameid.encryption', NULL);
|
||||
if ($encryptNameId === NULL) {
|
||||
$encryptNameId = $idpMetadata->getBoolean('nameid.encryption', FALSE);
|
||||
}
|
||||
if ($encryptNameId) {
|
||||
$lr->encryptNameId(sspmod_saml_Message::getEncryptionKey($spMetadata));
|
||||
}
|
||||
|
||||
SimpleSAML_Stats::log('saml:idp:LogoutRequest:sent', array(
|
||||
'spEntityID' => $association['saml:entityID'],
|
||||
'idpEntityID' => $idpMetadata->getString('entityid'),
|
||||
));
|
||||
|
||||
$bindings = array(SAML2_Const::BINDING_HTTP_REDIRECT);
|
||||
if ($type === 'js') {
|
||||
array_push($bindings, SAML2_Const::BINDING_HTTP_POST);
|
||||
}
|
||||
|
||||
$dst = $spMetadata->getDefaultEndpoint('SingleLogoutService', $bindings);
|
||||
$binding = SAML2_Binding::getBinding($dst['Binding']);
|
||||
$lr->setDestination($dst['Location']);
|
||||
|
||||
$binding->send($lr);
|
|
@ -382,9 +382,43 @@ class sspmod_saml_IdP_SAML2 {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a logout request to a given association.
|
||||
*
|
||||
* @param SimpleSAML_IdP $idp The IdP we are sending a logout request from.
|
||||
* @param array $association The association that should be terminated.
|
||||
* @param string|NULL $relayState An id that should be carried across the logout.
|
||||
*/
|
||||
public static function sendLogoutRequest(SimpleSAML_IdP $idp, array $association, $relayState) {
|
||||
assert('is_string($relayState) || is_null($relayState)');
|
||||
|
||||
SimpleSAML_Logger::info('Sending SAML 2.0 LogoutRequest to: '. var_export($association['saml:entityID'], TRUE));
|
||||
|
||||
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
|
||||
$idpMetadata = $idp->getConfig();
|
||||
$spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
|
||||
|
||||
SimpleSAML_Stats::log('saml:idp:LogoutRequest:sent', array(
|
||||
'spEntityID' => $association['saml:entityID'],
|
||||
'idpEntityID' => $idpMetadata->getString('entityid'),
|
||||
));
|
||||
|
||||
$dst = $spMetadata->getDefaultEndpoint('SingleLogoutService', array(
|
||||
SAML2_Const::BINDING_HTTP_REDIRECT,
|
||||
SAML2_Const::BINDING_HTTP_POST)
|
||||
);
|
||||
$binding = SAML2_Binding::getBinding($dst['Binding']);
|
||||
$lr = self::buildLogoutRequest($idpMetadata, $spMetadata, $association, $relayState);
|
||||
$lr->setDestination($dst['Location']);
|
||||
|
||||
$binding->send($lr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a logout response.
|
||||
*
|
||||
* @param SimpleSAML_IdP $idp The IdP we are sending a logout request from.
|
||||
* @param array &$state The logout state array.
|
||||
*/
|
||||
public static function sendLogoutResponse(SimpleSAML_IdP $idp, array $state) {
|
||||
|
@ -512,7 +546,8 @@ class sspmod_saml_IdP_SAML2 {
|
|||
|
||||
|
||||
/**
|
||||
* Retrieve a logout URL for a given logout association.
|
||||
* Retrieve a logout URL for a given logout association. Only for logout endpoints that support
|
||||
* HTTP-Redirect binding.
|
||||
*
|
||||
* @param SimpleSAML_IdP $idp The IdP we are sending a logout request from.
|
||||
* @param array $association The association that should be terminated.
|
||||
|
@ -527,29 +562,11 @@ class sspmod_saml_IdP_SAML2 {
|
|||
$idpMetadata = $idp->getConfig();
|
||||
$spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
|
||||
|
||||
$lr = sspmod_saml_Message::buildLogoutRequest($idpMetadata, $spMetadata);
|
||||
$lr->setRelayState($relayState);
|
||||
$lr->setSessionIndex($association['saml:SessionIndex']);
|
||||
$lr->setNameId($association['saml:NameID']);
|
||||
|
||||
$assertionLifetime = $spMetadata->getInteger('assertion.lifetime', NULL);
|
||||
if ($assertionLifetime === NULL) {
|
||||
$assertionLifetime = $idpMetadata->getInteger('assertion.lifetime', 300);
|
||||
}
|
||||
$lr->setNotOnOrAfter(time() + $assertionLifetime);
|
||||
|
||||
$encryptNameId = $spMetadata->getBoolean('nameid.encryption', NULL);
|
||||
if ($encryptNameId === NULL) {
|
||||
$encryptNameId = $idpMetadata->getBoolean('nameid.encryption', FALSE);
|
||||
}
|
||||
if ($encryptNameId) {
|
||||
$lr->encryptNameId(sspmod_saml_Message::getEncryptionKey($spMetadata));
|
||||
}
|
||||
|
||||
SimpleSAML_Stats::log('saml:idp:LogoutRequest:sent', array(
|
||||
'spEntityID' => $association['saml:entityID'],
|
||||
'idpEntityID' => $idpMetadata->getString('entityid'),
|
||||
));
|
||||
// It doesn't make sense to use HTTP-Post when asking for a logout URL, therefore we allow only
|
||||
// HTTP-Redirect.
|
||||
$dst = $spMetadata->getDefaultEndpoint('SingleLogoutService', array(SAML2_Const::BINDING_HTTP_REDIRECT));
|
||||
$lr = self::buildLogoutRequest($idpMetadata, $spMetadata, $association, $relayState);
|
||||
$lr->setDestination($dst['Location']);
|
||||
|
||||
$binding = new SAML2_HTTPRedirect();
|
||||
return $binding->getRedirectURL($lr);
|
||||
|
@ -693,7 +710,8 @@ class sspmod_saml_IdP_SAML2 {
|
|||
* @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
|
||||
* @return string The NameFormat.
|
||||
*/
|
||||
private static function getAttributeNameFormat(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata) {
|
||||
private static function getAttributeNameFormat(SimpleSAML_Configuration $idpMetadata,
|
||||
SimpleSAML_Configuration $spMetadata) {
|
||||
|
||||
/* Try SP metadata first. */
|
||||
$attributeNameFormat = $spMetadata->getString('attributes.NameFormat', NULL);
|
||||
|
@ -940,6 +958,40 @@ class sspmod_saml_IdP_SAML2 {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a logout request based on information in the metadata.
|
||||
*
|
||||
* @param SimpleSAML_Configuration idpMetadata The metadata of the IdP.
|
||||
* @param SimpleSAML_Configuration spMetadata The metadata of the SP.
|
||||
* @param array $association The SP association.
|
||||
* @param string|NULL $relayState An id that should be carried across the logout.
|
||||
*/
|
||||
private static function buildLogoutRequest(SimpleSAML_Configuration $idpMetadata,
|
||||
SimpleSAML_Configuration $spMetadata, array $association, $relayState) {
|
||||
|
||||
$lr = sspmod_saml_Message::buildLogoutRequest($idpMetadata, $spMetadata);
|
||||
$lr->setRelayState($relayState);
|
||||
$lr->setSessionIndex($association['saml:SessionIndex']);
|
||||
$lr->setNameId($association['saml:NameID']);
|
||||
|
||||
$assertionLifetime = $spMetadata->getInteger('assertion.lifetime', NULL);
|
||||
if ($assertionLifetime === NULL) {
|
||||
$assertionLifetime = $idpMetadata->getInteger('assertion.lifetime', 300);
|
||||
}
|
||||
$lr->setNotOnOrAfter(time() + $assertionLifetime);
|
||||
|
||||
$encryptNameId = $spMetadata->getBoolean('nameid.encryption', NULL);
|
||||
if ($encryptNameId === NULL) {
|
||||
$encryptNameId = $idpMetadata->getBoolean('nameid.encryption', FALSE);
|
||||
}
|
||||
if ($encryptNameId) {
|
||||
$lr->encryptNameId(sspmod_saml_Message::getEncryptionKey($spMetadata));
|
||||
}
|
||||
|
||||
return $lr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a authentication response based on information in the metadata.
|
||||
*
|
||||
|
@ -947,7 +999,8 @@ class sspmod_saml_IdP_SAML2 {
|
|||
* @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
|
||||
* @param string $consumerURL The Destination URL of the response.
|
||||
*/
|
||||
private static function buildResponse(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, $consumerURL) {
|
||||
private static function buildResponse(SimpleSAML_Configuration $idpMetadata,
|
||||
SimpleSAML_Configuration $spMetadata, $consumerURL) {
|
||||
|
||||
$signResponse = $spMetadata->getBoolean('saml20.sign.response', NULL);
|
||||
if ($signResponse === NULL) {
|
||||
|
|
|
@ -19,5 +19,5 @@ if(array_key_exists('head', $this->data)) {
|
|||
}
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<body class="body-embed">
|
||||
|
||||
|
|
|
@ -16,6 +16,12 @@ body {
|
|||
font: 83%/1.5 arial,tahoma,verdana,sans-serif;
|
||||
}
|
||||
|
||||
.body-embed {
|
||||
padding: 0;
|
||||
background: #ffffff;
|
||||
font: 83%/1.5 arial,tahoma,verdana,sans-serif;
|
||||
}
|
||||
|
||||
img {
|
||||
border: none;
|
||||
display: block;
|
||||
|
|
Reference in New Issue