diff --git a/modules/core/templates/logout-iframe-wrapper.php b/modules/core/templates/logout-iframe-wrapper.php index 3fafb77eec06498809c62a3acfe979516e45e604..00ce6be3ae9d71d89b4cc1b63166852fd36e765d 100644 --- a/modules/core/templates/logout-iframe-wrapper.php +++ b/modules/core/templates/logout-iframe-wrapper.php @@ -4,7 +4,7 @@ $id = $this->data['id']; $SPs = $this->data['SPs']; $timeout = $this->data['timeout']; -$iframeURL = 'logout-iframe.php?type=embed&id=' . urlencode($id) . '&timeout=' . (string)$timeout; +$iframeURL = 'logout-iframe.php?type=embed&id=' . urlencode($id); /* Pretty arbitrary height, but should have enough safety margins for most cases. */ $iframeHeight = 25 + count($SPs) * 4; diff --git a/modules/core/templates/logout-iframe.php b/modules/core/templates/logout-iframe.php index 1ae4073f6e95289a61930a71b84c042a0cc7170f..c632e61a562b25f1af87a4a08fc2b038a4160905 100644 --- a/modules/core/templates/logout-iframe.php +++ b/modules/core/templates/logout-iframe.php @@ -4,7 +4,6 @@ $id = $this->data['id']; $type = $this->data['type']; $from = $this->data['from']; $SPs = $this->data['SPs']; -$timeout = $this->data['timeout']; $stateImage = array( 'unsupported' => '/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png', @@ -23,12 +22,14 @@ $stateText = array( ); $spStatus = array(); +$spTimeout = array(); $nFailed = 0; $nProgress = 0; foreach ($SPs as $assocId => $sp) { assert('isset($sp["core:Logout-IFrame:State"])'); $state = $sp['core:Logout-IFrame:State']; $spStatus[sha1($assocId)] = $state; + $spTimeout[sha1($assocId)] = $sp['core:Logout-IFrame:Timeout'] - time(); if ($state === 'failed') { $nFailed += 1; } elseif ($state === 'inprogress') { @@ -52,8 +53,8 @@ $this->data['head'] .= ' window.stateImage = ' . json_encode($stateImage) . '; window.stateText = ' . json_encode($stateText) . '; window.spStatus = ' . json_encode($spStatus) . '; +window.spTimeout = ' . json_encode($spTimeout) . '; window.type = "' . $type . '"; -window.timeoutIn = ' . (string)($timeout - time()) . '; window.asyncURL = "logout-iframe.php?id=' . $id . '&type=async"; </script>'; diff --git a/modules/core/www/idp/logout-iframe.js b/modules/core/www/idp/logout-iframe.js index 62e91daf6945bf0037e56c9c3dfeddaa090157e0..282425ba6cd20fbbddac5484723f976a7cde1d30 100644 --- a/modules/core/www/idp/logout-iframe.js +++ b/modules/core/www/idp/logout-iframe.js @@ -53,16 +53,19 @@ function logoutFailed(spId, reason) { } function timeoutSPs() { + var cTime = ( (new Date()).getTime() - window.startTime ) / 1000; for (sp in window.spStatus) { - if (window.spStatus[sp] == 'inprogress') { + if (window.spTimeout[sp] <= cTime && window.spStatus[sp] == 'inprogress') { logoutFailed(sp, 'Timeout'); } } + window.timeoutID = window.setTimeout(timeoutSPs, 1000); } $('document').ready(function(){ + window.startTime = (new Date()).getTime(); if (window.type == 'js') { - window.timeoutID = window.setTimeout(timeoutSPs, window.timeoutIn * 1000); + window.timeoutID = window.setTimeout(timeoutSPs, 1000); updateStatus(); } else if (window.type == 'init') { $('#logout-type-selector').attr('value', 'js'); diff --git a/modules/core/www/idp/logout-iframe.php b/modules/core/www/idp/logout-iframe.php index 1754c4f08a870effabb947de4ff32be800456182..5b3c3e1abeaf9b8a4696b3ee6c0dbca23246bc87 100644 --- a/modules/core/www/idp/logout-iframe.php +++ b/modules/core/www/idp/logout-iframe.php @@ -14,12 +14,6 @@ if (isset($_REQUEST['type'])) { $type = 'init'; } -if (isset($_REQUEST['timeout'])) { - $timeout = (int)$_REQUEST['timeout']; -} else { - $timeout = time() + 5; -} - if ($type !== 'embed' && $type !== 'async') { SimpleSAML_Logger::stats('slo-iframe ' . $type); } @@ -49,6 +43,13 @@ if ($type !== 'init') { } } + /* Check for timeout. */ + if (isset($sp['core:Logout-IFrame:Timeout']) && $sp['core:Logout-IFrame:Timeout'] < time()) { + if ($sp['core:Logout-IFrame:State'] === 'inprogress') { + $sp['core:Logout-IFrame:State'] = 'failed'; + } + } + /* In case we are refreshing a page. */ if (!isset($associations[$assocId])) { $sp['core:Logout-IFrame:State'] = 'completed'; @@ -58,6 +59,16 @@ if ($type !== 'init') { if ($sp['core:Logout-IFrame:State'] === 'completed') { $idp->terminateAssociation($assocId); } + + if (!isset($sp['core:Logout-IFrame:Timeout'])) { + if (method_exists($sp['Handler'], 'getAssociationConfig')) { + $assocIdP = SimpleSAML_IdP::getByState($sp); + $assocConfig = call_user_func(array($sp['Handler'], 'getAssociationConfig'), $assocIdP, $sp); + $sp['core:Logout-IFrame:Timeout'] = $assocConfig->getInteger('core:logout-timeout', 5) + time(); + } else { + $sp['core:Logout-IFrame:Timeout'] = time() + 5; + } + } } } @@ -87,7 +98,6 @@ if ($type === 'nojs') { $t = new SimpleSAML_XHTML_Template($globalConfig, 'core:logout-iframe-wrapper.php'); $t->data['id'] = $id; $t->data['SPs'] = $state['core:Logout-IFrame:Associations']; - $t->data['timeout'] = $timeout; $t->show(); exit(0); } @@ -97,6 +107,5 @@ $t->data['id'] = $id; $t->data['type'] = $type; $t->data['from'] = $state['core:Logout-IFrame:From']; $t->data['SPs'] = $state['core:Logout-IFrame:Associations']; -$t->data['timeout'] = $timeout; $t->show(); exit(0); diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php index 803edfcc3918b50315118a5e2e57f6a1ef88b84e..26a0d47c9be54f17fbcb32e42797facf15f2f112 100644 --- a/modules/saml/lib/IdP/SAML2.php +++ b/modules/saml/lib/IdP/SAML2.php @@ -491,6 +491,23 @@ class sspmod_saml_IdP_SAML2 { } + /** + * Retrieve the metadata for the given SP association. + * + * @param SimpleSAML_IdP $idp The IdP the association belongs to. + * @param array $association The SP association. + * @return SimpleSAML_Configuration|NULL Configuration object for the SP metadata. + */ + public static function getAssociationConfig(SimpleSAML_IdP $idp, array $association, $relayState) { + $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); + try { + return $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote'); + } catch (Exception $e) { + SimpleSAML_Configuration::loadFromArray(array(), 'Unknown SAML 2 entity.'); + } + } + + /** * Calculate the NameID value that should be used. *