moodle/auth/shibboleth/logout.php

209 lines
7.0 KiB
PHP
Raw Normal View History

<?php
// Implements logout for Shibboleth authenticated users according to:
// - https://spaces.internet2.edu/display/SHIB2/NativeSPLogoutInitiator
// - https://spaces.internet2.edu/display/SHIB2/NativeSPNotify
require_once("../../config.php");
require_once($CFG->dirroot."/auth/shibboleth/auth.php");
2009-03-18 13:28:57 +00:00
// Find out whether host supports https
$protocol = 'http://';
if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'){
2011-01-24 16:20:30 +08:00
$protocol = 'https://';
}
2009-03-18 13:28:57 +00:00
// Front channel logout
if (
isset($_GET['return'])
2009-03-18 13:28:57 +00:00
&& isset($_GET['action'])
&& $_GET['action'] == 'logout'
){
2009-03-18 13:28:57 +00:00
// Logout out user from application
// E.g. destroy application session/cookie etc
require_logout();
2009-03-18 13:28:57 +00:00
// Finally, send user to the return URL
redirect($_GET['return']);
}
// Back channel logout
elseif (!empty($HTTP_RAW_POST_DATA)) {
2009-03-18 13:28:57 +00:00
// Requires PHP 5
2009-03-18 13:28:57 +00:00
// Set SOAP header
$server = new SoapServer($protocol.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'/LogoutNotification.wsdl');
2009-03-18 13:28:57 +00:00
$server->addFunction("LogoutNotification");
$server->handle();
}
// Return WSDL
else {
2009-03-18 13:28:57 +00:00
header('Content-Type: text/xml');
2009-03-18 13:28:57 +00:00
echo <<<WSDL
<?xml version ="1.0" encoding ="UTF-8" ?>
<definitions name="LogoutNotification"
targetNamespace="urn:mace:shibboleth:2.0:sp:notify"
xmlns:notify="urn:mace:shibboleth:2.0:sp:notify"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!--
This page either has to be called with the GET arguments 'action' and 'return' via
a redirect from the Shibboleth Service Provider logout handler (front-channel
logout) or via a SOAP request by a Shibboleth Service Provider (back-channel
logout).
Because neither of these two variants seems to be the case, the WSDL file for
the web service is returned.
For more information see:
- https://spaces.internet2.edu/display/SHIB2/NativeSPLogoutInitiator
- https://spaces.internet2.edu/display/SHIB2/NativeSPNotify
-->
2009-03-18 13:28:57 +00:00
<types>
<schema targetNamespace="urn:mace:shibboleth:2.0:sp:notify"
xmlns="http://www.w3.org/2000/10/XMLSchema"
xmlns:notify="urn:mace:shibboleth:2.0:sp:notify">
2009-03-18 13:28:57 +00:00
<simpleType name="string">
<restriction base="string">
<minLength value="1"/>
</restriction>
</simpleType>
2009-03-18 13:28:57 +00:00
<element name="OK" type="notify:OKType"/>
<complexType name="OKType">
<sequence/>
</complexType>
2009-03-18 13:28:57 +00:00
</schema>
</types>
2009-03-18 13:28:57 +00:00
<message name="getLogoutNotificationRequest">
<part name="SessionID" type="notify:string" />
</message>
2009-03-18 13:28:57 +00:00
<message name="getLogoutNotificationResponse" >
<part name="OK"/>
</message>
2009-03-18 13:28:57 +00:00
<portType name="LogoutNotificationPortType">
<operation name="LogoutNotification">
<input message="getLogoutNotificationRequest"/>
<output message="getLogoutNotificationResponse"/>
</operation>
</portType>
2009-03-18 13:28:57 +00:00
<binding name="LogoutNotificationBinding" type="notify:LogoutNotificationPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="LogoutNotification">
<soap:operation soapAction="urn:xmethods-logout-notification#LogoutNotification"/>
</operation>
</binding>
2009-03-18 13:28:57 +00:00
<service name="LogoutNotificationService">
<port name="LogoutNotificationPort" binding="notify:LogoutNotificationBinding">
<soap:address location="{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}"/>
</port>
</service>
</definitions>
WSDL;
2009-03-18 13:28:57 +00:00
exit;
}
/******************************************************************************/
function LogoutNotification($SessionID){
global $CFG, $SESSION, $DB;
2009-03-18 13:28:57 +00:00
// Delete session of user using $SessionID
if(empty($CFG->dbsessions)) {
2009-03-18 13:28:57 +00:00
// File session
$dir = $CFG->dataroot .'/sessions';
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
// Read all session files
while (($file = readdir($dh)) !== false) {
// Check if it is a file
if (is_file($dir.'/'.$file)){
$session_key = preg_replace('/sess_/', '', $file);
2009-03-18 13:28:57 +00:00
// Read session file data
$data = file($dir.'/'.$file);
if (isset($data[0])){
$user_session = unserializesession($data[0]);
// Check if we have found session that shall be deleted
2009-03-18 13:28:57 +00:00
if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){
2009-03-18 13:28:57 +00:00
// If there is a match, delete file
if ($user_session['SESSION']->shibboleth_session_id == $SessionID){
// Delete session file
if (!unlink($dir.'/'.$file)){
return new SoapFault('LogoutError', 'Could not delete Moodle session file.');
}
}
}
}
}
}
closedir($dh);
}
}
} else {
// DB Session
//TODO: this needs to be rewritten to use new session stuff
2009-03-18 13:28:57 +00:00
if (!empty($CFG->sessiontimeout)) {
$ADODB_SESS_LIFE = $CFG->sessiontimeout;
}
if ($user_session_data = $DB->get_records_sql('SELECT sesskey, sessdata FROM {sessions2} WHERE expiry > NOW()')) {
2009-03-18 13:28:57 +00:00
foreach ($user_session_data as $session_data) {
2009-03-18 13:28:57 +00:00
// Get user session
$user_session = adodb_unserialize( urldecode($session_data->sessdata) );
2009-03-18 13:28:57 +00:00
if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){
2009-03-18 13:28:57 +00:00
// If there is a match, delete file
if ($user_session['SESSION']->shibboleth_session_id == $SessionID){
// Delete this session entry
if (ADODB_Session::destroy($session_data->sesskey) !== true){
return new SoapFault('LogoutError', 'Could not delete Moodle session entry in database.');
}
}
}
}
}
}
2009-03-18 13:28:57 +00:00
// If now SoapFault was thrown the function will return OK as the SP assumes
}
/*****************************************************************************/
// Same function as in adodb, but cannot be used for file session for some reason...
function unserializesession($serialized_string) {
$variables = array();
$a = preg_split("/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$counta = count($a);
2011-01-24 16:20:30 +08:00
for ($i = 0; $i < $counta; $i = $i+2) {
$variables[$a[$i]] = unserialize($a[$i+1]);
2009-03-18 13:28:57 +00:00
}
2011-01-24 16:20:30 +08:00
return $variables;
}