TYPO3 CMS  TYPO3_6-2
FileStore.php
Go to the documentation of this file.
1 <?php
2 
20 require_once 'Auth/OpenID.php';
21 require_once 'Auth/OpenID/Interface.php';
22 require_once 'Auth/OpenID/HMAC.php';
23 require_once 'Auth/OpenID/Nonce.php';
24 
40 
49  function Auth_OpenID_FileStore($directory)
50  {
51  if (!Auth_OpenID::ensureDir($directory)) {
52  trigger_error('Not a directory and failed to create: '
53  . $directory, E_USER_ERROR);
54  }
55  $directory = realpath($directory);
56 
57  $this->directory = $directory;
58  $this->active = true;
59 
60  $this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces';
61 
62  $this->association_dir = $directory . DIRECTORY_SEPARATOR .
63  'associations';
64 
65  // Temp dir must be on the same filesystem as the assciations
66  // $directory.
67  $this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';
68 
69  $this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds
70 
71  if (!$this->_setup()) {
72  trigger_error('Failed to initialize OpenID file store in ' .
73  $directory, E_USER_ERROR);
74  }
75  }
76 
77  function destroy()
78  {
79  Auth_OpenID_FileStore::_rmtree($this->directory);
80  $this->active = false;
81  }
82 
89  function _setup()
90  {
91  return (Auth_OpenID::ensureDir($this->nonce_dir) &&
92  Auth_OpenID::ensureDir($this->association_dir) &&
93  Auth_OpenID::ensureDir($this->temp_dir));
94  }
95 
108  function _mktemp()
109  {
110  $name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir);
111  $file_obj = @fopen($name, 'wb');
112  if ($file_obj !== false) {
113  return array($file_obj, $name);
114  } else {
116  }
117  }
118 
119  function cleanupNonces()
120  {
121  global $Auth_OpenID_SKEW;
122 
123  $nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
124  $now = time();
125 
126  $removed = 0;
127  // Check all nonces for expiry
128  foreach ($nonces as $nonce_fname) {
129  $base = basename($nonce_fname);
130  $parts = explode('-', $base, 2);
131  $timestamp = $parts[0];
132  $timestamp = intval($timestamp, 16);
133  if (abs($timestamp - $now) > $Auth_OpenID_SKEW) {
135  $removed += 1;
136  }
137  }
138  return $removed;
139  }
140 
150  function getAssociationFilename($server_url, $handle)
151  {
152  if (!$this->active) {
153  trigger_error("FileStore no longer active", E_USER_ERROR);
154  return null;
155  }
156 
157  if (strpos($server_url, '://') === false) {
158  trigger_error(sprintf("Bad server URL: %s", $server_url),
159  E_USER_WARNING);
160  return null;
161  }
162 
163  list($proto, $rest) = explode('://', $server_url, 2);
164  $parts = explode('/', $rest);
165  $domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]);
166  $url_hash = Auth_OpenID_FileStore::_safe64($server_url);
167  if ($handle) {
168  $handle_hash = Auth_OpenID_FileStore::_safe64($handle);
169  } else {
170  $handle_hash = '';
171  }
172 
173  $filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash,
174  $handle_hash);
175 
176  return $this->association_dir. DIRECTORY_SEPARATOR . $filename;
177  }
178 
182  function storeAssociation($server_url, $association)
183  {
184  if (!$this->active) {
185  trigger_error("FileStore no longer active", E_USER_ERROR);
186  return false;
187  }
188 
189  $association_s = $association->serialize();
190  $filename = $this->getAssociationFilename($server_url,
191  $association->handle);
192  list($tmp_file, $tmp) = $this->_mktemp();
193 
194  if (!$tmp_file) {
195  trigger_error("_mktemp didn't return a valid file descriptor",
196  E_USER_WARNING);
197  return false;
198  }
199 
200  fwrite($tmp_file, $association_s);
201 
202  fflush($tmp_file);
203 
204  fclose($tmp_file);
205 
206  if (@rename($tmp, $filename)) {
207  return true;
208  } else {
209  // In case we are running on Windows, try unlinking the
210  // file in case it exists.
211  @unlink($filename);
212 
213  // Now the target should not exist. Try renaming again,
214  // giving up if it fails.
215  if (@rename($tmp, $filename)) {
216  return true;
217  }
218  }
219 
220  // If there was an error, don't leave the temporary file
221  // around.
223  return false;
224  }
225 
232  function getAssociation($server_url, $handle = null)
233  {
234  if (!$this->active) {
235  trigger_error("FileStore no longer active", E_USER_ERROR);
236  return null;
237  }
238 
239  if ($handle === null) {
240  $handle = '';
241  }
242 
243  // The filename with the empty handle is a prefix of all other
244  // associations for the given server URL.
245  $filename = $this->getAssociationFilename($server_url, $handle);
246 
247  if ($handle) {
248  return $this->_getAssociation($filename);
249  } else {
250  $association_files =
251  Auth_OpenID_FileStore::_listdir($this->association_dir);
252  $matching_files = array();
253 
254  // strip off the path to do the comparison
255  $name = basename($filename);
256  foreach ($association_files as $association_file) {
257  $base = basename($association_file);
258  if (strpos($base, $name) === 0) {
259  $matching_files[] = $association_file;
260  }
261  }
262 
263  $matching_associations = array();
264  // read the matching files and sort by time issued
265  foreach ($matching_files as $full_name) {
266  $association = $this->_getAssociation($full_name);
267  if ($association !== null) {
268  $matching_associations[] = array($association->issued,
269  $association);
270  }
271  }
272 
273  $issued = array();
274  $assocs = array();
275  foreach ($matching_associations as $key => $assoc) {
276  $issued[$key] = $assoc[0];
277  $assocs[$key] = $assoc[1];
278  }
279 
280  array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
281  $matching_associations);
282 
283  // return the most recently issued one.
284  if ($matching_associations) {
285  list($issued, $assoc) = $matching_associations[0];
286  return $assoc;
287  } else {
288  return null;
289  }
290  }
291  }
292 
296  function _getAssociation($filename)
297  {
298  if (!$this->active) {
299  trigger_error("FileStore no longer active", E_USER_ERROR);
300  return null;
301  }
302 
303  if (file_exists($filename) !== true) {
304  return null;
305  }
306 
307  $assoc_file = @fopen($filename, 'rb');
308 
309  if ($assoc_file === false) {
310  return null;
311  }
312 
313  $filesize = filesize($filename);
314  if ($filesize === false || $filesize <= 0) {
315  return null;
316  }
317 
318  $assoc_s = fread($assoc_file, $filesize);
319  fclose($assoc_file);
320 
321  if (!$assoc_s) {
322  return null;
323  }
324 
325  $association =
326  Auth_OpenID_Association::deserialize('Auth_OpenID_Association',
327  $assoc_s);
328 
329  if (!$association) {
331  return null;
332  }
333 
334  if ($association->getExpiresIn() == 0) {
336  return null;
337  } else {
338  return $association;
339  }
340  }
341 
347  function removeAssociation($server_url, $handle)
348  {
349  if (!$this->active) {
350  trigger_error("FileStore no longer active", E_USER_ERROR);
351  return null;
352  }
353 
354  $assoc = $this->getAssociation($server_url, $handle);
355  if ($assoc === null) {
356  return false;
357  } else {
358  $filename = $this->getAssociationFilename($server_url, $handle);
359  return Auth_OpenID_FileStore::_removeIfPresent($filename);
360  }
361  }
362 
369  function useNonce($server_url, $timestamp, $salt)
370  {
371  global $Auth_OpenID_SKEW;
372 
373  if (!$this->active) {
374  trigger_error("FileStore no longer active", E_USER_ERROR);
375  return null;
376  }
377 
378  if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
379  return false;
380  }
381 
382  if ($server_url) {
383  list($proto, $rest) = explode('://', $server_url, 2);
384  } else {
385  $proto = '';
386  $rest = '';
387  }
388 
389  $parts = explode('/', $rest, 2);
390  $domain = $this->_filenameEscape($parts[0]);
391  $url_hash = $this->_safe64($server_url);
392  $salt_hash = $this->_safe64($salt);
393 
394  $filename = sprintf('%08x-%s-%s-%s-%s', $timestamp, $proto,
395  $domain, $url_hash, $salt_hash);
396  $filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $filename;
397 
398  $result = @fopen($filename, 'x');
399 
400  if ($result === false) {
401  return false;
402  } else {
403  fclose($result);
404  return true;
405  }
406  }
407 
414  function _allAssocs()
415  {
416  $all_associations = array();
417 
418  $association_filenames =
419  Auth_OpenID_FileStore::_listdir($this->association_dir);
420 
421  foreach ($association_filenames as $association_filename) {
422  $association_file = fopen($association_filename, 'rb');
423 
424  if ($association_file !== false) {
425  $assoc_s = fread($association_file,
426  filesize($association_filename));
427  fclose($association_file);
428 
429  // Remove expired or corrupted associations
430  $association =
432  'Auth_OpenID_Association', $assoc_s);
433 
434  if ($association === null) {
436  $association_filename);
437  } else {
438  if ($association->getExpiresIn() == 0) {
439  $all_associations[] = array($association_filename,
440  $association);
441  }
442  }
443  }
444  }
445 
446  return $all_associations;
447  }
448 
449  function clean()
450  {
451  if (!$this->active) {
452  trigger_error("FileStore no longer active", E_USER_ERROR);
453  return null;
454  }
455 
456  $nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
457  $now = time();
458 
459  // Check all nonces for expiry
460  foreach ($nonces as $nonce) {
461  if (!Auth_OpenID_checkTimestamp($nonce, $now)) {
462  $filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
464  }
465  }
466 
467  foreach ($this->_allAssocs() as $pair) {
468  list($assoc_filename, $assoc) = $pair;
469  if ($assoc->getExpiresIn() == 0) {
471  }
472  }
473  }
474 
478  function _rmtree($dir)
479  {
480  if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
481  $dir .= DIRECTORY_SEPARATOR;
482  }
483 
484  if ($handle = opendir($dir)) {
485  while ($item = readdir($handle)) {
486  if (!in_array($item, array('.', '..'))) {
487  if (is_dir($dir . $item)) {
488 
489  if (!Auth_OpenID_FileStore::_rmtree($dir . $item)) {
490  return false;
491  }
492  } else if (is_file($dir . $item)) {
493  if (!unlink($dir . $item)) {
494  return false;
495  }
496  }
497  }
498  }
499 
500  closedir($handle);
501 
502  if (!@rmdir($dir)) {
503  return false;
504  }
505 
506  return true;
507  } else {
508  // Couldn't open directory.
509  return false;
510  }
511  }
512 
516  function _mkstemp($dir)
517  {
518  foreach (range(0, 4) as $i) {
519  $name = tempnam($dir, "php_openid_filestore_");
520 
521  if ($name !== false) {
522  return $name;
523  }
524  }
525  return false;
526  }
527 
531  static function _mkdtemp($dir)
532  {
533  foreach (range(0, 4) as $i) {
534  $name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) .
535  "-" . strval(rand(1, time()));
536  if (!mkdir($name, 0700)) {
537  return false;
538  } else {
539  return $name;
540  }
541  }
542  return false;
543  }
544 
548  function _listdir($dir)
549  {
550  $handle = opendir($dir);
551  $files = array();
552  while (false !== ($filename = readdir($handle))) {
553  if (!in_array($filename, array('.', '..'))) {
554  $files[] = $dir . DIRECTORY_SEPARATOR . $filename;
555  }
556  }
557  return $files;
558  }
559 
563  function _isFilenameSafe($char)
564  {
565  $_Auth_OpenID_filename_allowed = Auth_OpenID_letters .
566  Auth_OpenID_digits . ".";
567  return (strpos($_Auth_OpenID_filename_allowed, $char) !== false);
568  }
569 
573  function _safe64($str)
574  {
575  $h64 = base64_encode(Auth_OpenID_SHA1($str));
576  $h64 = str_replace('+', '_', $h64);
577  $h64 = str_replace('/', '.', $h64);
578  $h64 = str_replace('=', '', $h64);
579  return $h64;
580  }
581 
585  function _filenameEscape($str)
586  {
587  $filename = "";
588  $b = Auth_OpenID::toBytes($str);
589 
590  for ($i = 0; $i < count($b); $i++) {
591  $c = $b[$i];
593  $filename .= $c;
594  } else {
595  $filename .= sprintf("_%02X", ord($c));
596  }
597  }
598  return $filename;
599  }
600 
608  function _removeIfPresent($filename)
609  {
610  return @unlink($filename);
611  }
612 
614  {
615  $removed = 0;
616  foreach ($this->_allAssocs() as $pair) {
617  list($assoc_filename, $assoc) = $pair;
618  if ($assoc->getExpiresIn() == 0) {
619  $this->_removeIfPresent($assoc_filename);
620  $removed += 1;
621  }
622  }
623  return $removed;
624  }
625 }
626 
627 
Auth_OpenID_FileStore($directory)
Definition: FileStore.php:49
Auth_OpenID_checkTimestamp($nonce_string, $allowed_skew=null, $now=null)
Definition: Nonce.php:57
getAssociation($server_url, $handle=null)
Definition: FileStore.php:232
Auth_OpenID_SHA1($text)
Definition: HMAC.php:25
storeAssociation($server_url, $association)
Definition: FileStore.php:182
if(!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE' E_USER_ERROR
_getAssociation($filename)
Definition: FileStore.php:296
removeAssociation($server_url, $handle)
Definition: FileStore.php:347
useNonce($server_url, $timestamp, $salt)
Definition: FileStore.php:369
static deserialize($class_name, $assoc_s)
_removeIfPresent($filename)
Definition: FileStore.php:608
getAssociationFilename($server_url, $handle)
Definition: FileStore.php:150
static _mkdtemp($dir)
Definition: FileStore.php:531
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
static toBytes($str)
Definition: OpenID.php:471
const Auth_OpenID_letters
Definition: OpenID.php:96
static ensureDir($dir_name)
Definition: OpenID.php:204
const Auth_OpenID_digits
Definition: OpenID.php:98
global $Auth_OpenID_SKEW
Definition: Nonce.php:23