Skip to content
Snippets Groups Projects
Commit 76a51a1d authored by Olav Morken's avatar Olav Morken
Browse files

saml2/idp: Use the new logout processing.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2140 44740490-163a-0410-bde0-09ae8108e29a
parent 0a1f8bf3
Branches
Tags
No related merge requests found
......@@ -314,4 +314,126 @@ class sspmod_saml_IdP_SAML2 {
$idp->handleAuthenticationRequest($state);
}
/**
* Send a logout response.
*
* @param array &$state The logout state array.
*/
public static function sendLogoutResponse(SimpleSAML_IdP $idp, array $state) {
assert('isset($state["saml:SPEntityId"])');
assert('isset($state["saml:RequestId"])');
assert('array_key_exists("saml:RelayState", $state)'); // Can be NULL.
$spEntityId = $state['saml:SPEntityId'];
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $idp->getConfig();
$spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
$lr = sspmod_saml2_Message::buildLogoutResponse($idpMetadata, $spMetadata);
$lr->setInResponseTo($state['saml:RequestId']);
$lr->setRelayState($state['saml:RelayState']);
if (isset($state['core:Failed']) && $state['core:Failed']) {
$lr->setStatus(array(
'Code' => SAML2_Const::STATUS_SUCCESS,
'SubCode' => SAML2_Const::STATUS_PARTIAL_LOGOUT,
));
SimpleSAML_Logger::info('Sending logout response for partial logout to SP ' . var_export($spEntityId, TRUE));
} else {
SimpleSAML_Logger::debug('Sending logout response to SP ' . var_export($spEntityId, TRUE));
}
$binding = new SAML2_HTTPRedirect();
$binding->setDestination(sspmod_SAML2_Message::getDebugDestination());
$binding->send($lr);
}
/**
* Receive a logout message.
*
* @param SimpleSAML_IdP $idp The IdP we are receiving it for.
*/
public static function receiveLogoutMessage(SimpleSAML_IdP $idp) {
$binding = SAML2_Binding::getCurrentBinding();
$message = $binding->receive();
$spEntityId = $message->getIssuer();
if ($spEntityId === NULL) {
/* Without an issuer we have no way to respond to the message. */
throw new SimpleSAML_Error_BadRequest('Received message on logout endpoint without issuer.');
}
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $idp->getConfig();
$spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
sspmod_saml2_Message::validateMessage($idpMetadata, $spMetadata, $message);
if ($message instanceof SAML2_LogoutResponse) {
$spEntityId = $message->getIssuer();
if ($spEntityId === NULL) {
throw new SimpleSAML_Error_Exception('Missing <Issuer> in LogoutResponse.');
}
$relayState = $message->getRelayState();
if (!$message->isSuccess()) {
$logoutError = sspmod_saml2_Message::getResponseError($message);
SimpleSAML_Logger::warning('Unsuccessful logout. Status was: ' . $logoutError);
} else {
$logoutError = NULL;
}
$assocId = 'saml:' . $spEntityId;
$idp->handleLogoutResponse($assocId, $relayState, $logoutError);
} elseif ($message instanceof SAML2_LogoutRequest) {
$state = array(
'Responder' => array('sspmod_saml_IdP_SAML2', 'sendLogoutResponse'),
'saml:SPEntityId' => $spEntityId,
'saml:RelayState' => $message->getRelayState(),
'saml:RequestId' => $message->getId(),
);
$assocId = 'saml:' . $spEntityId;
$idp->handleLogoutRequest($state, $assocId);
} else {
throw new SimpleSAML_Error_BadRequest('Unknown message received on logout endpoint: ' . get_class($message));
}
}
/**
* Retrieve a logout URL for a given logout 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 getLogoutURL(SimpleSAML_IdP $idp, array $association, $relayState) {
assert('is_string($relayState) || is_null($relayState)');
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpMetadata = $idp->getConfig();
$spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
$lr = sspmod_saml2_Message::buildLogoutRequest($idpMetadata, $spMetadata);
$lr->setRelayState($relayState);
$lr->setSessionIndex($association['saml:SessionIndex']);
$lr->setNameId($association['saml:NameID']);
$binding = new SAML2_HTTPRedirect();
return $binding->getRedirectURL($lr);
}
}
<?php
$iframehtml = '';
foreach ($this->data['sparray'] AS $sp) {
$iframehtml .= '<iframe class="hiddeniframe" onload="xajax_updateslostatus()" style="border: 1px solid #888; width: 80%; height: 100px" src="' . htmlentities($sp['url']) . '" ></iframe>';
}
# $iframehtml = str_replace('"', '\"', $iframehtml);
# $iframehtml = str_replace("\n", '', $iframehtml);
# $iframehtml = str_replace("\r", '', $iframehtml);
$this->data['hideLanguageBar'] = TRUE;
$this->data['head'] .= '<script type="text/javascript" src="/' . $this->data['baseurlpath'] . 'resources/jquery.js"></script>';
$this->data['head'] .= '<link rel="stylesheet" type="text/css" href="/' . $this->data['baseurlpath'] . 'resources/slo.css" />';
$nologoutSPs = (count($this->data['sparrayNoLogout']) > 0);
$this->data['head'] .= '
<script type="text/javascript" language="JavaScript">
<!--
$(document).ready(function() {
$("div#requirejavascript").show();
/* $("div.completedButWarnings").hide(); */
$("div#interrupt").hide();
$("input#ok").click(function () {
startslo();
});
$("input#cancel").click(function () {
sendResponse();
});
$("input#returnanyway").click(function () {
sendResponse();
});
$("input#interruptbutton").click(function () {
sendResponse();
});
' . ($nologoutSPs ? '$("#incapablesps").show();' : '$("#incapablesps").hide();') . '
});
function toolong() {
$("div#interrupt").show().fadeOut("fast").fadeIn("fast");
}
/* This function is called when users clicks to start single logout */
function startslo() {
$("#confirmation").hide();
$("#hiddeniframecontainer").html("' . str_replace('"', '\"', $iframehtml) . '");
$("table#slostatustable tr.onhold").removeClass("onhold").addClass("inprogress");
/* $("div.completedButWarnings").show(); */
' . ($iframehtml === '' ? 'sendResponse();' : '') . '
setTimeout("toolong()", 16000);
}
/* This function is called from the AJAX response with xajax with the hash of the entityid of the SP */
function slocompletesp($entityhash) {
$("table#slostatustable tr#" + $entityhash).filter(".inprogress").removeClass("inprogress").addClass("completed").
children().fadeOut("fast").fadeIn("fast");
}
/* SLO completed for all sps. */
function slocompleted() {
/* $("div.completedButWarnings").show(); */
$("div#interrupt").hide();
setTimeout("sendResponse()", 2000);
}
function sendResponse() {
window.location = "' . $this->data['logoutresponse'] . '";
}
// -->
</script>';
$this->includeAtTemplateBase('includes/header.php');
?>
<!-- Proper fallback for browsers that do not support javascript or have javascript turned off -->
<noscript>
<div id="nojavascriptframe">
<iframe style="margin: 1em; width: 90%; height: 5em; border: 1px solid #eee" src="SingleLogoutServiceiFrameNoJavascript.php?response=<?php echo urlencode($this->data['logoutresponse']); ?>"></iframe>
</div>
<?php
foreach ($this->data['sparray'] AS $sp) {
echo '<iframe class="hiddeniframe" onload="xajax_updateslostatus()" style="border: 1px solid #888; width: 80%; height: 100px"
src="' . htmlentities($sp['url']) . '" ></iframe>' . "\n";
}
?>
</noscript>
<div id="requirejavascript" style="display: none">
<?php
#echo('<pre>'); print_r($this->data); exit;
if (array_key_exists('requesterName', $this->data)) {
$requesterName = is_array($this->data['requesterName']) ?
$this->getTranslation($this->data['requesterName']) : $this->data['requesterName'];
}
#echo('<p>' . $this->t('{logout:description}', array('%REQUESTERNAME%' => $requestername)) . '</p>');
?>
<!-- <div class="loggedout"><?php echo($this->t('{logout:logged_out}', array('%REQUESTERNAME%' => $requestername))); ?></div> -->
<?php
if (array_key_exists('requesterName', $this->data)) {
echo('<div><img style="float: left; margin-right: 12px" src="/' . $this->data['baseurlpath'] . 'resources/icons/checkmark48.png" alt="Successful logout" />');
echo('<p style="padding-top: 16px; ">' . $this->t('{logout:loggedoutfrom}', array('%SP%' => '<strong>' .$requesterName.'</strong>')) . '</p>');
echo('<p style="height: 0px; clear: left;"></p>');
echo('</div>');
}
echo('<div style="margin-top: 3em; clear: both">');
echo('<p style="margin-bottom: .5em">' . $this->t('{logout:also_from}') . '</p>');
echo '<table id="slostatustable">';
/** Remove initiated from. showed above instead
echo '<tr class="initiated" id="e_initiated">' . "\n";
echo ' <td><img style="float: left; margin: 3px" src="/' . $this->data['baseurlpath'] .
'resources/icons/silk/accept.png" alt="Initiated from" /></td>' . "\n";
echo ' <td>' . $this->t('{logout:initiated}') . '</td>';
echo ' <td>' . $requesterName . '</td>' ."\n";
echo '</tr>' . "\n";
*/
foreach ($this->data['sparrayNoLogout'] AS $spentityid => $sp) {
$spname = is_array($sp['name']) ? $this->getTranslation($sp['name']) : $sp['name'];
echo '<tr class="initiated" id="e' . sha1($spentityid) . '">' . "\n";
echo ' <td class="statustext">Logout not supported</td>';
echo ' <td ><img style="" src="/' . $this->data['baseurlpath'] .
'resources/icons/silk/delete.png" alt="Initiated from" /></td>' . "\n";
echo ' <td>' . $spname . '</td>' ."\n";
echo '</tr>' . "\n";
}
foreach ($this->data['sparray'] AS $spentityid => $sp) {
$spname = is_array($sp['name']) ? $this->getTranslation($sp['name']) : $sp['name'];
echo '<tr class="ready onhold" id="e' . sha1($spentityid) . '">' . "\n";
echo ' <td class="statustext">';
echo ' <span class="completed">' . $this->t('{logout:completed}') . '</span>' . "\n";
# echo ' <span class="onhold">' . $this->t('{logout:hold}') . '</span>' . "\n";
# echo ' <span class="onhold"></span>' . "\n";
echo ' <span class="inprogress">' . $this->t('{logout:progress}') . '</span>' . "\n";
echo ' <span class="failed">' . $this->t('{logout:failed}') . '</span>' . "\n";
echo ' </td>';
echo ' <td class="icons">';
echo ' <img class="completed" src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="Completed" />' . "\n";
echo ' <img class="onhold" src="/' . $this->data['baseurlpath'] . 'resources/icons/bullet16_grey.png" alt="SP SLO on hold" />' . "\n";
echo ' <img class="inprogress" src="/' . $this->data['baseurlpath'] . 'resources/progress.gif" alt="Progress bar" />' . "\n";
echo ' <img class="failed" src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/exclamation.png" alt="Failed" />' . "\n";
echo ' </td>' . "\n";
echo ' <td>' . $spname . '</td>' ."\n";
echo '</tr>' . "\n";
// echo '<div class="inprogress" id="e' . sha1($spentityid) . '">
// <img style="float: left; margin: 3px" src="/' . $this->data['baseurlpath'] . 'resources/progress.gif" alt="Progress bar" />Wait... is logging out from <strong>' . $spname . '</strong></div>' . "\n";
}
echo '</table></div>';
$completed = ' class="allcompleted"';
if (count($this->data['sparray']) > 0) {
$completed = '';
}
?>
<div id="confirmation" style="margin-top: 1em" >
<p>
<?php echo $this->t('{logout:logout_all_question}'); ?> <br />
</p>
<input type="button" id="ok" name="ok" value="<?php echo $this->t('{logout:logout_all}'); ?>" />
<?php
if (array_key_exists('requesterName', $this->data)) {
echo '<input type="button" id="cancel" name="cancel" value="' . $this->t('{logout:logout_only}', array('%SP%' => $requesterName)) . '" />';
} else {
echo '<input type="button" id="cancel" name="cancel" value="' . $this->t('{logout:no}') . '" />';
}
?>
<p id="incapablesps" >
<?php echo($this->t('{logout:incapablesps}')); ?>
</p>
</div>
<div id="interrupt" style="margin-top: 1em; border: 1px solid #ccc; padding: 1em; background: #eaeaea" >
<p style="margin: 0px; padding; 0px">
<img src="/<?php echo($this->data['baseurlpath']); ?>resources/icons/timeout.png"
alt="Timeout"
style="float: left; margin: 0px 5px 0px 0px"
/>
<?php echo $this->t('{logout:respond_info}'); ?> <br />
<input type="button" id="interruptbutton" name="interrupt" value="<?php echo $this->t('{logout:return}'); ?>" />
</p>
</div>
<div id="hiddeniframecontainer" style="margin: 0px; padding: 0px;"></div>
</div> <!-- requirejavascript -->
<!--
<script type="text/javascript" language="JavaScript">
showdiv('requirejavascript');
</script>
-->
<?php $this->includeAtTemplateBase('includes/footer.php'); ?>
......@@ -9,324 +9,17 @@
* @version $Id$
*/
// TODO: Show error message, when shibboleth sp is logged in.
require_once('../../_include.php');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Accessing SAML 2.0 IdP endpoint SingleLogoutService');
if (!$config->getBoolean('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError(isset($session) ? $session->getTrackID() : null, 'NOACCESS');
try {
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
} catch (Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got IdP entity id: ' . $idpEntityId);
$logouttype = $idpMetadata->getString('logouttype', 'traditional');
if ($logouttype !== 'traditional')
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS', new Exception('This IdP is configured to use logout type [' . $logouttype . '], but this endpoint is only available for IdP using logout type [traditional]'));
/**
* The $logoutInfo contains information about the current logout operation.
* It can have the following attributes:
* - 'RelayState' - The RelayState which should be returned to the SP which initiated the logout operation.
* - 'Issuer' - The entity id of the SP which initiated the logout operation.
* - 'RequestID' - The id of the LogoutRequest which initiated the logout operation.
*/
$logoutInfo = array();
/**
* This function retrieves the logout info with the given ID.
*
* @param $id The identifier of the logout info.
*/
function fetchLogoutInfo($id) {
global $session;
global $logoutInfo;
$logoutInfo = $session->getData('idplogoutresponsedata', $id);
if($logoutInfo === NULL) {
SimpleSAML_Logger::warning('SAML2.0 - IdP.SingleLogoutService: Lost logout information.');
}
}
/**
* This function saves the logout info with the given ID.
*
* @param $id The identifier the logout info should be saved with.
*/
function saveLogoutInfo($id) {
global $session;
global $logoutInfo;
$session->setData('idplogoutresponsedata', $id, $logoutInfo);
}
/**
* If we get an incoming LogoutRequest then we initiate the logout process.
* in this case an SAML 2.0 SP is sending an request, which also is referred to as
* SP initiated Single Logout.
*
*/
if (isset($_REQUEST['SAMLRequest'])) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got SAML reuqest');
$binding = SAML2_Binding::getCurrentBinding();
try {
$logoutRequest = $binding->receive();
if (!($logoutRequest instanceof SAML2_LogoutRequest)) {
throw new Exception('Received a request which wasn\'t a LogoutRequest ' .
'on logout endpoint. Was: ' . get_class($logoutRequest));
}
$spEntityId = $logoutRequest->getIssuer();
if ($spEntityId === NULL) {
throw new Exception('Missing issuer in logout reqeust.');
}
$spMetadata = $metadata->getMetadataConfig($spEntityId, 'saml20-sp-remote');
sspmod_saml2_Message::validateMessage($spMetadata, $idpMetadata, $logoutRequest);
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTREQUEST', $exception);
}
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: got Logoutrequest from ' . $spEntityId);
SimpleSAML_Logger::stats('saml20-idp-SLO spinit ' . $spEntityId . ' ' . $idpEntityId);
/* Fill in the $logoutInfo associative array with information about this logout request. */
$logoutInfo['Issuer'] = $spEntityId;
$logoutInfo['RequestID'] = $logoutRequest->getId();
$logoutInfo['RelayState'] = $logoutRequest->getRelayState();
SimpleSAML_Logger::debug('SAML2.0 - IDP.SingleLogoutService: Setting cached request with issuer ' . $spEntityId);
$session->set_sp_logout_completed($spEntityId);
/*
* We receive a Logout Response to a Logout Request that we have issued earlier.
*/
} elseif (isset($_REQUEST['SAMLResponse'])) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got SAML response');
$binding = SAML2_Binding::getCurrentBinding();
try {
$logoutResponse = $binding->receive();
if (!($logoutResponse instanceof SAML2_LogoutResponse)) {
throw new Exception('Received a response which wasn\'t a LogoutResponse ' .
'on logout endpoint. Was: ' . get_class($logoutResponse));
}
$spEntityId = $logoutResponse->getIssuer();
if ($spEntityId === NULL) {
throw new Exception('Missing issuer in logout response.');
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: SAML response parsed. Issuer is: ' . $spEntityId);
$spMetadata = $metadata->getMetadataConfig($spEntityId, 'saml20-sp-remote');
sspmod_saml2_Message::validateMessage($spMetadata, $idpMetadata, $logoutResponse);
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTRESPONSE', $exception);
}
/* Fetch the $logoutInfo variable based on the InResponseTo attribute of the response. */
fetchLogoutInfo($logoutResponse->getInResponseTo());
$session->set_sp_logout_completed($spEntityId);
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: got LogoutResponse from ' . $spEntityId);
} elseif(array_key_exists('LogoutID', $_GET)) {
/* This is a response from bridged SLO. */
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got response from bridged SLO.');
/* Fetch the $logoutInfo variable. */
fetchLogoutInfo($_GET['LogoutID']);
} elseif(array_key_exists('ReturnTo', $_GET)) {
/* We have a ReturnTo - this is IdP initialized SLO. */
$logoutInfo['RelayState'] = $_GET['ReturnTo'];
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId);
if (isset($_REQUEST['ReturnTo'])) {
$idp->doLogoutRedirect((string)$_REQUEST['ReturnTo']);
} else {
/*
* We have no idea what to do here. It is neither a logout request, a logout
* response nor a response from bridged SLO.
*/
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: No request, response or bridge');
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SLOSERVICEPARAMS');
}
/* First, log out of the current authentication source. */
$authority = $session->getAuthority();
if ($authority !== NULL) {
/* We are logged in. */
$bridgedId = SimpleSAML_Utilities::generateID();
$returnTo = SimpleSAML_Utilities::selfURLNoQuery() . '?LogoutID=' . $bridgedId;
/* Save the $logoutInfo until we return from the SP. */
saveLogoutInfo($bridgedId);
if ($authority === $idpMetadata->getString('auth')) {
/* This is probably an authentication source. */
SimpleSAML_Auth_Default::initLogoutReturn($returnTo);
} elseif ($authority === 'saml2') {
/* SAML 2 SP which isn't an authentication source. */
SimpleSAML_Utilities::redirect('/' . $config->getBaseURL() . 'saml2/sp/initSLO.php',
array('RelayState' => $returnTo)
);
} else {
/* A different old-style authentication file. */
$session->doLogout();
}
}
/*
* Find the next SP we should log out from. We will search through the list of
* SPs until we find a valid SP with a SingleLogoutService endpoint.
*/
while (TRUE) {
/* Dump the current sessions (for debugging). */
$session->dump_sp_sessions();
/*
* We proceed to send logout requests to all remaining SPs.
*/
$spEntityId = $session->get_next_sp_logout();
// If there are no more SPs left, then we will not look for more SPs.
if (empty($spEntityId)) {
break;
}
try {
$spMetadata = $metadata->getMetadataConfig($spEntityId, 'saml20-sp-remote');
} catch (Exception $e) {
/* It seems that an SP has disappeared from the metadata between login and logout. */
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Missing metadata for ' .
$spEntityId . '; looking for more SPs.');
continue;
}
$singleLogoutService = $spMetadata->getDefaultEndpoint('SingleLogoutService', array(SAML2_Const::BINDING_HTTP_REDIRECT), NULL);
if ($singleLogoutService === NULL) {
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: No supported SingleLogoutService for ' .
$spEntityId . '; looking for more SPs.');
continue;
}
/* $spEntityId now contains the next SP. */
break;
}
if ($spEntityId) {
SimpleSAML_Logger::info('SAML2.0 - IDP.SingleLogoutService: Logout next SP ' . $spEntityId);
try {
$nameId = $session->getSessionNameId('saml20-sp-remote', $spEntityId);
if($nameId === NULL) {
$nameId = $session->getNameID();
}
$lr = sspmod_saml2_Message::buildLogoutRequest($idpMetadata, $spMetadata);
$lr->setSessionIndex($session->getSessionIndex());
$lr->setNameId($nameId);
/* Save the $logoutInfo until we return from the SP. */
saveLogoutInfo($lr->getId());
$binding = new SAML2_HTTPRedirect();
$binding->setDestination(sspmod_SAML2_Message::getDebugDestination());
$binding->send($lr);
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATELOGOUTREQUEST', $exception);
}
}
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: LogoutService: All SPs done ');
/*
* Logout procedure is done and we send a Logout Response back to the SP
*/
try {
if(!$logoutInfo) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTINFOLOST');
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Found logout info with these keys: ' . join(',', array_keys($logoutInfo)));
/**
* Clean up session object to save storage.
*/
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size before cleaning: ' . $session->getSize());
$session->clean();
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size after cleaning: ' . $session->getSize());
/*
* Check if the Single Logout procedure is initated by an SP (alternatively IdP initiated SLO
*/
if (array_key_exists('Issuer', $logoutInfo)) {
$spEntityId = $logoutInfo['Issuer'];
$spMetadata = $metadata->getMetadataConfig($spEntityId, 'saml20-sp-remote');
$lr = sspmod_saml2_Message::buildLogoutResponse($idpMetadata, $spMetadata);
$lr->setInResponseTo($logoutInfo['RequestID']);
$lr->setRelayState($logoutInfo['RelayState']);
$binding = new SAML2_HTTPRedirect();
$binding->setDestination(sspmod_SAML2_Message::getDebugDestination());
$binding->send($lr);
} elseif (array_key_exists('RelayState', $logoutInfo)) {
SimpleSAML_Utilities::redirect($logoutInfo['RelayState']);
exit;
} else {
echo 'You are logged out'; exit;
}
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATELOGOUTRESPONSE', $exception);
sspmod_saml_IdP_SAML2::receiveLogoutMessage($idp);
}
assert('FALSE');
......@@ -11,444 +11,10 @@
require_once('../../_include.php');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrame: Accessing SAML 2.0 IdP endpoint SingleLogoutService (iFrame version)');
SimpleSAML_Logger::debug('Initially; ' . join(',', $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE)));
if (!$config->getBoolean('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError(isset($session) ? $session->getTrackID() : null, 'NOACCESS');
try {
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idpMetadata = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted');
} catch (Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: Got IdP entity id: ' . $idpentityid);
$logouttype = 'traditional';
$idpmeta = $metadata->getMetaDataCurrent('saml20-idp-hosted');
if (array_key_exists('logouttype', $idpmeta)) $logouttype = $idpmeta['logouttype'];
if ($logouttype !== 'iframe')
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS', new Exception('This IdP is configured to use logout type [' . $logouttype . '], but this endpoint is only available for IdP using logout type [iframe]'));
/**
* The $logoutInfo contains information about the current logout operation.
* It can have the following attributes:
* - 'RelayState' - The RelayState which should be returned to the SP which initiated the logout operation.
* - 'Issuer' - The entity id of the SP which initiated the logout operation.
* - 'RequestID' - The id of the LogoutRequest which initiated the logout operation.
*/
$logoutInfo = array();
/**
* This function retrieves the logout info with the given ID.
*
* @param $id The identifier of the logout info.
*/
function fetchLogoutInfo($id) {
global $session;
global $logoutInfo;
$logoutInfo = $session->getData('idplogoutresponsedata', $id);
if($logoutInfo === NULL) {
SimpleSAML_Logger::warning('SAML2.0 - IdP.SingleLogoutService: Lost logout information.');
}
}
/**
* This function saves the logout info with the given ID.
*
* @param $id The identifier the logout info should be saved with.
*/
function saveLogoutInfo($id) {
global $session;
global $logoutInfo;
$session->setData('idplogoutresponsedata', $id, $logoutInfo);
}
// Include XAJAX definition.
require_once(SimpleSAML_Utilities::resolvePath('libextinc') . '/xajax/xajax.inc.php');
/*
* This function is called via AJAX and will send LogoutRequest to one single SP by
* sending a LogoutRequest using HTTP-REDIRECT
*/
function updateslostatus() {
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrame: Accessing SAML 2.0 IdP endpoint SingleLogoutService (iFrame version) within updateslostatus() ');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$templistofsps = $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE);
$listofsps = array();
foreach ($templistofsps AS $spentityid) {
if (!empty($_COOKIE['spstate-' . sha1($spentityid)])) {
$listofsps[] = $spentityid;
continue;
}
try {
$spMetadata = $metadata->getMetaDataConfig($spentityid, 'saml20-sp-remote');
} catch (Exception $e) {
/*
* For some reason, the metadata for this SP is no longer available. Most
* likely it was deleted from the IdP while the user had a session to it.
* In any case - skip this SP.
*/
$listofsps[] = $spentityid;
continue;
}
$singleLogoutService = $spMetadata->getDefaultEndpoint('SingleLogoutService', array(SAML2_Const::BINDING_HTTP_REDIRECT), NULL);
if ($singleLogoutService === NULL) {
/* No logout endpoint. */
$listofsps[] = $spentityid;
continue;
}
/* This SP isn't ready yet. */
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: templistofsps ' . join(',', $templistofsps));
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: listofsps ' . join(',', $listofsps));
// Using template object to be able to translate name of service provider.
$t = new SimpleSAML_XHTML_Template($config, 'logout-iframe.php');
// Instantiate the xajaxResponse object
$objResponse = new xajaxResponse();
foreach ($listofsps AS $spentityid) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: Completed ' . $spentityid);
// add a command to the response to assign the innerHTML attribute of
// the element with id="SomeElementId" to whatever the new content is
try {
$spmetadata = $metadata->getMetaData($spentityid, 'saml20-sp-remote');
} catch (Exception $e) {
/*
* For some reason, the metadata for this SP is no longer available. Most
* likely it was deleted from the IdP while the user had a session to it.
* In any case - skip this SP.
*/
continue;
}
$name = array_key_exists('name', $spmetadata) ? $spmetadata['name'] : $spentityid;
$spname = is_array($name) ? $t->getTranslation($name) : $name;
$objResponse->addScriptCall('slocompletesp', 'e' . sha1($spentityid));
}
if (count($templistofsps) === count($listofsps)) {
$templistofsps = $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE);
foreach ($templistofsps AS $spentityid) {
$session->set_sp_logout_completed($spentityid);
setcookie('spstate-' . sha1($spentityid) , '', time() - 3600); // Delete cookie
}
$objResponse->addScriptCall('slocompleted');
/**
* Clean up session object to save storage.
*/
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size before cleaning: ' . $session->getSize());
$session->clean();
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size after cleaning: ' . $session->getSize());
} else {
SimpleSAML_Logger::debug('SAML2.0 - sp_logout_completed FALSE');
}
//return the xajaxResponse object
return $objResponse;
}
$xajax = new xajax();
$xajax->registerFunction("updateslostatus");
$xajax->processRequests();
/*
* If we get an LogoutRequest then we initiate the logout process.
*/
if (isset($_REQUEST['SAMLRequest'])) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Got SAML reuqest');
$binding = SAML2_Binding::getCurrentBinding();
try {
$logoutrequest = $binding->receive();
if (!($logoutrequest instanceof SAML2_LogoutRequest)) {
throw new Exception('Not a valid logout request.');
}
$spEntityId = $logoutrequest->getIssuer();
if ($spEntityId === NULL) {
throw new Exception('Missing issuer in logout request.');
}
$spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
sspmod_saml2_Message::validateMessage($spMetadata, $idpMetadata, $logoutrequest);
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTREQUEST', $exception);
}
/* Log a warning if the NameID in the LogoutRequest isn't the one we assigned to the SP. */
$requestNameId = $logoutrequest->getNameId();
ksort($requestNameId);
$sessionNameId = $session->getSessionNameId('saml20-sp-remote', $spEntityId);
ksort($sessionNameId);
if ($sessionNameId !== NULL && $requestNameId !== $sessionNameId) {
SimpleSAML_Logger::warning('Wrong NameID in LogoutRequest from ' .
var_export($spEntityId, TRUE) . '.');
}
/* Log a warning if the SessionIndex in the LogoutRequest isn't correct. */
$requestSessionIndex = $logoutrequest->getSessionIndex();
$sessionSessionIndex = $session->getSessionIndex();
if ($requestSessionIndex !== $sessionSessionIndex) {
SimpleSAML_Logger::warning('Wrong SessionIndex in LogoutRequest from ' .
var_export($spEntityId, TRUE) . '.');
}
// Extract some parameters from the logout request
#$requestid = $logoutrequest->getRequestID();
$requester = $logoutrequest->getIssuer();
#$relayState = $logoutrequest->getRelayState();
$responder = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: got Logoutrequest from ' . $logoutrequest->getIssuer());
SimpleSAML_Logger::stats('saml20-idp-SLO spinit ' . $requester . ' ' . $responder);
$session->doLogout();
/* Fill in the $logoutInfo associative array with information about this logout request. */
$logoutInfo['Issuer'] = $logoutrequest->getIssuer();
$logoutInfo['RequestID'] = $logoutrequest->getId();
$relayState = $logoutrequest->getRelayState();
if($relayState !== NULL) {
$logoutInfo['RelayState'] = $relayState;
}
SimpleSAML_Logger::debug('SAML2.0 - IDP.SingleLogoutService: Setting cached request with issuer ' . $logoutrequest->getIssuer());
$session->set_sp_logout_completed($logoutrequest->getIssuer());
/*
* We receive a Logout Response to a Logout Request that we have issued earlier.
* If so, there is a misconfiguration.
*/
} elseif (isset($_REQUEST['SAMLResponse'])) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTRESPONSE',
new Exception('The SP is likely to be misconfigured. The LogoutResponse is sent to wrong endpoint. This iFrame endpoint only accepts LogoutRequests, and the response is to be sent to a separate endpoint. Please revisit the IdP-Remote metadata on the SP.')
);
} else {
/*
* We have no idea what to do here. It is neither a logout request, a logout
* response nor a response from bridged SLO.
*/
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: No request, response or bridge');
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SLOSERVICEPARAMS');
}
// Debug entries in the log about what services the user is logged into.
$session->dump_sp_sessions();
/*
* Generate a list of all service providers, and create a LogoutRequest message for all these SPs.
*/
$listofsps = $session->get_sp_list();
$sparray = array();
$sparrayNoLogout = array();
foreach ($listofsps AS $spentityid) {
// ($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) {
$nameId = $session->getSessionNameId('saml20-sp-remote', $spentityid);
if($nameId === NULL) {
$nameId = $session->getNameID();
}
try {
$spMetadata = $metadata->getMetaDataConfig($spentityid, 'saml20-sp-remote');
} catch (Exception $e) {
/*
* For some reason, the metadata for this SP is no longer available. Most
* likely it was deleted from the IdP while the user had a session to it.
* In any case - skip this SP.
*/
continue;
}
$name = $spMetadata->getValue('name', $spentityid);
try {
$lr = sspmod_saml2_Message::buildLogoutRequest($idpMetadata, $spMetadata);
$lr->setSessionIndex($session->getSessionIndex());
$lr->setNameId($nameId);
$httpredirect = new SAML2_HTTPRedirect();
$url = $httpredirect->getRedirectURL($lr);
$sparray[$spentityid] = array('url' => $url, 'name' => $name);
/* Add the SP logout request information to the session so that we can check it later. */
$requestInfo = array(
'ID' => $lr->getId(),
'RelayState' => $lr->getRelayState(),
);
$session->setData('slo-request-info', $spentityid, $requestInfo, 15*60);
} catch (Exception $e) {
$sparrayNoLogout[$spentityid] = array('name' => $name);
}
}
SimpleSAML_Logger::debug('SAML2.0 - SP Counter. other SPs with SLO support (' . count($sparray) . ') without SLO support (' . count($sparrayNoLogout) . ')');
#print_r($sparray);
/*
* Logout procedure is done and we send a Logout Response back to the SP
*/
try {
if(!$logoutInfo) SimpleSAML_Utilities::fatalError($session->getTrackID(), 'LOGOUTINFOLOST');
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutService: Found logout info with these keys: ' . join(',', array_keys($logoutInfo)));
/*
* Check if the Single Logout procedure is initated by an SP (alternatively IdP initiated SLO)
*/
if (array_key_exists('Issuer', $logoutInfo)) {
$spMetadata = $metadata->getMetaDataConfig($logoutInfo['Issuer'], 'saml20-sp-remote');
// Find the relaystate if cached.
$relayState = isset($logoutInfo['RelayState']) ? $logoutInfo['RelayState'] : null;
/* Create a Logout Response. */
$rg = sspmod_saml2_Message::buildLogoutResponse($idpMetadata, $spMetadata);
$rg->setInResponseTo($logoutInfo['RequestID']);
$rg->setRelayState($relayState);
$httpredirect = new SAML2_HTTPRedirect();
/*
* If the user is not logged into any other SPs, send the LogoutResponse immediately
*/
if (count($sparray) + count($sparrayNoLogout) === 0) {
$httpredirect->setDestination(sspmod_SAML2_Message::getDebugDestination());
$httpredirect->send($rg);
} else {
$logoutresponse = $httpredirect->getRedirectURL($rg);
}
} elseif (array_key_exists('RelayState', $logoutInfo)) {
SimpleSAML_Utilities::redirect($logoutInfo['RelayState']);
exit;
} else {
echo 'You are logged out'; exit;
}
} catch(Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'GENERATELOGOUTRESPONSE', $exception);
}
$spmeta = $metadata->getMetaData($requester, 'saml20-sp-remote');
$spname = $requester;
if (array_key_exists('name', $spmeta)) $spname = $spmeta['name'];
$et = new SimpleSAML_XHTML_Template($config, 'logout-iframe.php');
$et->data['header'] = 'Logout';
$et->data['sparray'] = $sparray;
$et->data['sparrayNoLogout'] = $sparrayNoLogout;
$et->data['logoutresponse'] = $logoutresponse;
$et->data['xajax'] = $xajax;
$et->data['requesterName'] = $spname;
$et->data['head'] = $xajax->getJavascript();
$et->show();
exit(0);
?>
\ No newline at end of file
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId);
sspmod_saml_IdP_SAML2::receiveLogoutMessage($idp);
assert('FALSE');
<?php
/**
* This SAML 2.0 endpoint can receive incoming LogoutRequests. It will also send LogoutResponses,
* and LogoutRequests and also receive LogoutResponses. It is implemeting SLO at the SAML 2.0 IdP.
*
* @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
* @package simpleSAMLphp
* @version $Id$
*/
require_once('../../_include.php');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrame: Accessing SAML 2.0 IdP endpoint SingleLogoutService (iFrame version)');
if (!$config->getBoolean('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError(isset($session) ? $session->getTrackID() : null, 'NOACCESS');
try {
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
} catch (Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: Got IdP entity id: ' . $idpentityid);
$logouttype = 'traditional';
$idpmeta = $metadata->getMetaDataCurrent('saml20-idp-hosted');
if (array_key_exists('logouttype', $idpmeta)) $logouttype = $idpmeta['logouttype'];
if ($logouttype !== 'iframe')
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS', new Exception('This IdP is configured to use logout type [' . $logouttype . '], but this endpoint is only available for IdP using logout type [iframe]'));
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrameNoJavascript: Accessing SAML 2.0 IdP endpoint SingleLogoutService (iFrame version without javascript support) ');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$templistofsps = $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE);
$listofsps = array();
foreach ($templistofsps AS $spentityid) {
if (!empty($_COOKIE['spstate-' . sha1($spentityid)])) $listofsps[] = $spentityid;
}
if (count($templistofsps) === count($listofsps)) {
$templistofsps = $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE);
foreach ($templistofsps AS $spentityid) {
$session->set_sp_logout_completed($spentityid);
setcookie('spstate-' . sha1($spentityid) , '', time() - 3600); // Delete cookie
}
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.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>Logout Update notificator for Non-Javascript Single Log-Out</title>
</head>
<body>
<p>You are successfully logged out. [ <a target="_top" href="' . htmlentities($_REQUEST['response']) . '">Continue</a> ]</p>
</body>
</html>
';
} else {
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.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" />
<meta http-equiv="refresh" content="3;url=SingleLogoutServiceiFrameNoJavascript.php?response=' . urlencode($_REQUEST['response']) . '" />
<title>Logout Update notificator for Non-Javascript Single Log-Out</title>
</head>
<body>
<p>
<img style="float: left; margin: 3px" src="/' . $config->getBaseURL() . 'resources/progress.gif" alt="Progress bar" />
Logout in progress. [ <a target="_top" href="' . htmlentities($_REQUEST['response']) . '">Interrupt</a> ]</p>
</body>
</html>
';
}
?>
\ No newline at end of file
......@@ -11,79 +11,10 @@
require_once('../../_include.php');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrameResponse: Accessing SAML 2.0 IdP endpoint SingleLogoutServiceResponse (iFrame version)');
if (!$config->getBoolean('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError(isset($session) ? $session->getTrackID() : null, 'NOACCESS');
try {
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
} catch (Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: Got IdP entity id: ' . $idpEntityId);
$logouttype = $idpMetadata->getString('logouttype', 'traditional');
if ($logouttype !== 'iframe')
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS', new Exception('This IdP is configured to use logout type [' . $logouttype . '], but this endpoint is only available for IdP using logout type [iframe]'));
if (!isset($_REQUEST['SAMLResponse'])) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SLOSERVICEPARAMS',
new Exception('No valid SAMLResponse found? Probably some error in remote partys metadata that sends something to this endpoint that is not SAML LogoutResponses') );
}
$binding = SAML2_Binding::getCurrentBinding();;
$logoutResponse = $binding->receive();;
if (!($logoutResponse instanceof SAML2_LogoutResponse)) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SLOSERVICEPARAMS',
new Exception('Message received on response endpoint wasn\'t a response. Was: ' . get_class($logoutResponse)));
}
$spEntityId = $logoutResponse->getIssuer();
if ($spEntityId === NULL) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'SLOSERVICEPARAMS',
new Exception('Missing issuer on logout response.'));
}
$spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
sspmod_saml2_Message::validateMessage($spMetadata, $idpMetadata, $logoutResponse);
/*
* Check the logout response against the logout request, and log
* warnings if there is a mismatch.
*/
$requestInfo = $session->getData('slo-request-info', $spEntityId);
if ($requestInfo !== NULL) {
if ($logoutResponse->getInResponseTo() !== $requestInfo['ID']) {
SimpleSAML_Logger::warning('Wrong InResponseTo in LogoutResponse from ' .
var_export($spEntityId, TRUE) . '.');
}
if ($logoutResponse->getRelayState() !== $requestInfo['RelayState']) {
SimpleSAML_Logger::warning('Wrong RelayState in LogoutResponse from ' .
var_export($spEntityId, TRUE) . '.');
}
}
$sphash = sha1($spEntityId);
setcookie('spstate-' . $sphash , '1'); // Duration: 2 hours
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrameResponse: Logging out completed');
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.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>Logout OK</title>
</head>
<body>OK</body>
</html>';
?>
\ No newline at end of file
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId);
sspmod_saml_IdP_SAML2::receiveLogoutMessage($idp);
assert('FALSE');
......@@ -10,277 +10,13 @@
require_once('../../_include.php');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
SimpleSAML_Logger::info('SAML2.0 - IdP.idpInitSingleLogoutServiceiFrame: Accessing SAML 2.0 IdP endpoint SingleLogoutService (iFrame version)');
SimpleSAML_Logger::debug('Initially; ' . join(',', $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE)));
if (!$config->getBoolean('enable.saml20-idp', false))
SimpleSAML_Utilities::fatalError(isset($session) ? $session->getTrackID() : null, 'NOACCESS');
try {
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idpMetadata = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted');
} catch (Exception $exception) {
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'METADATA', $exception);
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: Got IdP entity id: ' . $idpentityid);
$logouttype = 'traditional';
$idpmeta = $metadata->getMetaDataCurrent('saml20-idp-hosted');
if (array_key_exists('logouttype', $idpmeta)) $logouttype = $idpmeta['logouttype'];
if ($logouttype !== 'iframe')
SimpleSAML_Utilities::fatalError($session->getTrackID(), 'NOACCESS', new Exception('This IdP is configured to use logout type [' . $logouttype . '], but this endpoint is only available for IdP using logout type [iframe]'));
/**
* This function retrieves the logout info with the given ID.
*
* @param $id The identifier of the logout info.
*/
function fetchLogoutInfo($id) {
global $session;
global $logoutInfo;
$logoutInfo = $session->getData('idplogoutresponsedata', $id);
if($logoutInfo === NULL) {
SimpleSAML_Logger::warning('SAML2.0 - IdP.SingleLogoutService: Lost logout information.');
}
}
/**
* This function saves the logout info with the given ID.
*
* @param $id The identifier the logout info should be saved with.
*/
function saveLogoutInfo($id) {
global $session;
global $logoutInfo;
$session->setData('idplogoutresponsedata', $id, $logoutInfo);
}
// Include XAJAX definition.
require_once(SimpleSAML_Utilities::resolvePath('libextinc') . '/xajax/xajax.inc.php');
/*
* This function is called via AJAX and will send LogoutRequest to one single SP by
* sending a LogoutRequest using HTTP-REDIRECT
*/
function updateslostatus() {
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutServiceiFrame: Accessing SAML 2.0 IdP endpoint SingleLogoutService (iFrame version) within updateslostatus() ');
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
$session = SimpleSAML_Session::getInstance();
$idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$templistofsps = $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE);
$listofsps = array();
foreach ($templistofsps AS $spentityid) {
if (!empty($_COOKIE['spstate-' . sha1($spentityid)])) {
$listofsps[] = $spentityid;
continue;
}
try {
$spMetadata = $metadata->getMetaDataConfig($spentityid, 'saml20-sp-remote');
} catch (Exception $e) {
/*
* For some reason, the metadata for this SP is no longer available. Most
* likely it was deleted from the IdP while the user had a session to it.
* In any case - skip this SP.
*/
$listofsps[] = $spentityid;
continue;
}
$singleLogoutService = $spMetadata->getDefaultEndpoint('SingleLogoutService', array(SAML2_Const::BINDING_HTTP_REDIRECT), NULL);
if ($singleLogoutService === NULL) {
/* No logout endpoint. */
$listofsps[] = $spentityid;
continue;
}
/* This SP isn't ready yet. */
}
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: templistofsps ' . join(',', $templistofsps));
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: listofsps ' . join(',', $listofsps));
// Using template object to be able to translate name of service provider.
$t = new SimpleSAML_XHTML_Template($config, 'logout-iframe.php');
// Instantiate the xajaxResponse object
$objResponse = new xajaxResponse();
foreach ($listofsps AS $spentityid) {
SimpleSAML_Logger::debug('SAML2.0 - IdP.SingleLogoutServiceiFrame: Completed ' . $spentityid);
// add a command to the response to assign the innerHTML attribute of
// the element with id="SomeElementId" to whatever the new content is
$spmetadata = $metadata->getMetaData($spentityid, 'saml20-sp-remote');
$name = array_key_exists('name', $spmetadata) ? $spmetadata['name'] : $spentityid;
$spname = is_array($name) ? $t->getTranslation($name) : $name;
$objResponse->addScriptCall('slocompletesp', 'e' . sha1($spentityid));
}
if (count($templistofsps) === count($listofsps)) {
$templistofsps = $session->get_sp_list(SimpleSAML_Session::STATE_ONLINE);
foreach ($templistofsps AS $spentityid) {
$session->set_sp_logout_completed($spentityid);
setcookie('spstate-' . sha1($spentityid) , '', time() - 3600); // Delete cookie
}
$objResponse->addScriptCall('slocompleted');
/**
* Clean up session object to save storage.
*/
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size before cleaning: ' . $session->getSize());
$session->clean();
if ($config->getBoolean('debug', false))
SimpleSAML_Logger::info('SAML2.0 - IdP.SingleLogoutService: Session Size after cleaning: ' . $session->getSize());
} else {
SimpleSAML_Logger::debug('SAML2.0 - sp_logout_completed FALSE');
}
//return the xajaxResponse object
return $objResponse;
}
$xajax = new xajax();
$xajax->registerFunction("updateslostatus");
$xajax->processRequests();
/**
* Which URL to send the user to after logout?
*/
$relayState = NULL;
if (array_key_exists('RelayState', $_REQUEST)) $relayState = $_REQUEST['RelayState'];
// Do logout from the IdP
$session->doLogout();
// Debug entries in the log about what services the user is logged into.
$session->dump_sp_sessions();
/*
* Generate a list of all service providers, and create a LogoutRequest message for all these SPs.
*/
$listofsps = $session->get_sp_list();
$sparray = array();
$sparrayNoLogout = array();
foreach ($listofsps AS $spentityid) {
// ($issuer, $receiver, $nameid, $nameidformat, $sessionindex, $mode) {
$nameId = $session->getSessionNameId('saml20-sp-remote', $spentityid);
if($nameId === NULL) {
$nameId = $session->getNameID();
}
$spMetadata = $metadata->getMetaDataConfig($spentityid, 'saml20-sp-remote');
$name = $spMetadata->getValue('name', $spentityid);
try {
$lr = sspmod_saml2_Message::buildLogoutRequest($idpMetadata, $spMetadata);
$lr->setSessionIndex($session->getSessionIndex());
$lr->setNameId($nameId);
$httpredirect = new SAML2_HTTPRedirect();
$url = $httpredirect->getRedirectURL($lr);
$sparray[$spentityid] = array('url' => $url, 'name' => $name);
/* Add the SP logout request information to the session so that we can check it later. */
$requestInfo = array(
'ID' => $lr->getId(),
'RelayState' => $lr->getRelayState(),
);
$session->setData('slo-request-info', $spentityid, $requestInfo, 15*60);
} catch (Exception $e) {
$sparrayNoLogout[$spentityid] = array('name' => $name);
}
$idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
$idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId);
if (!isset($_REQUEST['RelayState'])) {
throw new SimpleSAML_Error_BadRequest('Missing required RelayState parameter.');
}
SimpleSAML_Logger::debug('SAML2.0 - SP Counter. other SPs with SLO support (' . count($sparray) . ') without SLO support (' . count($sparrayNoLogout) . ')');
#print_r($sparray);
/*
* If the user is not logged into any other SPs.
*/
if (count($sparray) + count($sparrayNoLogout) === 0) {
SimpleSAML_Utilities::redirect($relayState);
exit;
}
$et = new SimpleSAML_XHTML_Template($config, 'logout-iframe.php');
$et->data['header'] = 'Logout';
$et->data['sparray'] = $sparray;
$et->data['sparrayNoLogout'] = $sparrayNoLogout;
$et->data['logoutresponse'] = $relayState;
$et->data['xajax'] = $xajax;
#$et->data['idpInitRelayState'] = $relayState;
# $et->data['requesterName'] = $spname;
$et->data['head'] = $xajax->getJavascript();
$et->show();
exit(0);
?>
\ No newline at end of file
$idp->doLogoutRedirect((string)$_REQUEST['RelayState']);
assert('FALSE');
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment