Commit | Line | Data |
---|---|---|
5117d598 | 1 | <?php |
2db6ec19 | 2 | |
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 | |
6 | ||
7 | require_once("../../config.php"); | |
8 | ||
9 | require_once($CFG->dirroot."/auth/shibboleth/auth.php"); | |
10 | ||
11 | ||
ad9f023c | 12 | // Find out whether host supports https |
13 | $protocol = 'http://'; | |
14 | if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'){ | |
80c12897 | 15 | $protocol = 'https://'; |
5117d598 | 16 | } |
ad9f023c | 17 | |
2db6ec19 | 18 | // Front channel logout |
19 | if ( | |
5117d598 | 20 | isset($_GET['return']) |
ad9f023c | 21 | && isset($_GET['action']) |
22 | && $_GET['action'] == 'logout' | |
2db6ec19 | 23 | ){ |
5117d598 | 24 | |
ad9f023c | 25 | // Logout out user from application |
26 | // E.g. destroy application session/cookie etc | |
27 | require_logout(); | |
5117d598 | 28 | |
ad9f023c | 29 | // Finally, send user to the return URL |
30 | redirect($_GET['return']); | |
2db6ec19 | 31 | } |
32 | ||
33 | // Back channel logout | |
34 | elseif (!empty($HTTP_RAW_POST_DATA)) { | |
5117d598 | 35 | |
ad9f023c | 36 | // Requires PHP 5 |
5117d598 PS |
37 | |
38 | ||
ad9f023c | 39 | // Set SOAP header |
40 | $server = new SoapServer($protocol.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'/LogoutNotification.wsdl'); | |
5117d598 PS |
41 | |
42 | ||
ad9f023c | 43 | $server->addFunction("LogoutNotification"); |
44 | $server->handle(); | |
5117d598 | 45 | } |
2db6ec19 | 46 | |
47 | // Return WSDL | |
48 | else { | |
5117d598 | 49 | |
ad9f023c | 50 | header('Content-Type: text/xml'); |
5117d598 | 51 | |
ad9f023c | 52 | echo <<<WSDL |
2db6ec19 | 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/"> | |
59 | ||
60 | <!-- | |
61 | This page either has to be called with the GET arguments 'action' and 'return' via | |
5117d598 PS |
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 | |
2db6ec19 | 64 | logout). |
5117d598 | 65 | Because neither of these two variants seems to be the case, the WSDL file for |
2db6ec19 | 66 | the web service is returned. |
67 | ||
68 | For more information see: | |
69 | - https://spaces.internet2.edu/display/SHIB2/NativeSPLogoutInitiator | |
70 | - https://spaces.internet2.edu/display/SHIB2/NativeSPNotify | |
71 | --> | |
72 | ||
ad9f023c | 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"> | |
5117d598 | 77 | |
ad9f023c | 78 | <simpleType name="string"> |
79 | <restriction base="string"> | |
80 | <minLength value="1"/> | |
81 | </restriction> | |
82 | </simpleType> | |
5117d598 | 83 | |
ad9f023c | 84 | <element name="OK" type="notify:OKType"/> |
85 | <complexType name="OKType"> | |
86 | <sequence/> | |
87 | </complexType> | |
5117d598 | 88 | |
ad9f023c | 89 | </schema> |
90 | </types> | |
5117d598 | 91 | |
ad9f023c | 92 | <message name="getLogoutNotificationRequest"> |
93 | <part name="SessionID" type="notify:string" /> | |
94 | </message> | |
5117d598 | 95 | |
ad9f023c | 96 | <message name="getLogoutNotificationResponse" > |
97 | <part name="OK"/> | |
98 | </message> | |
5117d598 | 99 | |
ad9f023c | 100 | <portType name="LogoutNotificationPortType"> |
101 | <operation name="LogoutNotification"> | |
102 | <input message="getLogoutNotificationRequest"/> | |
103 | <output message="getLogoutNotificationResponse"/> | |
104 | </operation> | |
105 | </portType> | |
5117d598 | 106 | |
ad9f023c | 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> | |
5117d598 | 113 | |
ad9f023c | 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> | |
2db6ec19 | 119 | </definitions> |
120 | WSDL; | |
ad9f023c | 121 | exit; |
2db6ec19 | 122 | |
123 | } | |
124 | ||
125 | /******************************************************************************/ | |
126 | ||
127 | function LogoutNotification($SessionID){ | |
5117d598 | 128 | |
ffdd703a | 129 | global $CFG, $SESSION, $DB; |
5117d598 | 130 | |
ad9f023c | 131 | // Delete session of user using $SessionID |
132 | if(empty($CFG->dbsessions)) { | |
5117d598 | 133 | |
ad9f023c | 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)){ | |
c78a948e | 142 | $session_key = preg_replace('/sess_/', '', $file); |
5117d598 | 143 | |
ad9f023c | 144 | // Read session file data |
145 | $data = file($dir.'/'.$file); | |
146 | if (isset($data[0])){ | |
147 | $user_session = unserializesession($data[0]); | |
5117d598 PS |
148 | |
149 | // Check if we have found session that shall be deleted | |
ad9f023c | 150 | if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){ |
5117d598 | 151 | |
ad9f023c | 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 | |
cc220229 | 168 | //TODO: this needs to be rewritten to use new session stuff |
ad9f023c | 169 | if (!empty($CFG->sessiontimeout)) { |
170 | $ADODB_SESS_LIFE = $CFG->sessiontimeout; | |
171 | } | |
5117d598 | 172 | |
ffdd703a | 173 | if ($user_session_data = $DB->get_records_sql('SELECT sesskey, sessdata FROM {sessions2} WHERE expiry > NOW()')) { |
ad9f023c | 174 | foreach ($user_session_data as $session_data) { |
5117d598 | 175 | |
ad9f023c | 176 | // Get user session |
177 | $user_session = adodb_unserialize( urldecode($session_data->sessdata) ); | |
5117d598 | 178 | |
ad9f023c | 179 | if (isset($user_session['SESSION']) && isset($user_session['SESSION']->shibboleth_session_id)){ |
5117d598 | 180 | |
ad9f023c | 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 | } | |
5117d598 | 192 | |
ad9f023c | 193 | // If now SoapFault was thrown the function will return OK as the SP assumes |
5117d598 | 194 | |
2db6ec19 | 195 | } |
196 | ||
197 | /*****************************************************************************/ | |
198 | ||
199 | // Same function as in adodb, but cannot be used for file session for some reason... | |
b692e4aa AB |
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); | |
80c12897 | 204 | for ($i = 0; $i < $counta; $i = $i+2) { |
b692e4aa | 205 | $variables[$a[$i]] = unserialize($a[$i+1]); |
ad9f023c | 206 | } |
80c12897 | 207 | return $variables; |
2db6ec19 | 208 | } |