Overview

Namespaces

  • None
  • PHP
  • Pry
    • Auth
      • Interfaces
    • Config
    • Controller
    • Date
    • Db
    • Feed
      • Abstracts
      • Writers
    • File
      • Decorator
    • Form
      • Element
    • Image
    • Log
      • Writer
    • Net
      • Exception
    • Session
    • Util
    • Validate
      • Validator
    • View

Classes

  • ACL
  • Auth
  • Bcrypt
  • Util
  • WithRole
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * Pry Framework
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file LICENSE.txt.
 10:  * 
 11:  */
 12: 
 13: namespace Pry\Auth;
 14: 
 15: use Pry\Auth\Bcrypt;
 16: use Pry\Auth\Interfaces\OnAutoLoginEvent;
 17: use Pry\Session\Session;
 18: 
 19: /**
 20:  * Identification d'utilisateur via BDD
 21:  * 
 22:  * <code>
 23:  * // Exemple d'identification
 24:  * $sess = Session::getInstance('nomSession',10);
 25:  * $auth = new Auth($sess);
 26:  * $auth->setUserTable('user');
 27:  * $auth->setUserField('login');
 28:  * $auth->setPwdField('pwd');
 29:  * $auth->setHashRounds(10);
 30:  * $auth->login($_POST['login'],$_POST['mdp']);
 31:  * if(!$auth->error)
 32:  * {
 33:  *   if($auth->isLogged())
 34:  *   {
 35:  *     echo 'Connnecté';
 36:  *     print_r($_SESSION);
 37:  *   }
 38:  *   else
 39:  *     echo 'pas Connecté';
 40:  *   }
 41:  * else
 42:  * {
 43:  *   echo $auth->displayError();
 44:  * }
 45:  * </code>
 46:  * 
 47:  * @category Pry
 48:  * @package Auth
 49:  * @version 1.4.2 
 50:  * @author Olivier ROGER <oroger.fr>
 51:  * @see http://stackoverflow.com/questions/549/the-definitive-guide-to-forms-based-website-authentication#477579  
 52:  * 
 53:  */
 54: class Auth
 55: {
 56: 
 57:     const NO_ERROR    = 0;
 58:     const ERROR_LOG   = 1;
 59:     const ERROR_PASS  = 2;
 60:     const ERROR_TABLE = 3;
 61:     const ERROR_FIELD = 4;
 62: 
 63:     /**
 64:      * Objet pour accès bdd
 65:      * @access private
 66:      * @var Zend_Db_Adapter_Abstract
 67:      */
 68:     private $oDB;
 69: 
 70:     /**
 71:      * Type d'erreur rencontrée
 72:      * @access private
 73:      * @var int $errorType
 74:      */
 75:     private $errorType;
 76: 
 77:     /**
 78:      * Message d'erreur
 79:      * @access private
 80:      * @var string $errorMsg
 81:      */
 82:     private $errorMsg;
 83: 
 84:     /**
 85:      * Table des utilisateurs
 86:      * @access public
 87:      * @var string $userTable
 88:      */
 89:     private $userTable;
 90: 
 91:     /**
 92:      * Champs du nom d'utilisateur
 93:      * @access public
 94:      * @var string $userField
 95:      */
 96:     private $userField;
 97: 
 98:     /**
 99:      * Champs du mot de passe
100:      * @access public
101:      * @var string $pwdField
102:      */
103:     private $pwdField;
104: 
105:     /** Champs contenant le token d'autologin */
106:     private $autologTokenField;
107: 
108:     /** Nombre d'itération pour l'algo bcrypt */
109:     private $hashRounds;
110: 
111:     /**
112:      * Connexion automatique
113:      * @access public
114:      * @var boolean $autoLogin
115:      */
116:     private $autoLogin;
117: 
118:     /**
119:      * Option des cookies
120:      * @access public
121:      * @var array $cookieOption
122:      */
123:     private $cookieOption;
124: 
125:     /**
126:      * Durée de vie de l'authentification
127:      * @var type 
128:      */
129:     private $timeOutSession;
130: 
131:     /**
132:      * Erreur lors de l'identification
133:      *
134:      * @var boolean $error
135:      */
136:     public $error;
137: 
138:     /**
139:      * Session
140:      *
141:      * @var Session_Session
142:      */
143:     private $session;
144: 
145:     /**
146:      * Constructeur
147:      * 
148:      * @param Zend_Db_Adapter_Abstract $db Objet Zend Db
149:      * @param Session_Session $session
150:      * @access public
151:      */
152:     public function __construct(Session $session, \Zend_Db_Adapter_Abstract $db)
153:     {
154:         $this->oDB               = $db;
155:         $this->userTable         = 'user';
156:         $this->userField         = 'login';
157:         $this->pwdField          = 'password';
158:         $this->autologTokenField = 'autologKey';
159:         $this->autoLogin         = false;
160: 
161:         $this->cookieOption = array(
162:             'name' => 'loginCookie',
163:             'ttl' => time() + (365 * 24 * 3600)
164:         );
165:         $this->timeOutSession = 0;
166:         $this->error          = false;
167:         $this->errorType      = self::NO_ERROR;
168:         $this->errorMsg       = '';
169:         $this->session        = $session;
170: 
171:         if (!isset($session->AC_lastAct))
172:         {
173:             $session->AC_connected = 0;
174:             $session->AC_lastAct   = 0;
175:         }
176:     }
177: 
178:     /**
179:      * Identification classique via formulaire
180:      *
181:      * @param string $login
182:      * @param string $pass
183:      */
184:     public function login($login, $pass)
185:     {
186:         if ($this->checkUser($login))
187:             if ($this->checkPass($login, $pass))
188:             {
189:                 $this->startSession();
190:                 $this->session->AC_connected = true;
191:                 $this->session->AC_lastAct   = time();
192:                 if ($this->autoLogin)
193:                 {
194:                     $this->createCookie($login);
195:                 }
196:             }
197:             else
198:                 $this->displayError();
199:         else
200:             $this->displayError();
201:     }
202: 
203:     public function logout()
204:     {
205:         $this->destroySession();
206:         $this->destroyCookie();
207:     }
208: 
209:     /**
210:      * Vérifie si l'utilisateur est identifié
211:      *
212:      * @return boolean
213:      */
214:     public function isLogged()
215:     {
216:         $lastActivity = time() - $this->session->AC_lastAct;
217:         // Cas 1 - Session existante illimité
218:         if ($this->session->AC_connected === true && $this->timeOutSession == 0)
219:         {
220:             $this->session->AC_lastAct = time();
221:             if ($lastActivity > 300)
222:                 $this->session->refresh();
223:             return true;
224:         }
225:         // Cas 2 - Session limité mais existante et TTL non dépassé
226:         if ($this->session->AC_connected === true && $lastActivity < $this->timeOutSession && $this->timeOutSession != 0)
227:         {
228:             $this->session->AC_lastAct = time();
229:             if ($lastActivity > 300)
230:                 $this->session->refresh();
231:             return true;
232:         }
233:         // Cas 3 - Session limité mais existante et TTL dépassé
234:         if ($this->session->AC_connected === true && $lastActivity > $this->timeOutSession && $this->timeOutSession != 0)
235:         {
236:             $this->logout();
237:             return false;
238:         }
239:         // Cas 4 - Session inexistante mais autologin
240:         if (isset($this->session->AC_connected) && !$this->session->AC_connected && $this->autoLogin)
241:         {
242:             if ($this->loginCookie())
243:                 return true;
244:             else
245:                 return false;
246:         }
247: 
248:         return false;
249:     }
250: 
251:     /**
252:      * Affichage des erreurs
253:      *
254:      * @return string
255:      */
256:     public function displayError()
257:     {
258:         switch ($this->errorType)
259:         {
260:             case self::ERROR_LOG:
261:                 $this->errorMsg = 'Identifiant incorrect';
262:                 break;
263:             case self::ERROR_PASS:
264:                 $this->errorMsg = 'Mot de passe incorrect';
265:                 break;
266:         }
267:         return $this->errorMsg;
268:     }
269: 
270:     /**
271:      * Identification via cookie
272:      *
273:      * @return boolean
274:      */
275:     private function loginCookie()
276:     {
277:         if (isset($_COOKIE['' . $this->cookieOption['name'] . '']))
278:         {
279:             $datas = $_COOKIE['' . $this->cookieOption['name'] . ''];
280:             $pos   = strripos($datas, '|');
281:             $login = substr($datas, 0, $pos);
282:             $token = substr($datas, $pos + 1);
283: 
284:             if ($this->checkUser($login))
285:             {
286:                 $prepare = $this->oDB->prepare('SELECT ' . $this->autologTokenField . ' FROM ' . $this->userTable . ' WHERE ' . $this->userField . ' = :logCookie');
287:                 $prepare->execute(array(':logCookie' => $login));
288:                 $data        = $prepare->fetchColumn();
289: 
290:                 if ($token == $data)
291:                 {
292:                     $this->startSession();
293:                     $this->session->AC_connected = true;
294:                     $this->session->AC_lastAct   = time();
295:                     //Mise à jour du cookie et du token d'autologin
296:                     $this->destroyCookie();
297:                     $this->createCookie($login);
298: 
299:                     if (!empty($this->autoLoginEvent))
300:                     {
301:                         $this->autoLoginEvent->onAutoLogin($login);
302:                     }
303: 
304:                     return true;
305:                 }
306:                 else
307:                 {
308:                     $this->error     = true;
309:                     $this->errorType = self::ERROR_PASS;
310:                     $this->destroyCookie();
311:                     $this->displayError();
312:                 }
313:             }
314:             else
315:             {
316:                 $this->destroyCookie();
317:                 $this->displayError();
318:             }
319:         }
320:         return false;
321:     }
322: 
323:     /**
324:      * Démarrage session si innexistante
325:      *
326:      */
327:     public function startSession($name = 'acauth')
328:     {
329:         if (empty($this->session))
330:             $this->session = Session_Session::getInstance($name, $this->timeOutSession);
331:     }
332: 
333:     /**
334:      * Création du cookie avec salage du mdp avec le token
335:      *
336:      * @param string $login
337:      */
338:     private function createCookie($login)
339:     {
340:         $token = $this->generateRandomToken();
341:         $value = $login . '|' . $token;
342:         setcookie($this->cookieOption['name'], $value, $this->cookieOption['ttl'], '/');
343: 
344:         //Mise à jour du token dans la base
345:         $prep = $this->oDB->prepare('UPDATE ' . $this->userTable . ' SET ' . $this->autologTokenField . ' = :token WHERE ' . $this->userField . ' = :user');
346:         $prep->execute(array(
347:             ':token' => $token,
348:             ':user' => $login
349:         ));
350:     }
351: 
352:     private function generateRandomToken()
353:     {
354:         $token = '';
355:         $char  = '+-*$=)_!?./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
356:         for ($i = 0; $i < 35; $i++)
357:             $token .= $char[mt_rand(0, 72)];
358: 
359:         return sha1($token);
360:     }
361: 
362:     /**
363:      * Destruction de la session et de toute les variables associées
364:      *
365:      */
366:     private function destroySession()
367:     {
368:         $this->session->destroy();
369:     }
370: 
371:     /**
372:      * Destruction du cookie
373:      *
374:      */
375:     private function destroyCookie()
376:     {
377:         setcookie($this->cookieOption['name'], NULL, time() - 10, '/');
378:     }
379: 
380:     /**
381:      * Vérification de l'identifiant
382:      *
383:      * @param string $user
384:      * @return boolean
385:      */
386:     private function checkUser($user)
387:     {
388:         $prepare = $this->oDB->prepare('SELECT ' . $this->userField . ' FROM ' . $this->userTable . ' WHERE ' . $this->userField . ' = :user');
389:         $prepare->execute(array(':user' => $user));
390:         if ($prepare->fetchColumn())
391:             return true;
392:         else
393:         {
394:             $this->error     = true;
395:             $this->errorType = self::ERROR_LOG;
396:             return false;
397:         }
398:     }
399: 
400:     /**
401:      * Vérification du mot de passe
402:      *
403:      * @param string $login Identifiant
404:      * @param string $pass
405:      * @access private
406:      * @return boolean
407:      */
408:     private function checkPass($login, $pass)
409:     {
410:         $prepare = $this->oDB->prepare('SELECT ' . $this->pwdField . ' FROM ' . $this->userTable . ' WHERE ' . $this->userField . ' = :login');
411:         $prepare->execute(array(':login' => $login));
412:         $hash    = $prepare->fetchColumn();
413: 
414:         if (Bcrypt::check($pass, $hash))
415:             return true;
416:         else
417:         {
418:             $this->error     = true;
419:             $this->errorType = self::ERROR_PASS;
420:             return false;
421:         }
422:     }
423: 
424:     /**
425:      * Hash le mot de pass dans l'algo souhaité
426:      *
427:      * @param string $algo
428:      * @param string $pass
429:      * @return string
430:      */
431:     private function hashPass($pass)
432:     {
433:         /* if ($this->pwdHash != 'nohash')
434:           return hash($this->pwdHash, $pass);
435:           else
436:           return $pass; */
437: 
438:         $bCrypt = new Bcrypt($this->hashRounds);
439:         return $bCrypt->hash($pass);
440:     }
441: 
442:     /**
443:      * Retourne l'erreur si existante
444:      *
445:      * @since 1.0.5
446:      * @return int
447:      */
448:     public function getErrorType()
449:     {
450:         return $this->errorType;
451:     }
452: 
453:     /**
454:      * Défini le nom de la table contenant les comptes utilisateurs
455:      * @param string $userTable 
456:      */
457:     public function setUserTable($userTable)
458:     {
459:         $this->userTable = $userTable;
460:     }
461: 
462:     /**
463:      * Défini le champs contenant l'identifiant unique par utilisateur
464:      * @param string $userField 
465:      */
466:     public function setUserField($userField)
467:     {
468:         $this->userField = $userField;
469:     }
470: 
471:     /**
472:      * Défini le champs contenant le hash du mot de passe
473:      * @param string $pwdField 
474:      */
475:     public function setPwdField($pwdField)
476:     {
477:         $this->pwdField = $pwdField;
478:     }
479: 
480:     /**
481:      * Défini le champs contenant le token utilisé par le cookie d'autologin
482:      * @param string $autologTokenField 
483:      */
484:     public function setAutologTokenField($autologTokenField)
485:     {
486:         $this->autologTokenField = $autologTokenField;
487:     }
488: 
489:     /**
490:      * Défini le nombre d'itération utilisé dans le cryptage Bcrypt du mot de passe
491:      * @param int $hashRounds 
492:      */
493:     public function setHashRounds($hashRounds)
494:     {
495:         $this->hashRounds = $hashRounds;
496:     }
497: 
498:     /**
499:      * Active ou non l'autologin
500:      * @param boolean $autoLogin 
501:      */
502:     public function setAutoLogin($autoLogin)
503:     {
504:         $this->autoLogin = $autoLogin;
505:     }
506: 
507:     /**
508:      * Défini les options du cookie d'autologin.
509:      * 
510:      * @param array $cookieOption Doit contenir les clés "name" (string) et ttl (int) durée de vie en seconde
511:      */
512:     public function setCookieOption($cookieOption)
513:     {
514:         $this->cookieOption = $cookieOption;
515:     }
516: 
517:     /**
518:      * Défini en seconde la durée de vie de l'authentification
519:      * @param type $timeout 
520:      */
521:     public function setTimeoutSession($timeout)
522:     {
523:         $this->timeOutSession = $timeout;
524:     }
525: 
526:     /**
527:      * Défini une instance de classe implémentant 
528:      * Auth_Interfaces_OnAutoLoginEvent afin d'appeler la méthode onAutoLogin
529:      * après l'authentification via cookie
530:      * @param Auth_Interfaces_OnAutoLoginEvent $event
531:      */
532:     public function setOnAutoLoginEvent(OnAutoLoginEvent $event)
533:     {
534:         $this->autoLoginEvent = $event;
535:     }
536: 
537: }
538: 
539: ?>
Pry API documentation generated by ApiGen 2.8.0