You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

233 lines
9.7 KiB

<?php
/**
* li₃: the most RAD framework for PHP (http://li3.me)
*
* Copyright 2009, Union of RAD. All rights reserved. This source
* code is distributed under the terms of the BSD 3-Clause License.
* The full license text can be found in the LICENSE.txt file.
*/
namespace lithium\security;
use lithium\aop\Filters;
use lithium\core\ConfigException;
/**
* The `Auth` class provides a common interface to authenticate user credentials from different
* sources against different storage backends in a uniform way. As with most other adapter-driven
* classes in the framework, `Auth` allows you to specify one or more named configurations,
* including an adapter, which can be referenced by name in your application.
*
* `Auth` is responsible for managing session state for each configuration, and exposes a set of
* methods which adapters can implement: `set()`, `check()` and `clear()`. You can read more about
* each method below. Beyond these methods, `Auth` makes very few assumptions about how your
* application authenticates users. Each adapter accepts a set of credentials, and returns an array
* of user information on success, and `false` on failure. On successful authentication attempts,
* the data returned from the credential check is written to the session, which is automatically
* accessed on subsequent checks (though manual re-checking can be forced on a per-instance basis).
*
* To be secure by default (and if you don't override it), a `password` field is never stored in
* the session adapter. This prevents a possible password hash to be leaked in a cookie (for
* example). You can also be very specific on what you want to store in the session:
*
* ```
* Auth::config([
* 'default' => [
* 'session' => [
* 'persist' => ['username', 'email']
* ]
* ]
* ]);
* ```
*
* You can also pass an optional `persist` param to the `check` method to override this default.
*
* For additional information on configuring and working with `Auth`, see the `Form` adapter.
*
* @see lithium\security\auth\adapter\Form
*/
class Auth extends \lithium\core\Adaptable {
/**
* Stores configurations for various authentication adapters.
*
* @var object `Collection` of authentication configurations.
*/
protected static $_configurations = [];
/**
* Libraries::locate() compatible path to adapters for this class.
*
* @see lithium\core\Libraries::locate()
* @var string Dot-delimited path.
*/
protected static $_adapters = 'adapter.security.auth';
/**
* Dynamic class dependencies.
*
* @var array Associative array of class names & their namespaces.
*/
protected static $_classes = [
'session' => 'lithium\storage\Session'
];
/**
* Called when an adapter configuration is first accessed, this method sets the default
* configuration for session handling. While each configuration can use its own session class
* and options, this method initializes them to the default dependencies written into the class.
* For the session key name, the default value is set to the name of the configuration.
*
* @param string $name The name of the adapter configuration being accessed.
* @param array $config The user-specified configuration.
* @return array Returns an array that merges the user-specified configuration with the
* generated default values.
*/
protected static function _initConfig($name, $config) {
$defaults = ['session' => [
'key' => $name,
'class' => static::$_classes['session'],
'options' => [],
'persist' => []
]];
$config = parent::_initConfig($name, $config) + $defaults;
$config['session'] += $defaults['session'];
return $config;
}
/**
* Performs an authentication check against the specified configuration, and writes the
* resulting user information to the session such that credentials are not required for
* subsequent authentication checks, and user information is returned directly from the session.
*
* @param string $name The name of the `Auth` configuration/adapter to check against.
* @param mixed $credentials A container for the authentication credentials used in this check.
* This will vary by adapter, but generally will be an object or array containing
* a user name and password. In the case of the `Form` adapter, it contains a
* `Request` object containing `POST` data with user login information.
* @param array $options Additional options used when performing the authentication check. The
* options available will vary by adapter, please consult the documentation for the
* `check()` method of the adapter you intend to use. The global options for this
* method are:
* - `'checkSession'` _boolean_: By default, the session store configured for the
* adapter will always be queried first, to see if an authentication check has
* already been performed during the current user session. If yes, then the
* session data will be returned. By setting `'checkSession'` to `false`,
* session checks are bypassed and the credentials provided are always checked
* against the adapter directly.
* - `'writeSession'` _boolean_: Upon a successful credentials check, the returned
* user information is, by default, written to the session. Set this to `false`
* to disable session writing for this authentication check.
* - `'persist'` _array_: A list of fields that should be stored in the session.
* If no list is provided will store all fields in the session except
* the `'password'` field.
* @return array After a successful credential check against the adapter (or a successful
* lookup against the current session), returns an array of user information from the
* storage backend used by the configured adapter.
* @filter
*/
public static function check($name, $credentials = null, array $options = []) {
$config = static::config($name);
$defaults = [
'checkSession' => true,
'writeSession' => true,
'persist' => $config['session']['persist'] ?: static::_config('persist')
];
$options += $defaults;
$params = compact('name', 'credentials', 'options');
return Filters::run(get_called_class(), __FUNCTION__, $params, function($params) {
extract($params);
$config = static::_config($name);
if ($config === null) {
throw new ConfigException("Configuration `{$name}` has not been defined.");
}
$session = $config['session'];
if ($options['checkSession']) {
if ($data = $session['class']::read($session['key'], $session['options'])) {
return $data;
}
}
if (($credentials) && $data = static::adapter($name)->check($credentials, $options)) {
if ($options['persist'] && is_array($data)) {
$data = array_intersect_key($data, array_fill_keys($options['persist'], true));
} elseif (is_array($data)) {
unset($data['password']);
}
return ($options['writeSession']) ? static::set($name, $data) : $data;
}
return false;
});
}
/**
* Manually authenticate a user with the given set of data. Rather than checking a user's
* credentials, this method allows you to manually specify a user for whom you'd like to
* initialize an authenticated session.
*
* By default, before writing the data to the session, the `set()` method of the named
* configuration's adapter receives the data to be written, and has an opportunity to modify
* or reject it.
*
* @param string $name The name of the adapter configuration to.
* @param array $data The user data to be written to the session.
* @param array $options Any additional session-writing options. These may override any options
* set by the default session configuration for `$name`.
* @return array Returns the array of data written to the session, or `false` if the adapter
* rejects the data.
* @filter
*/
public static function set($name, $data, array $options = []) {
$params = compact('name', 'data', 'options');
return Filters::run(get_called_class(), __FUNCTION__, $params, function($params) {
extract($params);
$config = static::_config($name);
$session = $config['session'];
if ($data = static::adapter($name)->set($data, $options)) {
$session['class']::write($session['key'], $data, $options + $session['options']);
return $data;
}
return false;
});
}
/**
* Removes session information for the given configuration, and allows the configuration's
* adapter to perform any associated cleanup tasks.
*
* @param string $name The name of the `Auth` configuration to clear the login information for.
* Calls the `clear()` method of the given configuration's adapter, and removes
* the information in the session key used by this configuration.
* @param array $options Additional options used when clearing the authenticated session. See
* each adapter's `clear()` method for all available options. Global options:
* - `'clearSession'` _boolean_: If `true` (the default), session data for the
* specified configuration is removed, otherwise it is retained.
* @return void
* @filter
*/
public static function clear($name, array $options = []) {
$defaults = ['clearSession' => true];
$options += $defaults;
$params = compact('name', 'options');
return Filters::run(get_called_class(), __FUNCTION__, $params, function($params) {
extract($params);
$config = static::_config($name);
$session = $config['session'];
if ($options['clearSession']) {
$session['class']::delete($session['key'], $session['options']);
}
static::adapter($name)->clear($options);
});
}
}
?>