mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2025-01-31 00:48:25 +00:00
Refactoring AuthComponent and implementing digest authentication in SecurityComponent
git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@5745 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
parent
736ab28b0b
commit
61c06ae94a
3 changed files with 114 additions and 65 deletions
|
@ -54,6 +54,13 @@ class AuthComponent extends Object {
|
|||
* @access public
|
||||
*/
|
||||
var $components = array('Session', 'RequestHandler');
|
||||
/**
|
||||
* A reference to the object used for authentication
|
||||
*
|
||||
* @var object
|
||||
* @access public
|
||||
*/
|
||||
var $authenticate = null;
|
||||
/**
|
||||
* The name of the component to use for Authorization or set this to
|
||||
* 'controller' will validate against Controller::isAuthorized()
|
||||
|
@ -62,7 +69,7 @@ class AuthComponent extends Object {
|
|||
* array('model'=> 'name'); will validate mapActions against model $name::isAuthorize(user, controller, mapAction)
|
||||
* 'object' will validate Controller::action against object::isAuthorized(user, controller, action)
|
||||
*
|
||||
* @var string
|
||||
* @var mixed
|
||||
* @access public
|
||||
*/
|
||||
var $authorize = false;
|
||||
|
@ -97,13 +104,6 @@ class AuthComponent extends Object {
|
|||
* @access public
|
||||
*/
|
||||
var $fields = array('username' => 'username', 'password' => 'password');
|
||||
/**
|
||||
* the hash function to use, options: sha1, sha256, md5
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $hash = 'sha1';
|
||||
/**
|
||||
* The session key name where the record of the current user is stored. If
|
||||
* unspecified, it will be "Auth.{$userModel name}".
|
||||
|
@ -262,16 +262,16 @@ class AuthComponent extends Object {
|
|||
return;
|
||||
}
|
||||
|
||||
if ($this->allowedActions == array('*') || in_array($controller->action, $this->allowedActions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->__setDefaults()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->data = $controller->data = $this->hashPasswords($controller->data);
|
||||
|
||||
if ($this->allowedActions == array('*') || in_array($controller->action, $this->allowedActions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($controller->params['url']['url'])) {
|
||||
$url = '';
|
||||
} else {
|
||||
|
@ -774,6 +774,10 @@ class AuthComponent extends Object {
|
|||
* @return array
|
||||
*/
|
||||
function hashPasswords($data) {
|
||||
if (is_object($this->authenticate) && method_exists($this->authenticate, 'hashPasswords')) {
|
||||
return $this->authenticate->hashPasswords($data);
|
||||
}
|
||||
|
||||
if (isset($data[$this->userModel])) {
|
||||
if (!empty($data[$this->userModel][$this->fields['username']]) && !empty($data[$this->userModel][$this->fields['password']])) {
|
||||
$data[$this->userModel][$this->fields['password']] = $this->password($data[$this->userModel][$this->fields['password']]);
|
||||
|
@ -790,7 +794,7 @@ class AuthComponent extends Object {
|
|||
* @return string
|
||||
*/
|
||||
function password($password) {
|
||||
return Security::hash(CAKE_SESSION_STRING . $password, $this->hash);
|
||||
return Security::hash(CAKE_SESSION_STRING . $password);
|
||||
}
|
||||
/**
|
||||
* Component shutdown. If user is logged in, wipe out redirect.
|
||||
|
|
|
@ -35,13 +35,6 @@
|
|||
* @subpackage cake.cake.libs.controller.components
|
||||
*/
|
||||
class SecurityComponent extends Object {
|
||||
/**
|
||||
* Holds an instance of the core Security object
|
||||
*
|
||||
* @var object Security
|
||||
* @access public
|
||||
*/
|
||||
var $Security = null;
|
||||
/**
|
||||
* The controller method that will be called if this request is black-hole'd
|
||||
*
|
||||
|
@ -88,7 +81,7 @@ class SecurityComponent extends Object {
|
|||
* @access public
|
||||
* @see SecurityComponent::requireLogin()
|
||||
*/
|
||||
var $loginOptions = array('type' => '');
|
||||
var $loginOptions = array('type' => '', 'prompt' => null);
|
||||
/**
|
||||
* An associative array of usernames/passwords used for HTTP-authenticated logins.
|
||||
* If using digest authentication, passwords should be MD5-hashed.
|
||||
|
@ -127,12 +120,6 @@ class SecurityComponent extends Object {
|
|||
* @access public
|
||||
*/
|
||||
var $components = array('RequestHandler', 'Session');
|
||||
/**
|
||||
* Security class initialization
|
||||
*/
|
||||
function initialize(&$controller) {
|
||||
$this->Security =& Security::getInstance();
|
||||
}
|
||||
/**
|
||||
* Component startup. All security checking happens here.
|
||||
*
|
||||
|
@ -196,6 +183,8 @@ class SecurityComponent extends Object {
|
|||
*/
|
||||
function requireLogin() {
|
||||
$args = func_get_args();
|
||||
$base = $this->loginOptions;
|
||||
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
$this->loginOptions = $arg;
|
||||
|
@ -203,6 +192,7 @@ class SecurityComponent extends Object {
|
|||
$this->requireLogin[] = $arg;
|
||||
}
|
||||
}
|
||||
$this->loginOptions = am($base, $this->loginOptions);
|
||||
|
||||
if (empty($this->requireLogin)) {
|
||||
$this->requireLogin = array('*');
|
||||
|
@ -213,41 +203,40 @@ class SecurityComponent extends Object {
|
|||
}
|
||||
}
|
||||
/**
|
||||
* Gets the login credentials for an HTTP-authenticated request
|
||||
* Attempts to validate the login credentials for an HTTP-authenticated request
|
||||
*
|
||||
* @param string $type Either 'basic', 'digest', or null. If null/empty, will try both.
|
||||
* @return mixed If successful, returns an array with login name and password, otherwise null.
|
||||
* @access public
|
||||
*/
|
||||
function loginCredentials($type = null) {
|
||||
if (empty($type) || low($type) == 'basic') {
|
||||
$login = array('username' => env('PHP_AUTH_USER'), 'password' => env('PHP_AUTH_PW'));
|
||||
|
||||
if ($login['username'] != null) {
|
||||
return $login;
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == '' || low($type) == 'digest') {
|
||||
$digest = null;
|
||||
|
||||
if (version_compare(phpversion(), '5.1') != -1) {
|
||||
$digest = env('PHP_AUTH_DIGEST');
|
||||
} elseif (function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
if (isset($headers['Authorization']) && !empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') {
|
||||
$digest = substr($headers['Authorization'], 7);
|
||||
switch (low($type)) {
|
||||
case 'basic':
|
||||
$login = array('username' => env('PHP_AUTH_USER'), 'password' => env('PHP_AUTH_PW'));
|
||||
if (!empty($login['username'])) {
|
||||
return $login;
|
||||
}
|
||||
} else {
|
||||
// Server doesn't support digest-auth headers
|
||||
trigger_error(__('SecurityComponent::loginCredentials() - Server does not support digest authentication', true), E_USER_WARNING);
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case 'digest':
|
||||
default:
|
||||
$digest = null;
|
||||
|
||||
if ($digest == null) {
|
||||
return null;
|
||||
}
|
||||
$data = $this->parseDigestAuthData($digest);
|
||||
if (version_compare(phpversion(), '5.1') != -1) {
|
||||
$digest = env('PHP_AUTH_DIGEST');
|
||||
} elseif (function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
if (isset($headers['Authorization']) && !empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') {
|
||||
$digest = substr($headers['Authorization'], 7);
|
||||
}
|
||||
} else {
|
||||
// Server doesn't support digest-auth headers
|
||||
trigger_error(__('SecurityComponent::loginCredentials() - Server does not support digest authentication', true), E_USER_WARNING);
|
||||
}
|
||||
|
||||
if (!empty($digest)) {
|
||||
return $this->parseDigestAuthData($digest);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -261,8 +250,16 @@ class SecurityComponent extends Object {
|
|||
function loginRequest($options = array()) {
|
||||
$options = am($this->loginOptions, $options);
|
||||
$this->__setLoginDefaults($options);
|
||||
$data = 'WWW-Authenticate: ' . ucfirst($options['type']) . ' realm="' . $options['realm'] . '"';
|
||||
return $data;
|
||||
$auth = 'WWW-Authenticate: ' . ucfirst($options['type']);
|
||||
$out = array('realm="' . $options['realm'] . '"');
|
||||
|
||||
if (low($options['type']) == 'digest') {
|
||||
$out[] = 'qop="auth"';
|
||||
$out[] = 'nonce="' . uniqid() . '"'; //str_replace('-', '', String::uuid())
|
||||
$out[] = 'opaque="' . md5($options['realm']).'"';
|
||||
}
|
||||
|
||||
return $auth . ' ' . join(',', $out);
|
||||
}
|
||||
/**
|
||||
* Parses an HTTP digest authentication response, and returns an array of the data, or null on failure.
|
||||
|
@ -291,6 +288,21 @@ class SecurityComponent extends Object {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generates a hash to be compared with an HTTP digest-authenticated response
|
||||
*
|
||||
* @param array $data HTTP digest response data, as parsed by SecurityComponent::parseDigestAuthData()
|
||||
* @return string Digest authentication hash
|
||||
* @access public
|
||||
* @see SecurityComponent::parseDigestAuthData()
|
||||
*/
|
||||
function generateDigestResponseHash($data) {
|
||||
return md5(
|
||||
md5($data['username'] . ':' . $this->loginOptions['realm'] . ':' . $this->loginUsers[$data['username']]) .
|
||||
':' . $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' .
|
||||
md5(env('REQUEST_METHOD') . ':' . $data['uri'])
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Black-hole an invalid request with a 404 error or custom callback
|
||||
*
|
||||
|
@ -398,7 +410,7 @@ class SecurityComponent extends Object {
|
|||
// User hasn't been authenticated yet
|
||||
header($this->loginRequest());
|
||||
|
||||
if (isset($this->loginOptions['prompt'])) {
|
||||
if (!empty($this->loginOptions['prompt'])) {
|
||||
$this->__callback($controller, $this->loginOptions['prompt']);
|
||||
} else {
|
||||
$this->blackHole($controller, 'login');
|
||||
|
@ -409,6 +421,12 @@ class SecurityComponent extends Object {
|
|||
} else {
|
||||
if (low($this->loginOptions['type']) == 'digest') {
|
||||
// Do digest authentication
|
||||
if ($login && isset($this->loginUsers[$login['username']])) {
|
||||
if ($login['response'] == $this->generateDigestResponseHash($login)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->blackHole($controller, 'login');
|
||||
} else {
|
||||
if (!(in_array($login['username'], array_keys($this->loginUsers)) && $this->loginUsers[$login['username']] == $login['password'])) {
|
||||
$this->blackHole($controller, 'login');
|
||||
|
@ -579,11 +597,12 @@ class SecurityComponent extends Object {
|
|||
* @access private
|
||||
*/
|
||||
function __setLoginDefaults(&$options) {
|
||||
$options = am(array('type' => 'basic',
|
||||
'realm' => env('SERVER_NAME'),
|
||||
'qop' => 'auth',
|
||||
'nonce' => String::uuid()),
|
||||
array_filter($options));
|
||||
$options = am(array(
|
||||
'type' => 'basic',
|
||||
'realm' => env('SERVER_NAME'),
|
||||
'qop' => 'auth',
|
||||
'nonce' => String::uuid()
|
||||
), array_filter($options));
|
||||
$options = am(array('opaque' => md5($options['realm'])), $options);
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -34,7 +34,15 @@
|
|||
* @package cake
|
||||
* @subpackage cake.cake.libs
|
||||
*/
|
||||
class Security extends Object{
|
||||
class Security extends Object {
|
||||
|
||||
/**
|
||||
* Default hash method
|
||||
*
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
var $hashType = null;
|
||||
/**
|
||||
* Singleton implementation to get object instance.
|
||||
*
|
||||
|
@ -106,10 +114,14 @@ class Security extends Object{
|
|||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function hash($string, $type = 'sha1') {
|
||||
function hash($string, $type = null) {
|
||||
$_this =& Security::getInstance();
|
||||
if (empty($type)) {
|
||||
$type = $_this->hashType;
|
||||
}
|
||||
$type = strtolower($type);
|
||||
if ($type == 'sha1') {
|
||||
|
||||
if ($type == 'sha1' || $type == null) {
|
||||
if (function_exists('sha1')) {
|
||||
$return = sha1($string);
|
||||
return $return;
|
||||
|
@ -132,6 +144,20 @@ class Security extends Object{
|
|||
return $return;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the default hash method for the Security object. This affects all objects using
|
||||
* Security::hash().
|
||||
*
|
||||
* @param string $hash Method to use (sha1/sha256/md5)
|
||||
* @return void
|
||||
* @access public
|
||||
* @static
|
||||
* @see Security::hash()
|
||||
*/
|
||||
function setHash($hash) {
|
||||
$_this =& Security::getInstance();
|
||||
$_this->hashType = $hash;
|
||||
}
|
||||
/**
|
||||
* Encripts/Decrypts a text using the given key.
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue