Overview

Packages

  • Auth

Classes

  • Horde_Auth
  • Horde_Auth_Auto
  • Horde_Auth_Base
  • Horde_Auth_Composite
  • Horde_Auth_Customsql
  • Horde_Auth_Cyrsql
  • Horde_Auth_Exception
  • Horde_Auth_Ftp
  • Horde_Auth_Http
  • Horde_Auth_Http_Remote
  • Horde_Auth_Imap
  • Horde_Auth_Ipbasic
  • Horde_Auth_Kolab
  • Horde_Auth_Ldap
  • Horde_Auth_Login
  • Horde_Auth_Msad
  • Horde_Auth_Pam
  • Horde_Auth_Passwd
  • Horde_Auth_Peclsasl
  • Horde_Auth_Radius
  • Horde_Auth_Shibboleth
  • Horde_Auth_Smb
  • Horde_Auth_Smbclient
  • Horde_Auth_Sql
  • Horde_Auth_Translation
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Horde_Auth_Base:: class provides a common abstracted interface to
  4:  * creating various authentication backends.
  5:  *
  6:  * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See the enclosed file COPYING for license information (LGPL). If you did
  9:  * not receive this file, http://www.horde.org/licenses/lgpl21
 10:  *
 11:  * @author   Chuck Hagenbuch <chuck@horde.org>
 12:  * @author   Michael Slusarz <slusarz@horde.org>
 13:  * @category Horde
 14:  * @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
 15:  * @package  Auth
 16:  */
 17: abstract class Horde_Auth_Base
 18: {
 19:     /**
 20:      * An array of capabilities, so that the driver can report which
 21:      * operations it supports and which it doesn't.
 22:      *
 23:      * @var array
 24:      */
 25:     protected $_capabilities = array(
 26:         'add'           => false,
 27:         'authenticate'  => true,
 28:         'groups'        => false,
 29:         'list'          => false,
 30:         'resetpassword' => false,
 31:         'remove'        => false,
 32:         'transparent'   => false,
 33:         'update'        => false,
 34:         'badlogincount' => false,
 35:         'lock'          => false,
 36:     );
 37: 
 38:     /**
 39:      * Hash containing parameters needed for the drivers.
 40:      *
 41:      * @var array
 42:      */
 43:     protected $_params = array();
 44: 
 45:     /**
 46:      * The credentials currently being authenticated.
 47:      *
 48:      * @var array
 49:      */
 50:     protected $_credentials = array(
 51:         'change' => false,
 52:         'credentials' => array(),
 53:         'expire' => null,
 54:         'userId' => ''
 55:     );
 56: 
 57:     /**
 58:      * Logger object.
 59:      *
 60:      * @var Horde_Log_Logger
 61:      */
 62:     protected $_logger;
 63: 
 64:     /**
 65:      * History object.
 66:      *
 67:      * @var Horde_History
 68:      */
 69:     protected $_history_api;
 70: 
 71:     /**
 72:      * Lock object.
 73:      *
 74:      * @var Horde_Lock
 75:      */
 76:     protected $_lock_api;
 77: 
 78:     /**
 79:      * Authentication error information.
 80:      *
 81:      * @var array
 82:      */
 83:     protected $_error;
 84: 
 85:     /**
 86:      * Constructor.
 87:      *
 88:      * @param array $params  Optional parameters:
 89:      *     - default_user:      (string) The default user.
 90:      *     - logger:            (Horde_Log_Logger, optional) A logger object.
 91:      *     - lock_api:          (Horde_Lock, optional) A locking object.
 92:      *     - history_api:       (Horde_History, optional) A history object.
 93:      *     - login_block_count: (integer, optional) How many failed logins
 94:      *                          trigger autoblocking? 0 disables the feature.
 95:      *     - login_block_time:  (integer, options) How many minutes should
 96:      *                          autoblocking last? 0 means no expiration.
 97:      */
 98:     public function __construct(array $params = array())
 99:     {
100:         if (isset($params['logger'])) {
101:             $this->_logger = $params['logger'];
102:             unset($params['logger']);
103:         }
104: 
105:         if (isset($params['lock_api'])) {
106:             $this->_lock_api = $params['lock_api'];
107:             $this->_capabilities['lock'] = true;
108:             unset($params['lock_api']);
109:         }
110: 
111:         if (isset($params['history_api'])) {
112:             $this->_history_api = $params['history_api'];
113:             $this->_capabilities['badlogincount'] = true;
114:             unset($params['history_api']);
115:         }
116: 
117:         $params = array_merge(array(
118:             'default_user' => ''
119:         ), $params);
120: 
121:         $this->_params = $params;
122:     }
123: 
124:     /**
125:      * Finds out if a set of login credentials are valid, and if requested,
126:      * mark the user as logged in in the current session.
127:      *
128:      * @param string $userId      The userId to check.
129:      * @param array $credentials  The credentials to check.
130:      * @param boolean $login      Whether to log the user in. If false, we'll
131:      *                            only test the credentials and won't modify
132:      *                            the current session. Defaults to true.
133:      *
134:      * @return boolean  Whether or not the credentials are valid.
135:      */
136:     public function authenticate($userId, $credentials, $login = true)
137:     {
138:         $userId = trim($userId);
139: 
140:         try {
141:             $this->_credentials['userId'] = $userId;
142:             if (($this->hasCapability('lock')) &&
143:                 $this->isLocked($userId)) {
144:                 throw new Horde_Auth_Exception('', Horde_Auth::REASON_LOCKED);
145:             }
146:             $this->_authenticate($userId, $credentials);
147:             $this->setCredential('userId', $this->_credentials['userId']);
148:             $this->setCredential('credentials', $credentials);
149:             if ($this->hasCapability('badlogincount')) {
150:                 $this->_resetBadLogins($userId);
151:             }
152:             return true;
153:         } catch (Horde_Auth_Exception $e) {
154:             if (($code = $e->getCode()) &&
155:                 $code != Horde_Auth::REASON_MESSAGE) {
156:                 if (($code == Horde_Auth::REASON_BADLOGIN) &&
157:                     $this->hasCapability('badlogincount')) {
158:                     $this->_badLogin($userId);
159:                 }
160:                 $this->setError($code);
161:             } else {
162:                 $this->setError(Horde_Auth::REASON_MESSAGE, $e->getMessage());
163:             }
164:             return false;
165:         }
166:     }
167: 
168:     /**
169:      * Basic sort implementation.
170:      *
171:      * If the backend has listUsers and doesn't have a native sorting option,
172:      * fall back to this method.
173:      *
174:      * @param array   $users  An array of usernames.
175:      * @param boolean $sort   Whether to sort or not.
176:      *
177:      * @return array the users, sorted or not
178:      *
179:      */
180:     protected function _sort($users, $sort)
181:     {
182:         if ($sort) {
183:             sort($users);
184:         }
185:         return $users;
186:     }
187: 
188:     /**
189:      * Authentication stub.
190:      *
191:      * On failure, Horde_Auth_Exception should pass a message string (if any)
192:      * in the message field, and the Horde_Auth::REASON_* constant in the code
193:      * field (defaults to Horde_Auth::REASON_MESSAGE).
194:      *
195:      * @param string $userID      The userID to check.
196:      * @param array $credentials  An array of login credentials.
197:      *
198:      * @throws Horde_Auth_Exception
199:      */
200:     abstract protected function _authenticate($userId, $credentials);
201: 
202:     /**
203:      * Checks for triggers that may invalidate the current auth.
204:      * These triggers are independent of the credentials.
205:      *
206:      * @return boolean  True if the results of authenticate() are still valid.
207:      */
208:     public function validateAuth()
209:     {
210:         return true;
211:     }
212: 
213:     /**
214:      * Adds a set of authentication credentials.
215:      *
216:      * @param string $userId      The userId to add.
217:      * @param array $credentials  The credentials to use.
218:      *
219:      * @throws Horde_Auth_Exception
220:      */
221:     public function addUser($userId, $credentials)
222:     {
223:         throw new Horde_Auth_Exception('Unsupported.');
224:     }
225: 
226:     /**
227:      * Locks a user indefinitely or for a specified time.
228:      *
229:      * @since Horde_Auth 1.2.0
230:      *
231:      * @param string $userId  The user to lock.
232:      * @param integer $time   The duration in minutes, 0 = permanent.
233:      *
234:      * @throws Horde_Auth_Exception
235:      */
236:     public function lockUser($userId, $time = 0)
237:     {
238:         if (!$this->_lock_api) {
239:             throw new Horde_Auth_Exception('Unsupported.');
240:         }
241: 
242:         if ($time == 0) {
243:             /* Roughly max timestamp32. */
244:             $time = pow(2, 32) - time();
245:         } else {
246:             $time *= 60;
247:         }
248: 
249:         try {
250:             if ($this->_lock_api->setLock($userId, 'horde_auth', 'login:' . $userId, $time, Horde_Lock::TYPE_EXCLUSIVE)) {
251:                 return;
252:             }
253:         } catch (Horde_Lock_Exception $e) {
254:             throw new Horde_Auth_Exception($e);
255:         }
256: 
257:         throw new Horde_Auth_Exception('User is already locked',
258:                                        Horde_Auth::REASON_LOCKED);
259:     }
260: 
261:     /**
262:      * Unlocks a user and optionally resets the bad login count.
263:      *
264:      * @since Horde_Auth 1.2.0
265:      *
266:      * @param string  $userId          The user to unlock.
267:      * @param boolean $resetBadLogins  Reset bad login counter?
268:      *
269:      * @throws Horde_Auth_Exception
270:      */
271:     public function unlockUser($userId, $resetBadLogins = false)
272:     {
273:         if (!$this->_lock_api) {
274:             throw new Horde_Auth_Exception('Unsupported.');
275:         }
276: 
277:         try {
278:             $locks = $this->_lock_api->getLocks(
279:                 'horde_auth', 'login:' . $userId, Horde_Lock::TYPE_EXCLUSIVE);
280:             $lock_id = key($locks);
281:             if ($lock_id) {
282:                 $this->_lock_api->clearLock($lock_id);
283:             }
284:             if ($resetBadLogins) {
285:                 $this->_resetBadLogins($userId);
286:             }
287:         } catch (Horde_Lock_Exception $e) {
288:             throw new Horde_Auth_Exception($e);
289:         }
290:     }
291: 
292:     /**
293:      * Returns whether a user is currently locked.
294:      *
295:      * @since Horde_Auth 1.2.0
296:      *
297:      * @param string $userId         The user to check.
298:      * @param boolean $show_details  Return timeout too?
299:      *
300:      * @return boolean|array  If $show_details is a true, an array with
301:      *                        'locked' and 'lock_timeout' values. Whether the
302:      *                        user is locked, otherwise.
303:      * @throws Horde_Auth_Exception
304:      */
305:     public function isLocked($userId, $show_details = false)
306:     {
307:         if (!$this->_lock_api) {
308:             throw new Horde_Auth_Exception('Unsupported.');
309:         }
310: 
311:         try  {
312:             $locks = $this->_lock_api->getLocks(
313:                 'horde_auth', 'login:' . $userId, Horde_Lock::TYPE_EXCLUSIVE);
314:         } catch (Horde_Lock_Exception $e) {
315:             throw new Horde_Auth_Exception($e);
316:         }
317: 
318:         if ($show_details) {
319:             $lock_id = key($locks);
320:             return empty($lock_id)
321:                 ? array('locked' => false, 'lock_timeout' => 0)
322:                 : array('locked' => true, 'lock_timeout' => $locks[$lock_id]['lock_expiry_timestamp']);
323:         }
324: 
325:         return !empty($locks);
326:     }
327: 
328:     /**
329:      * Handles a bad login.
330:      *
331:      * @since Horde_Auth 1.2.0
332:      *
333:      * @param string $userId  The user with a bad login.
334:      *
335:      * @throws Horde_Auth_Exception
336:      */
337:     protected function _badLogin($userId)
338:     {
339:         if (!$this->_history_api) {
340:             throw new Horde_Auth_Exception('Unsupported.');
341:         }
342: 
343:         $history_identifier = $userId . '@logins.failed';
344:         try {
345:             $this->_history_api->log(
346:                 $history_identifier,
347:                 array('action' => 'login_failed', 'who' => $userId));
348:             $history_log = $this->_history_api->getHistory($history_identifier);
349:             if ($this->_params['login_block_count'] > 0 &&
350:                 $this->_params['login_block_count'] <= $history_log->count() &&
351:                 $this->hasCapability('lock')) {
352:                 $this->lockUser($userId, $this->_params['login_block_time']);
353:             }
354:         } catch (Horde_History_Exception $e) {
355:             throw new Horde_Auth_Exception($e);
356:         }
357:     }
358: 
359:     /**
360:      * Resets the bad login counter.
361:      *
362:      * @since Horde_Auth 1.2.0
363:      *
364:      * @param string $userId  The user to reset.
365:      *
366:      * @throws Horde_Auth_Exception
367:      */
368:     protected function _resetBadLogins($userId)
369:     {
370:         if (!$this->_history_api) {
371:             throw new Horde_Auth_Exception('Unsupported.');
372:         }
373: 
374:         try {
375:             $this->_history_api->removeByNames(array($userId . '@logins.failed'));
376:         } catch (Horde_History_Exception $e) {
377:             throw new Horde_Auth_Exception($e);
378:         }
379:     }
380: 
381:     /**
382:      * Updates a set of authentication credentials.
383:      *
384:      * @param string $oldID       The old userId.
385:      * @param string $newID       The new userId.
386:      * @param array $credentials  The new credentials
387:      *
388:      * @throws Horde_Auth_Exception
389:      */
390:     public function updateUser($oldID, $newID, $credentials)
391:     {
392:         throw new Horde_Auth_Exception('Unsupported.');
393:     }
394: 
395:     /**
396:      * Deletes a set of authentication credentials.
397:      *
398:      * @param string $userId  The userId to delete.
399:      *
400:      * @throws Horde_Auth_Exception
401:      */
402:     public function removeUser($userId)
403:     {
404:         throw new Horde_Auth_Exception('Unsupported.');
405:     }
406: 
407:     /**
408:      * Lists all users in the system.
409:      *
410:      * @return mixed  The array of userIds.
411:      * @throws Horde_Auth_Exception
412:      */
413:     public function listUsers($sort = false)
414:     {
415:         throw new Horde_Auth_Exception('Unsupported.');
416:     }
417: 
418:     /**
419:      * Checks if $userId exists in the system.
420:      *
421:      * @param string $userId  User ID for which to check
422:      *
423:      * @return boolean  Whether or not $userId already exists.
424:      */
425:     public function exists($userId)
426:     {
427:         try {
428:             $users = $this->listUsers();
429:             return in_array($userId, $users);
430:         } catch (Horde_Auth_Exception $e) {
431:             return false;
432:         }
433:     }
434: 
435:     /**
436:      * Automatic authentication.
437:      *
438:      * Transparent authentication should set 'userId', 'credentials', or
439:      * 'params' in $this->_credentials as needed - these values will be used
440:      * to set the credentials in the session.
441:      *
442:      * Transparent authentication should normally never throw an error - false
443:      * should be returned.
444:      *
445:      * @return boolean  Whether transparent login is supported.
446:      * @throws Horde_Auth_Exception
447:      */
448:     public function transparent()
449:     {
450:         return false;
451:     }
452: 
453:     /**
454:      * Reset a user's password. Used for example when the user does not
455:      * remember the existing password.
456:      *
457:      * @param string $userId  The user id for which to reset the password.
458:      *
459:      * @return string  The new password on success.
460:      * @throws Horde_Auth_Exception
461:      */
462:     public function resetPassword($userId)
463:     {
464:         throw new Horde_Auth_Exception('Unsupported.');
465:     }
466: 
467:     /**
468:      * Queries the current driver to find out if it supports the given
469:      * capability.
470:      *
471:      * @param string $capability  The capability to test for.
472:      *
473:      * @return boolean  Whether or not the capability is supported.
474:      */
475:     public function hasCapability($capability)
476:     {
477:         return !empty($this->_capabilities[$capability]);
478:     }
479: 
480:     /**
481:      * Returns the named parameter for the current auth driver.
482:      *
483:      * @param string $param  The parameter to fetch.
484:      *
485:      * @return string  The parameter's value, or null if it doesn't exist.
486:      */
487:     public function getParam($param)
488:     {
489:         return isset($this->_params[$param])
490:             ? $this->_params[$param]
491:             : null;
492:     }
493: 
494:     /**
495:      * Retrieve internal credential value(s).
496:      *
497:      * @param mixed $name  The credential value to get. If null, will return
498:      *                     the entire credential list. Valid names:
499:      * <pre>
500:      * 'change' - (boolean) Do credentials need to be changed?
501:      * 'credentials' - (array) The credentials needed to authenticate.
502:      * 'expire' - (integer) UNIX timestamp of the credential expiration date.
503:      * 'userId' - (string) The user ID.
504:      * </pre>
505:      *
506:      * @return mixed  Return the credential information, or null if the
507:      *                credential doesn't exist.
508:      */
509:     public function getCredential($name = null)
510:     {
511:         if (is_null($name)) {
512:             return $this->_credentials;
513:         }
514: 
515:         return isset($this->_credentials[$name])
516:             ? $this->_credentials[$name]
517:             : null;
518:     }
519: 
520:     /**
521:      * Set internal credential value.
522:      *
523:      * @param string $name  The credential name to set.
524:      * @param mixed $value  The credential value to set. See getCredential()
525:      *                      for the list of valid credentials/types.
526:      */
527:     public function setCredential($type, $value)
528:     {
529:         switch ($type) {
530:         case 'change':
531:             $this->_credentials['change'] = (bool)$value;
532:             break;
533: 
534:         case 'credentials':
535:             $this->_credentials['credentials'] = array_filter(array_merge($this->_credentials['credentials'], $value));
536:             break;
537: 
538:         case 'expire':
539:             $this->_credentials['expire'] = intval($value);
540:             break;
541: 
542:         case 'userId':
543:             $this->_credentials['userId'] = strval($value);
544:             break;
545:         }
546:     }
547: 
548:     /**
549:      * Sets the error message for an invalid authentication.
550:      *
551:      * @param string $type  The type of error (Horde_Auth::REASON_* constant).
552:      * @param string $msg   The error message/reason for invalid
553:      *                      authentication.
554:      */
555:     public function setError($type, $msg = null)
556:     {
557:         $this->_error = array(
558:             'msg' => $msg,
559:             'type' => $type
560:         );
561:     }
562: 
563:     /**
564:      * Returns the error type or message for an invalid authentication.
565:      *
566:      * @param boolean $msg  If true, returns the message string (if set).
567:      *
568:      * @return mixed  Error type, error message (if $msg is true) or false
569:      *                if entry doesn't exist.
570:      */
571:     public function getError($msg = false)
572:     {
573:         return isset($this->_error['type'])
574:             ? ($msg ? $this->_error['msg'] : $this->_error['type'])
575:             : false;
576:     }
577: 
578: }
579: 
API documentation generated by ApiGen