ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
LogoutStore.php
Go to the documentation of this file.
1<?php
2
9{
15 private static function createLogoutTable(\SimpleSAML\Store\SQL $store)
16 {
17 $tableVer = $store->getTableVersion('saml_LogoutStore');
18 if ($tableVer === 2) {
19 return;
20 } elseif ($tableVer === 1) {
21 /* TableVersion 2 increased the column size to 255 which is the maximum length of a FQDN. */
22 switch ($store->driver) {
23 case 'pgsql':
24 // This does not affect the NOT NULL constraint
25 $query = 'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore ALTER COLUMN _authSource TYPE VARCHAR(255)';
26 break;
27 default:
28 $query = 'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore MODIFY _authSource VARCHAR(255) NOT NULL';
29 break;
30 }
31
32 try {
33 $store->pdo->exec($query);
34 } catch (Exception $e) {
35 SimpleSAML\Logger::warning($store->pdo->errorInfo());
36 return;
37 }
38 $store->setTableVersion('saml_LogoutStore', 2);
39 return;
40 }
41
42 $query = 'CREATE TABLE ' . $store->prefix . '_saml_LogoutStore (
43 _authSource VARCHAR(255) NOT NULL,
44 _nameId VARCHAR(40) NOT NULL,
45 _sessionIndex VARCHAR(50) NOT NULL,
46 _expire TIMESTAMP NOT NULL,
47 _sessionId VARCHAR(50) NOT NULL,
48 UNIQUE (_authSource, _nameID, _sessionIndex)
49 )';
50 $store->pdo->exec($query);
51
52 $query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_expire ON ' . $store->prefix . '_saml_LogoutStore (_expire)';
53 $store->pdo->exec($query);
54
55 $query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_nameId ON ' . $store->prefix . '_saml_LogoutStore (_authSource, _nameId)';
56 $store->pdo->exec($query);
57
58 $store->setTableVersion('saml_LogoutStore', 2);
59 }
60
61
67 private static function cleanLogoutStore(\SimpleSAML\Store\SQL $store)
68 {
69 SimpleSAML\Logger::debug('saml.LogoutStore: Cleaning logout store.');
70
71 $query = 'DELETE FROM ' . $store->prefix . '_saml_LogoutStore WHERE _expire < :now';
72 $params = array('now' => gmdate('Y-m-d H:i:s'));
73
74 $query = $store->pdo->prepare($query);
75 $query->execute($params);
76 }
77
78
87 private static function addSessionSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId, $sessionIndex, $expire, $sessionId)
88 {
89 assert(is_string($authId));
90 assert(is_string($nameId));
91 assert(is_string($sessionIndex));
92 assert(is_string($sessionId));
93 assert(is_int($expire));
94
96
97 if (rand(0, 1000) < 10) {
99 }
100
101 $data = array(
102 '_authSource' => $authId,
103 '_nameId' => $nameId,
104 '_sessionIndex' => $sessionIndex,
105 '_expire' => gmdate('Y-m-d H:i:s', $expire),
106 '_sessionId' => $sessionId,
107 );
108 $store->insertOrUpdate($store->prefix . '_saml_LogoutStore', array('_authSource', '_nameId', '_sessionIndex'), $data);
109 }
110
111
120 private static function getSessionsSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId)
121 {
122 assert(is_string($authId));
123 assert(is_string($nameId));
124
126
127 $params = array(
128 '_authSource' => $authId,
129 '_nameId' => $nameId,
130 'now' => gmdate('Y-m-d H:i:s'),
131 );
132
133 // We request the columns in lowercase in order to be compatible with PostgreSQL
134 $query = 'SELECT _sessionIndex AS _sessionindex, _sessionId AS _sessionid FROM ' . $store->prefix . '_saml_LogoutStore' .
135 ' WHERE _authSource = :_authSource AND _nameId = :_nameId AND _expire >= :now';
136 $query = $store->pdo->prepare($query);
137 $query->execute($params);
138
139 $res = array();
140 while ( ($row = $query->fetch(PDO::FETCH_ASSOC)) !== false) {
141 $res[$row['_sessionindex']] = $row['_sessionid'];
142 }
143
144 return $res;
145 }
146
147
157 private static function getSessionsStore(\SimpleSAML\Store $store, $authId, $nameId, array $sessionIndexes)
158 {
159 assert(is_string($authId));
160 assert(is_string($nameId));
161
162 $res = array();
163 foreach ($sessionIndexes as $sessionIndex) {
164 $sessionId = $store->get('saml.LogoutStore', $nameId . ':' . $sessionIndex);
165 if ($sessionId === null) {
166 continue;
167 }
168 assert(is_string($sessionId));
169 $res[$sessionIndex] = $sessionId;
170 }
171
172 return $res;
173 }
174
175
189 public static function addSession($authId, $nameId, $sessionIndex, $expire)
190 {
191 assert(is_string($authId));
192 assert(is_string($sessionIndex) || $sessionIndex === null);
193 assert(is_int($expire));
194
195 if ($sessionIndex === null) {
196 /* This IdP apparently did not include a SessionIndex, and thus probably does not
197 * support SLO. We still want to add the session to the data store just in case
198 * it supports SLO, but we don't want an LogoutRequest with a specific
199 * SessionIndex to match this session. We therefore generate our own session index.
200 */
202 }
203
205 if ($store === false) {
206 // We don't have a datastore.
207 return;
208 }
209
210 // serialize and anonymize the NameID
211 // TODO: remove this conditional statement
212 if (is_array($nameId)) {
214 }
215 $strNameId = serialize($nameId);
216 $strNameId = sha1($strNameId);
217
218 /* Normalize SessionIndex. */
219 if (strlen($sessionIndex) > 50) {
221 }
222
224 $sessionId = $session->getSessionId();
225
226 if ($store instanceof \SimpleSAML\Store\SQL) {
227 self::addSessionSQL($store, $authId, $strNameId, $sessionIndex, $expire, $sessionId);
228 } else {
229 $store->set('saml.LogoutStore', $strNameId . ':' . $sessionIndex, $sessionId, $expire);
230 }
231 }
232
233
242 public static function logoutSessions($authId, $nameId, array $sessionIndexes)
243 {
244 assert(is_string($authId));
245
247 if ($store === false) {
248 /* We don't have a datastore. */
249 return false;
250 }
251
252 // serialize and anonymize the NameID
253 // TODO: remove this conditional statement
254 if (is_array($nameId)) {
256 }
257 $strNameId = serialize($nameId);
258 $strNameId = sha1($strNameId);
259
260 /* Normalize SessionIndexes. */
261 foreach ($sessionIndexes as &$sessionIndex) {
262 assert(is_string($sessionIndex));
263 if (strlen($sessionIndex) > 50) {
265 }
266 }
267 unset($sessionIndex); // Remove reference
268
269 if ($store instanceof \SimpleSAML\Store\SQL) {
270 $sessions = self::getSessionsSQL($store, $authId, $strNameId);
271 } elseif (empty($sessionIndexes)) {
272 /* We cannot fetch all sessions without a SQL store. */
273 return false;
274 } else {
276 $sessions = self::getSessionsStore($store, $authId, $strNameId, $sessionIndexes);
277
278 }
279
280 if (empty($sessionIndexes)) {
281 $sessionIndexes = array_keys($sessions);
282 }
283
284 $numLoggedOut = 0;
285 foreach ($sessionIndexes as $sessionIndex) {
286 if (!isset($sessions[$sessionIndex])) {
287 SimpleSAML\Logger::info('saml.LogoutStore: Logout requested for unknown SessionIndex.');
288 continue;
289 }
290
291 $sessionId = $sessions[$sessionIndex];
292
294 if ($session === null) {
295 SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of missing session.');
296 continue;
297 }
298
299 if (!$session->isValid($authId)) {
300 SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of session because it isn\'t authenticated.');
301 continue;
302 }
303
304 SimpleSAML\Logger::info('saml.LogoutStore: Logging out of session with trackId [' . $session->getTrackID() . '].');
305 $session->doLogout($authId);
306 $numLoggedOut += 1;
307 }
308
309 return $numLoggedOut;
310 }
311
312}
An exception for terminatinating execution or to throw for unit testing.
static fromArray(array $nameId)
Create a \SAML2\XML\saml\NameID object from an array with its contents.
Definition: NameIDType.php:87
static info($string)
Definition: Logger.php:199
static warning($string)
Definition: Logger.php:177
static debug($string)
Definition: Logger.php:211
static getInstance()
Retrieve our singleton instance.
Definition: Store.php:31
static generateID()
Generate a random identifier, ID_LENGTH bytes long.
Definition: Random.php:26
static getSession($sessionId=null)
Get a session from the session handler.
Definition: Session.php:315
static getSessionFromRequest()
Retrieves the current session.
Definition: Session.php:241
static addSession($authId, $nameId, $sessionIndex, $expire)
Register a new session in the datastore.
static cleanLogoutStore(\SimpleSAML\Store\SQL $store)
Clean the logout table of expired entries.
Definition: LogoutStore.php:67
static addSessionSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId, $sessionIndex, $expire, $sessionId)
Register a session in the SQL datastore.
Definition: LogoutStore.php:87
static getSessionsSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId)
Retrieve sessions from the SQL datastore.
static getSessionsStore(\SimpleSAML\Store $store, $authId, $nameId, array $sessionIndexes)
Retrieve all session IDs from a key-value store.
static createLogoutTable(\SimpleSAML\Store\SQL $store)
Create logout table in SQL, if it is missing.
Definition: LogoutStore.php:15
if(! $oauthconfig->getBoolean('getUserInfo.enable', FALSE)) $store
Definition: getUserInfo.php:11
$nameId
Definition: saml2-acs.php:138
$expire
Definition: saml2-acs.php:140
$sessionIndex
Definition: saml2-acs.php:139
$row
Attribute-related utility methods.
$query
$session
foreach($_POST as $key=> $value) $res
$data
Definition: bench.php:6