/auth/shibboleth/logout.php
PHP | 204 lines | 136 code | 40 blank | 28 comment | 31 complexity | 8bdb4782adeaa0682e62b38e516331f1 MD5 | raw file
- <?php
- // Implements logout for Shibboleth authenticated users according to:
- // - https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPLogoutInitiator
- // - https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPNotify
- require_once("../../config.php");
- require_once($CFG->dirroot."/auth/shibboleth/auth.php");
- $action = optional_param('action', '', PARAM_ALPHA);
- $redirect = optional_param('return', '', PARAM_URL);
- // Find out whether host supports https
- $protocol = 'http://';
- if (is_https()) {
- $protocol = 'https://';
- }
- // If the shibboleth plugin is not enable, throw an exception.
- if (!is_enabled_auth('shibboleth')) {
- throw new moodle_exception(get_string('pluginnotenabled', 'auth', 'shibboleth'));
- }
- // Front channel logout.
- $inputstream = file_get_contents("php://input");
- if ($action == 'logout' && !empty($redirect)) {
- if (isloggedin($USER) && $USER->auth == 'shibboleth') {
- // Logout user from application.
- require_logout();
- }
- // Finally, send user to the return URL.
- redirect($redirect);
- } else if (!empty($inputstream)) {
- // Back channel logout.
- // Set SOAP header.
- $server = new SoapServer($protocol.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'/LogoutNotification.wsdl');
- $server->addFunction("LogoutNotification");
- $server->handle();
- } else {
- // Return WSDL.
- header('Content-Type: text/xml');
- 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://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPLogoutInitiator
- - https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPNotify
- -->
- <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">
- <simpleType name="string">
- <restriction base="string">
- <minLength value="1"/>
- </restriction>
- </simpleType>
- <element name="OK" type="notify:OKType"/>
- <complexType name="OKType">
- <sequence/>
- </complexType>
- </schema>
- </types>
- <message name="getLogoutNotificationRequest">
- <part name="SessionID" type="notify:string" />
- </message>
- <message name="getLogoutNotificationResponse" >
- <part name="OK"/>
- </message>
- <portType name="LogoutNotificationPortType">
- <operation name="LogoutNotification">
- <input message="getLogoutNotificationRequest"/>
- <output message="getLogoutNotificationResponse"/>
- </operation>
- </portType>
- <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>
- <service name="LogoutNotificationService">
- <port name="LogoutNotificationPort" binding="notify:LogoutNotificationBinding">
- <soap:address location="{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}"/>
- </port>
- </service>
- </definitions>
- WSDL;
- exit;
- }
- /******************************************************************************/
- function LogoutNotification($SessionID){
- global $CFG, $SESSION, $DB;
- // Delete session of user using $SessionID
- if(empty($CFG->dbsessions)) {
- // 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);
- // 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
- if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){
- // 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
- 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()')) {
- foreach ($user_session_data as $session_data) {
- // Get user session
- $user_session = adodb_unserialize( urldecode($session_data->sessdata) );
- if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){
- // 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.');
- }
- }
- }
- }
- }
- }
- // 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);
- for ($i = 0; $i < $counta; $i = $i+2) {
- $variables[$a[$i]] = unserialize($a[$i+1]);
- }
- return $variables;
- }