Skip to content

Commit

Permalink
Updated AuthComponent and friends to use new ORM and other 3.x changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
ADmad committed Nov 17, 2013
1 parent 6421ce3 commit aa6088a
Show file tree
Hide file tree
Showing 15 changed files with 256 additions and 247 deletions.
74 changes: 34 additions & 40 deletions Cake/Controller/Component/Auth/BaseAuthenticate.php
Expand Up @@ -16,10 +16,12 @@
namespace Cake\Controller\Component\Auth;

use Cake\Controller\ComponentRegistry;
use Cake\Controller\Component\Auth\AbstractPasswordHasher;
use Cake\Core\App;
use Cake\Error;
use Cake\Network\Request;
use Cake\Network\Response;
use Cake\Utility\ClassRegistry;
use Cake\ORM\TableRegistry;
use Cake\Utility\Hash;
use Cake\Utility\Security;

Expand All @@ -33,28 +35,26 @@ abstract class BaseAuthenticate {
* Settings for this object.
*
* - `fields` The fields to use to identify a user by.
* - `userModel` The model name of the User, defaults to User.
* - `userModel` The alias for users table, defaults to Users.
* - `scope` Additional conditions to use when looking up and authenticating users,
* i.e. `array('User.is_active' => 1).`
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
* i.e. `['Users.is_active' => 1].`
* - `contain` Extra models to contain and store in session.
* - `passwordHasher` Password hasher class. Can be a string specifying class name
* or an array containing `className` key, any other keys will be passed as
* settings to the class. Defaults to 'Simple'.
*
* @var array
*/
public $settings = array(
'fields' => array(
public $settings = [
'fields' => [
'username' => 'username',
'password' => 'password'
),
'userModel' => 'User',
'scope' => array(),
'recursive' => 0,
],
'userModel' => 'Users',
'scope' => [],
'contain' => null,
'passwordHasher' => 'Simple'
);
];

/**
* A Component registry, used to get more components.
Expand Down Expand Up @@ -82,56 +82,48 @@ public function __construct(ComponentRegistry $registry, $settings) {
}

/**
* Find a user record using the standard options.
*
* The $username parameter can be a (string)username or an array containing
* conditions for Model::find('first'). If the $password param is not provided
* the password field will be present in returned array.
* Find a user record using the username and password provided.
*
* Input passwords will be hashed even when a user doesn't exist. This
* helps mitigate timing attacks that are attempting to find valid usernames.
*
* @param string|array $username The username/identifier, or an array of find conditions.
* @param string $password The password, only used if $username param is string.
* @param string $username The username/identifier.
* @param string $password The password, if not provide password checking is skipped
* and result of find is returned.
* @return boolean|array Either false on failure, or an array of user data.
*/
protected function _findUser($username, $password = null) {
$userModel = $this->settings['userModel'];
list(, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];

if (is_array($username)) {
$conditions = $username;
} else {
$conditions = array(
$model . '.' . $fields['username'] => $username
);
}
$conditions = [$model . '.' . $fields['username'] => $username];

if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}

$result = ClassRegistry::init($userModel)->find('first', array(
'conditions' => $conditions,
'recursive' => $this->settings['recursive'],
'contain' => $this->settings['contain'],
));
if (empty($result[$model])) {
$this->passwordHasher()->hash($password);
$table = TableRegistry::get($userModel)->find('all');
if ($this->settings['contain']) {
$table = $table->contain($this->settings['contain']);
}
$result = $table
->where($conditions)
->hydrate(false)
->first();

if (empty($result)) {
return false;
}

$user = $result[$model];
if ($password) {
if (!$this->passwordHasher()->check($password, $user[$fields['password']])) {
if ($password !== null) {
if (!$this->passwordHasher()->check($password, $result[$fields['password']])) {
return false;
}
unset($user[$fields['password']]);
unset($result[$fields['password']]);
}

unset($result[$model]);
return array_merge($user, $result);
return $result;
}

/**
Expand All @@ -154,15 +146,17 @@ public function passwordHasher() {
$config = $this->settings['passwordHasher'];
unset($config['className']);
}

list($plugin, $class) = pluginSplit($class, true);
$className = App::classname($class, 'Controller/Component/Auth', 'PasswordHasher');
if (!class_exists($className)) {
throw new Error\Exception(__d('cake_dev', 'Password hasher class "%s" was not found.', $class));
}
if (!is_subclass_of($className, 'AbstractPasswordHasher')) {

$this->_passwordHasher = new $className($config);
if (!($this->_passwordHasher instanceof AbstractPasswordHasher)) {
throw new Error\Exception(__d('cake_dev', 'Password hasher must extend AbstractPasswordHasher class.'));
}
$this->_passwordHasher = new $className($config);
return $this->_passwordHasher;
}

Expand Down
2 changes: 1 addition & 1 deletion Cake/Controller/Component/Auth/BaseAuthorize.php
Expand Up @@ -65,7 +65,7 @@ abstract class BaseAuthorize {
'delete' => 'delete',
'remove' => 'delete'
),
'userModel' => 'User'
'userModel' => 'Users'
);

/**
Expand Down
2 changes: 1 addition & 1 deletion Cake/Controller/Component/Auth/BasicAuthenticate.php
Expand Up @@ -84,7 +84,7 @@ public function getUser(Request $request) {
*/
public function unauthenticated(Request $request, Response $response) {
$Exception = new Error\UnauthorizedException();
$Exception->responseHeader(array($this->loginHeaders()));
$Exception->responseHeader(array($this->loginHeaders($request)));
throw $Exception;
}

Expand Down
7 changes: 2 additions & 5 deletions Cake/Controller/Component/Auth/DigestAuthenticate.php
Expand Up @@ -19,7 +19,6 @@
use Cake\Controller\Component\Auth\BasicAuthenticate;
use Cake\Network\Request;
use Cake\Network\Response;
use Cake\Utility\ClassRegistry;

/**
* Digest Authentication adapter for AuthComponent.
Expand Down Expand Up @@ -107,9 +106,7 @@ public function getUser(Request $request) {
}

list(, $model) = pluginSplit($this->settings['userModel']);
$user = $this->_findUser(array(
$model . '.' . $this->settings['fields']['username'] => $digest['username']
));
$user = $this->_findUser($digest['username']);
if (empty($user)) {
return false;
}
Expand Down Expand Up @@ -207,7 +204,7 @@ public function loginHeaders(Request $request) {
'qop' => $this->settings['qop'],
'nonce' => $this->settings['nonce'] ?: uniqid(''),
);
$options['nonce'] = $this->settings['nonce'] ?: $options['realm'];
$options['opaque'] = $this->settings['opaque'] ?: md5($options['realm']);
$opts = array();
foreach ($options as $k => $v) {
$opts[] = sprintf('%s="%s"', $k, $v);
Expand Down
2 changes: 1 addition & 1 deletion Cake/Controller/Component/Auth/FormAuthenticate.php
Expand Up @@ -26,7 +26,7 @@
* {{{
* $this->Auth->authenticate = array(
* 'Form' => array(
* 'scope' => array('User.active' => 1)
* 'scope' => array('Users.active' => 1)
* )
* )
* }}}
Expand Down
17 changes: 9 additions & 8 deletions Cake/Controller/Component/AuthComponent.php
Expand Up @@ -21,9 +21,9 @@
use Cake\Core\Configure;
use Cake\Error;
use Cake\Event\Event;
use Cake\Model\Datasource\Session;
use Cake\Network\Request;
use Cake\Network\Response;
use Cake\Network\Session;
use Cake\Routing\Router;
use Cake\Utility\Debugger;
use Cake\Utility\Hash;
Expand Down Expand Up @@ -57,7 +57,7 @@ class AuthComponent extends Component {
* {{{
* $this->Auth->authenticate = array(
* 'Form' => array(
* 'userModel' => 'Users.User'
* 'userModel' => 'Users.Users'
* )
* );
* }}}
Expand All @@ -69,8 +69,8 @@ class AuthComponent extends Component {
* {{{
* $this->Auth->authenticate = array(
* 'all' => array(
* 'userModel' => 'Users.User',
* 'scope' => array('User.active' => 1)
* 'userModel' => 'Users.Users',
* 'scope' => ['Users.active' => 1]
* ),
* 'Form',
* 'Basic'
Expand Down Expand Up @@ -351,10 +351,11 @@ protected function _unauthenticated(Controller $controller) {
}

if ($this->_isLoginAction($controller)) {
if (empty($controller->request->data)) {
if (!$this->Session->check('Auth.redirect') && env('HTTP_REFERER')) {
$this->Session->write('Auth.redirect', $controller->referer(null, true));
}
if (empty($controller->request->data) &&
!$this->Session->check('Auth.redirect') &&
$this->request->env('HTTP_REFERER')
) {
$this->Session->write('Auth.redirect', $controller->referer(null, true));
}
return true;
}
Expand Down
3 changes: 2 additions & 1 deletion Cake/Test/TestApp/Controller/AjaxAuthController.php
Expand Up @@ -18,6 +18,7 @@
namespace TestApp\Controller;

use Cake\Controller\Controller;
use Cake\Event\Event;

/**
* AjaxAuthController class
Expand Down Expand Up @@ -58,7 +59,7 @@ class AjaxAuthController extends Controller {
*
* @return void
*/
public function beforeFilter() {
public function beforeFilter(Event $event) {
$this->TestAuth->ajaxLogin = 'test_element';
$this->TestAuth->userModel = 'AuthUser';
$this->TestAuth->RequestHandler->ajaxLayout = 'ajax2';
Expand Down
2 changes: 1 addition & 1 deletion Cake/Test/TestApp/Controller/AuthTestController.php
Expand Up @@ -38,7 +38,7 @@ class AuthTestController extends Controller {
*
* @var array
*/
public $uses = array('AuthUser');
public $uses = array('Users');

/**
* components property
Expand Down
22 changes: 22 additions & 0 deletions Cake/Test/TestApp/Model/Repository/AuthUsersTable.php
@@ -0,0 +1,22 @@
<?php
/**
* CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
* Copyright 2005-2013, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice
*
* @since CakePHP(tm) v 3.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace TestApp\Model\Repository;

use Cake\ORM\Table;

/**
* AuthUser class
*
*/
class AuthUsersTable extends Table {

}
Expand Up @@ -62,7 +62,7 @@ protected function _mockAcl() {
*/
public function testAuthorizeFailure() {
$user = array(
'User' => array(
'Users' => array(
'id' => 1,
'user' => 'mariano'
)
Expand All @@ -81,7 +81,7 @@ public function testAuthorizeFailure() {
->with($user, 'controllers/Posts/index')
->will($this->returnValue(false));

$this->assertFalse($this->auth->authorize($user['User'], $request));
$this->assertFalse($this->auth->authorize($user['Users'], $request));
}

/**
Expand All @@ -91,7 +91,7 @@ public function testAuthorizeFailure() {
*/
public function testAuthorizeSuccess() {
$user = array(
'User' => array(
'Users' => array(
'id' => 1,
'user' => 'mariano'
)
Expand All @@ -110,7 +110,7 @@ public function testAuthorizeSuccess() {
->with($user, 'controllers/Posts/index')
->will($this->returnValue(true));

$this->assertTrue($this->auth->authorize($user['User'], $request));
$this->assertTrue($this->auth->authorize($user['Users'], $request));
}

/**
Expand All @@ -128,13 +128,13 @@ public function testAuthorizeSettings() {

$this->_mockAcl();

$this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser';
$this->auth->settings['userModel'] = 'TestPlugin.AuthUser';
$user = array(
'id' => 1,
'user' => 'mariano'
'username' => 'mariano'
);

$expected = array('TestPlugin.TestPluginAuthUser' => array('id' => 1, 'user' => 'mariano'));
$expected = array('TestPlugin.AuthUser' => array('id' => 1, 'username' => 'mariano'));
$this->Acl->expects($this->once())
->method('check')
->with($expected, 'controllers/Posts/index')
Expand Down

0 comments on commit aa6088a

Please sign in to comment.