763bf4b4ea3a6df461bd2d926ac869fefc6c9c83
[moodle.git] / auth / shibboleth / logout.php
1 <?php
3 // Implements logout for Shibboleth authenticated users according to:
4 // - https://spaces.internet2.edu/display/SHIB2/NativeSPLogoutInitiator
5 // - https://spaces.internet2.edu/display/SHIB2/NativeSPNotify
7 require_once("../../config.php");
9 require_once($CFG->dirroot."/auth/shibboleth/auth.php");
12 // Find out whether host supports https
13 $protocol = 'http://';
14 if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'){
15         $protocol = 'https://';
16 }
18 // Front channel logout
19 if (
20         isset($_GET['return'])
21         && isset($_GET['action'])
22         && $_GET['action'] == 'logout'
23    ){
25     // Logout out user from application
26     // E.g. destroy application session/cookie etc
27     require_logout();
29     // Finally, send user to the return URL
30     redirect($_GET['return']);
31 }
33 // Back channel logout
34 elseif (!empty($HTTP_RAW_POST_DATA)) {
36     // Requires PHP 5
39     // Set SOAP header
40     $server = new SoapServer($protocol.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'/LogoutNotification.wsdl');
43     $server->addFunction("LogoutNotification");
44     $server->handle();
45 }
47 // Return WSDL
48 else {
50     header('Content-Type: text/xml');
52     echo <<<WSDL
53 <?xml version ="1.0" encoding ="UTF-8" ?>
54 <definitions name="LogoutNotification"
55   targetNamespace="urn:mace:shibboleth:2.0:sp:notify"
56   xmlns:notify="urn:mace:shibboleth:2.0:sp:notify"
57   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
58   xmlns="http://schemas.xmlsoap.org/wsdl/">
60 <!--
61 This page either has to be called with the GET arguments 'action' and 'return' via
62 a redirect from the Shibboleth Service Provider logout handler (front-channel
63 logout) or via a SOAP request by a Shibboleth Service Provider (back-channel
64 logout).
65 Because neither of these two variants seems to be the case, the WSDL file for
66 the web service is returned.
68 For more information see:
69 - https://spaces.internet2.edu/display/SHIB2/NativeSPLogoutInitiator
70 - https://spaces.internet2.edu/display/SHIB2/NativeSPNotify
71 -->
73     <types>
74        <schema targetNamespace="urn:mace:shibboleth:2.0:sp:notify"
75            xmlns="http://www.w3.org/2000/10/XMLSchema"
76            xmlns:notify="urn:mace:shibboleth:2.0:sp:notify">
78             <simpleType name="string">
79                 <restriction base="string">
80                     <minLength value="1"/>
81                 </restriction>
82             </simpleType>
84             <element name="OK" type="notify:OKType"/>
85             <complexType name="OKType">
86                 <sequence/>
87             </complexType>
89         </schema>
90     </types>
92     <message name="getLogoutNotificationRequest">
93         <part name="SessionID" type="notify:string" />
94     </message>
96     <message name="getLogoutNotificationResponse" >
97         <part name="OK"/>
98     </message>
100     <portType name="LogoutNotificationPortType">
101         <operation name="LogoutNotification">
102             <input message="getLogoutNotificationRequest"/>
103             <output message="getLogoutNotificationResponse"/>
104         </operation>
105     </portType>
107     <binding name="LogoutNotificationBinding" type="notify:LogoutNotificationPortType">
108         <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
109         <operation name="LogoutNotification">
110             <soap:operation soapAction="urn:xmethods-logout-notification#LogoutNotification"/>
111         </operation>
112     </binding>
114     <service name="LogoutNotificationService">
115           <port name="LogoutNotificationPort" binding="notify:LogoutNotificationBinding">
116             <soap:address location="{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}"/>
117           </port>
118     </service>
119 </definitions>
120 WSDL;
121     exit;
125 /******************************************************************************/
127 function LogoutNotification($SessionID){
129     global $CFG, $SESSION, $DB;
131     // Delete session of user using $SessionID
132     if(empty($CFG->dbsessions)) {
134         // File session
135         $dir = $CFG->dataroot .'/sessions';
136         if (is_dir($dir)) {
137             if ($dh = opendir($dir)) {
138                 // Read all session files
139                 while (($file = readdir($dh)) !== false) {
140                     // Check if it is a file
141                     if (is_file($dir.'/'.$file)){
142                         $session_key = preg_replace('/sess_/', '', $file);
144                         // Read session file data
145                         $data = file($dir.'/'.$file);
146                         if (isset($data[0])){
147                             $user_session = unserializesession($data[0]);
149                             // Check if we have found session that shall be deleted
150                             if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){
152                                 // If there is a match, delete file
153                                 if ($user_session['SESSION']->shibboleth_session_id == $SessionID){
154                                     // Delete session file
155                                     if (!unlink($dir.'/'.$file)){
156                                         return new SoapFault('LogoutError', 'Could not delete Moodle session file.');
157                                     }
158                                 }
159                             }
160                         }
161                     }
162                 }
163                 closedir($dh);
164             }
165         }
166     } else {
167         // DB Session
168         //TODO: this needs to be rewritten to use new session stuff
169         if (!empty($CFG->sessiontimeout)) {
170             $ADODB_SESS_LIFE   = $CFG->sessiontimeout;
171         }
173             if ($user_session_data = $DB->get_records_sql('SELECT sesskey, sessdata FROM {sessions2} WHERE expiry > NOW()')) {
174             foreach ($user_session_data as $session_data) {
176                 // Get user session
177                 $user_session = adodb_unserialize( urldecode($session_data->sessdata) );
179                 if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){
181                     // If there is a match, delete file
182                     if ($user_session['SESSION']->shibboleth_session_id == $SessionID){
183                         // Delete this session entry
184                         if (ADODB_Session::destroy($session_data->sesskey) !== true){
185                             return new SoapFault('LogoutError', 'Could not delete Moodle session entry in database.');
186                         }
187                     }
188                 }
189             }
190         }
191     }
193     // If now SoapFault was thrown the function will return OK as the SP assumes
197 /*****************************************************************************/
199 // Same function as in adodb, but cannot be used for file session for some reason...
200 function unserializesession($serialized_string) {
201     $variables = array();
202     $a = preg_split("/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
203     $counta = count($a);
204     for($i = 0; $i < $counta; $i=$i+2) {
205             $variables[$a[$i]] = unserialize($a[$i+1]);
206     }
207     return($variables);