ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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  $query = 'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore MODIFY _authSource VARCHAR(255) NOT NULL';
23  try {
24  $ret = $store->pdo->exec($query);
25  } catch (Exception $e) {
26  SimpleSAML\Logger::warning($store->pdo->errorInfo());
27  return;
28  }
29  $store->setTableVersion('saml_LogoutStore', 2);
30  return;
31  }
32 
33  $query = 'CREATE TABLE ' . $store->prefix . '_saml_LogoutStore (
34  _authSource VARCHAR(255) NOT NULL,
35  _nameId VARCHAR(40) NOT NULL,
36  _sessionIndex VARCHAR(50) NOT NULL,
37  _expire TIMESTAMP NOT NULL,
38  _sessionId VARCHAR(50) NOT NULL,
39  UNIQUE (_authSource, _nameID, _sessionIndex)
40  )';
41  $store->pdo->exec($query);
42 
43  $query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_expire ON ' . $store->prefix . '_saml_LogoutStore (_expire)';
44  $store->pdo->exec($query);
45 
46  $query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_nameId ON ' . $store->prefix . '_saml_LogoutStore (_authSource, _nameId)';
47  $store->pdo->exec($query);
48 
49  $store->setTableVersion('saml_LogoutStore', 2);
50  }
51 
52 
58  private static function cleanLogoutStore(\SimpleSAML\Store\SQL $store) {
59 
60  SimpleSAML\Logger::debug('saml.LogoutStore: Cleaning logout store.');
61 
62  $query = 'DELETE FROM ' . $store->prefix . '_saml_LogoutStore WHERE _expire < :now';
63  $params = array('now' => gmdate('Y-m-d H:i:s'));
64 
65  $query = $store->pdo->prepare($query);
66  $query->execute($params);
67  }
68 
69 
78  private static function addSessionSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId, $sessionIndex, $expire, $sessionId) {
79  assert('is_string($authId)');
80  assert('is_string($nameId)');
81  assert('is_string($sessionIndex)');
82  assert('is_string($sessionId)');
83  assert('is_int($expire)');
84 
85  self::createLogoutTable($store);
86 
87  if (rand(0, 1000) < 10) {
88  self::cleanLogoutStore($store);
89  }
90 
91  $data = array(
92  '_authSource' => $authId,
93  '_nameId' => $nameId,
94  '_sessionIndex' => $sessionIndex,
95  '_expire' => gmdate('Y-m-d H:i:s', $expire),
96  '_sessionId' => $sessionId,
97  );
98  $store->insertOrUpdate($store->prefix . '_saml_LogoutStore', array('_authSource', '_nameId', '_sessionIndex'), $data);
99  }
100 
101 
110  private static function getSessionsSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId) {
111  assert('is_string($authId)');
112  assert('is_string($nameId)');
113 
114  self::createLogoutTable($store);
115 
116  $params = array(
117  '_authSource' => $authId,
118  '_nameId' => $nameId,
119  'now' => gmdate('Y-m-d H:i:s'),
120  );
121 
122  // We request the columns in lowercase in order to be compatible with PostgreSQL
123  $query = 'SELECT _sessionIndex AS _sessionindex, _sessionId AS _sessionid FROM ' . $store->prefix . '_saml_LogoutStore' .
124  ' WHERE _authSource = :_authSource AND _nameId = :_nameId AND _expire >= :now';
125  $query = $store->pdo->prepare($query);
126  $query->execute($params);
127 
128  $res = array();
129  while ( ($row = $query->fetch(PDO::FETCH_ASSOC)) !== FALSE) {
130  $res[$row['_sessionindex']] = $row['_sessionid'];
131  }
132 
133  return $res;
134  }
135 
136 
146  private static function getSessionsStore(\SimpleSAML\Store $store, $authId, $nameId, array $sessionIndexes) {
147  assert('is_string($authId)');
148  assert('is_string($nameId)');
149 
150  $res = array();
151  foreach ($sessionIndexes as $sessionIndex) {
152  $sessionId = $store->get('saml.LogoutStore', $nameId . ':' . $sessionIndex);
153  if ($sessionId === NULL) {
154  continue;
155  }
156  assert('is_string($sessionId)');
157  $res[$sessionIndex] = $sessionId;
158  }
159 
160  return $res;
161  }
162 
163 
177  public static function addSession($authId, $nameId, $sessionIndex, $expire) {
178  assert('is_string($authId)');
179  assert('is_string($sessionIndex) || is_null($sessionIndex)');
180  assert('is_int($expire)');
181 
182  if ($sessionIndex === NULL) {
183  /* This IdP apparently did not include a SessionIndex, and thus probably does not
184  * support SLO. We still want to add the session to the data store just in case
185  * it supports SLO, but we don't want an LogoutRequest with a specific
186  * SessionIndex to match this session. We therefore generate our own session index.
187  */
189  }
190 
192  if ($store === FALSE) {
193  // We don't have a datastore.
194  return;
195  }
196 
197  // serialize and anonymize the NameID
198  // TODO: remove this conditional statement
199  if (is_array($nameId)) {
201  }
202  $strNameId = serialize($nameId);
203  $strNameId = sha1($strNameId);
204 
205  /* Normalize SessionIndex. */
206  if (strlen($sessionIndex) > 50) {
208  }
209 
211  $sessionId = $session->getSessionId();
212 
213  if ($store instanceof \SimpleSAML\Store\SQL) {
214  self::addSessionSQL($store, $authId, $strNameId, $sessionIndex, $expire, $sessionId);
215  } else {
216  $store->set('saml.LogoutStore', $strNameId . ':' . $sessionIndex, $sessionId, $expire);
217  }
218  }
219 
220 
229  public static function logoutSessions($authId, $nameId, array $sessionIndexes) {
230  assert('is_string($authId)');
231 
233  if ($store === FALSE) {
234  /* We don't have a datastore. */
235  return FALSE;
236  }
237 
238  // serialize and anonymize the NameID
239  // TODO: remove this conditional statement
240  if (is_array($nameId)) {
242  }
243  $strNameId = serialize($nameId);
244  $strNameId = sha1($strNameId);
245 
246  /* Normalize SessionIndexes. */
247  foreach ($sessionIndexes as &$sessionIndex) {
248  assert('is_string($sessionIndex)');
249  if (strlen($sessionIndex) > 50) {
250  $sessionIndex = sha1($sessionIndex);
251  }
252  }
253  unset($sessionIndex); // Remove reference
254 
255  if ($store instanceof \SimpleSAML\Store\SQL) {
256  $sessions = self::getSessionsSQL($store, $authId, $strNameId);
257  } elseif (empty($sessionIndexes)) {
258  /* We cannot fetch all sessions without a SQL store. */
259  return FALSE;
260  } else {
262  $sessions = self::getSessionsStore($store, $authId, $strNameId, $sessionIndexes);
263 
264  }
265 
266  if (empty($sessionIndexes)) {
267  $sessionIndexes = array_keys($sessions);
268  }
269 
271 
272  $numLoggedOut = 0;
273  foreach ($sessionIndexes as $sessionIndex) {
274  if (!isset($sessions[$sessionIndex])) {
275  SimpleSAML\Logger::info('saml.LogoutStore: Logout requested for unknown SessionIndex.');
276  continue;
277  }
278 
279  $sessionId = $sessions[$sessionIndex];
280 
282  if ($session === NULL) {
283  SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of missing session.');
284  continue;
285  }
286 
287  if (!$session->isValid($authId)) {
288  SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of session because it isn\'t authenticated.');
289  continue;
290  }
291 
292  SimpleSAML\Logger::info('saml.LogoutStore: Logging out of session with trackId [' . $session->getTrackID() . '].');
293  $session->doLogout($authId);
294  $numLoggedOut += 1;
295  }
296 
297  return $numLoggedOut;
298  }
299 
300 }
$params
Definition: disable.php:11
$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:58
static debug($string)
Definition: Logger.php:213
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:317
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:201
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:78
static warning($string)
Definition: Logger.php:179
$query
Create styles array
The data for the language used.
static getSessionHandler()
This function retrieves the current instance of the session handler.
$ret
Definition: parser.php:6
static getInstance()
Retrieve our singleton instance.
Definition: Store.php:31
static getSessionFromRequest()
Retrieves the current session.
Definition: Session.php:243
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