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 
95  self::createLogoutTable($store);
96 
97  if (rand(0, 1000) < 10) {
98  self::cleanLogoutStore($store);
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 
125  self::createLogoutTable($store);
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) {
264  $sessionIndex = sha1($sessionIndex);
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 }
$expire
Definition: saml2-acs.php:140
static generateID()
Generate a random identifier, ID_LENGTH bytes long.
Definition: Random.php:26
static addSession($authId, $nameId, $sessionIndex, $expire)
Register a new session in the datastore.
static getSessionsStore(\SimpleSAML\Store $store, $authId, $nameId, array $sessionIndexes)
Retrieve all session IDs from a key-value store.
static cleanLogoutStore(\SimpleSAML\Store\SQL $store)
Clean the logout table of expired entries.
Definition: LogoutStore.php:67
static debug($string)
Definition: Logger.php:211
static getSessionsSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId)
Retrieve sessions from the SQL datastore.
$session
$sessionIndex
Definition: saml2-acs.php:139
static getSession($sessionId=null)
Get a session from the session handler.
Definition: Session.php:315
if(! $oauthconfig->getBoolean('getUserInfo.enable', FALSE)) $store
Definition: getUserInfo.php:11
$nameId
Definition: saml2-acs.php:138
Attribute-related utility methods.
static info($string)
Definition: Logger.php:199
foreach($_POST as $key=> $value) $res
static addSessionSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId, $sessionIndex, $expire, $sessionId)
Register a session in the SQL datastore.
Definition: LogoutStore.php:87
static warning($string)
Definition: Logger.php:177
$query
$row
static getInstance()
Retrieve our singleton instance.
Definition: Store.php:31
static getSessionFromRequest()
Retrieves the current session.
Definition: Session.php:241
static createLogoutTable(\SimpleSAML\Store\SQL $store)
Create logout table in SQL, if it is missing.
Definition: LogoutStore.php:15
static fromArray(array $nameId)
Create a object from an array with its contents.
Definition: NameIDType.php:87
$data
Definition: bench.php:6