Development

/branches/1.4/lib/user/sfBasicSecurityUser.class.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/user/sfBasicSecurityUser.class.php

Revision 33466, 7.2 kB (checked in by fabien, 3 years ago)

[1.4] fixed a possible DB session fixation attack (patch from Dmitri Groutso)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  * (c) 2004-2006 Sean Kerr <sean@code-box.org>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 /**
13  * sfBasicSecurityUser will handle any type of data as a credential.
14  *
15  * @package    symfony
16  * @subpackage user
17  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
18  * @author     Sean Kerr <sean@code-box.org>
19  * @version    SVN: $Id$
20  */
21 class sfBasicSecurityUser extends sfUser implements sfSecurityUser
22 {
23   const LAST_REQUEST_NAMESPACE = 'symfony/user/sfUser/lastRequest';
24   const AUTH_NAMESPACE = 'symfony/user/sfUser/authenticated';
25   const CREDENTIAL_NAMESPACE = 'symfony/user/sfUser/credentials';
26
27   protected $lastRequest = null;
28
29   protected $credentials = null;
30   protected $authenticated = null;
31
32   protected $timedout = false;
33
34   /**
35    * Clears all credentials.
36    *
37    */
38   public function clearCredentials()
39   {
40     $this->credentials = array();
41   }
42
43   /**
44    * Returns the current user's credentials.
45    *
46    * @return array
47    */
48   public function getCredentials()
49   {
50     return $this->credentials;
51   }
52
53   /**
54    * Removes a credential.
55    *
56    * @param  mixed $credential credential
57    */
58   public function removeCredential($credential)
59   {
60     if ($this->hasCredential($credential))
61     {
62       foreach ($this->credentials as $key => $value)
63       {
64         if ($credential == $value)
65         {
66           if ($this->options['logging'])
67           {
68             $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Remove credential "%s"', $credential))));
69           }
70
71           unset($this->credentials[$key]);
72
73           $this->storage->regenerate(true);
74
75           return;
76         }
77       }
78     }
79   }
80
81   /**
82    * Adds a credential.
83    *
84    * @param mixed $credential
85    */
86   public function addCredential($credential)
87   {
88     $this->addCredentials(func_get_args());
89   }
90
91   /**
92    * Adds several credential at once.
93    *
94    * @param  mixed array or list of credentials
95    */
96   public function addCredentials()
97   {
98     if (func_num_args() == 0) return;
99
100     // Add all credentials
101     $credentials = (is_array(func_get_arg(0))) ? func_get_arg(0) : func_get_args();
102
103     if ($this->options['logging'])
104     {
105       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Add credential(s) "%s"', implode(', ', $credentials)))));
106     }
107
108     $added = false;
109     foreach ($credentials as $aCredential)
110     {
111       if (!in_array($aCredential, $this->credentials))
112       {
113         $added = true;
114         $this->credentials[] = $aCredential;
115       }
116     }
117
118     if ($added)
119     {
120       $this->storage->regenerate(true);
121     }
122   }
123
124   /**
125    * Returns true if user has credential.
126    *
127    * @param  mixed $credentials
128    * @param  bool  $useAnd       specify the mode, either AND or OR
129    * @return bool
130    *
131    * @author Olivier Verdier <Olivier.Verdier@free.fr>
132    */
133   public function hasCredential($credentials, $useAnd = true)
134   {
135     if (null === $this->credentials)
136     {
137       return false;
138     }
139
140     if (!is_array($credentials))
141     {
142       return in_array($credentials, $this->credentials);
143     }
144
145     // now we assume that $credentials is an array
146     $test = false;
147
148     foreach ($credentials as $credential)
149     {
150       // recursively check the credential with a switched AND/OR mode
151       $test = $this->hasCredential($credential, $useAnd ? false : true);
152
153       if ($useAnd)
154       {
155         $test = $test ? false : true;
156       }
157
158       if ($test) // either passed one in OR mode or failed one in AND mode
159       {
160         break; // the matter is settled
161       }
162     }
163
164     if ($useAnd) // in AND mode we succeed if $test is false
165     {
166       $test = $test ? false : true;
167     }
168
169     return $test;
170   }
171
172   /**
173    * Returns true if user is authenticated.
174    *
175    * @return boolean
176    */
177   public function isAuthenticated()
178   {
179     return $this->authenticated;
180   }
181
182   /**
183    * Sets authentication for user.
184    *
185    * @param  bool $authenticated
186    */
187   public function setAuthenticated($authenticated)
188   {
189     if ($this->options['logging'])
190     {
191       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('User is %sauthenticated', $authenticated === true ? '' : 'not '))));
192     }
193
194     if ((bool) $authenticated !== $this->authenticated)
195     {
196       if ($authenticated === true)
197       {
198         $this->authenticated = true;
199       }
200       else
201       {
202         $this->authenticated = false;
203         $this->clearCredentials();
204       }
205
206       $this->dispatcher->notify(new sfEvent($this, 'user.change_authentication', array('authenticated' => $this->authenticated)));
207
208       $this->storage->regenerate(true);
209     }
210   }
211
212   public function setTimedOut()
213   {
214     $this->timedout = true;
215   }
216
217   public function isTimedOut()
218   {
219     return $this->timedout;
220   }
221
222   /**
223    * Returns the timestamp of the last user request.
224    *
225    * @return  int
226    */
227   public function getLastRequestTime()
228   {
229     return $this->lastRequest;
230   }
231
232   /**
233    * Available options:
234    *
235    *  * timeout: Timeout to automatically log out the user in seconds (1800 by default)
236    *             Set to false to disable
237    *
238    * @param sfEventDispatcher $dispatcher  An sfEventDispatcher instance.
239    * @param sfStorage         $storage     An sfStorage instance.
240    * @param array             $options     An associative array of options.
241    *
242    * @see sfUser
243    */
244   public function initialize(sfEventDispatcher $dispatcher, sfStorage $storage, $options = array())
245   {
246     // initialize parent
247     parent::initialize($dispatcher, $storage, $options);
248
249     if (!array_key_exists('timeout', $this->options))
250     {
251       $this->options['timeout'] = 1800;
252     }
253
254     // force the max lifetime for session garbage collector to be greater than timeout
255     if (ini_get('session.gc_maxlifetime') < $this->options['timeout'])
256     {
257       ini_set('session.gc_maxlifetime', $this->options['timeout']);
258     }
259
260     // read data from storage
261     $this->authenticated = $storage->read(self::AUTH_NAMESPACE);
262     $this->credentials   = $storage->read(self::CREDENTIAL_NAMESPACE);
263     $this->lastRequest   = $storage->read(self::LAST_REQUEST_NAMESPACE);
264
265     if (null === $this->authenticated)
266     {
267       $this->authenticated = false;
268       $this->credentials   = array();
269     }
270     else
271     {
272       // Automatic logout logged in user if no request within timeout parameter seconds
273       $timeout = $this->options['timeout'];
274       if (false !== $timeout && null !== $this->lastRequest && time() - $this->lastRequest >= $timeout)
275       {
276         if ($this->options['logging'])
277         {
278           $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Automatic user logout due to timeout')));
279         }
280
281         $this->setTimedOut();
282         $this->setAuthenticated(false);
283       }
284     }
285
286     $this->lastRequest = time();
287   }
288
289   public function shutdown()
290   {
291     // write the last request time to the storage
292     $this->storage->write(self::LAST_REQUEST_NAMESPACE, $this->lastRequest);
293
294     $this->storage->write(self::AUTH_NAMESPACE,         $this->authenticated);
295     $this->storage->write(self::CREDENTIAL_NAMESPACE,   $this->credentials);
296
297     // call the parent shutdown method
298     parent::shutdown();
299   }
300 }
301
Note: See TracBrowser for help on using the browser.