Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add BlowfishAuthenticate adapter.

  • Loading branch information...
commit d24bbcb2550aadadb6e7b2d333d559dc0bc84da5 1 parent 8e93c47
sitedyno sitedyno authored
30 lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
View
@@ -66,19 +66,28 @@ public function __construct(ComponentCollection $collection, $settings) {
/**
* Find a user record using the standard options.
*
- * @param string $username The username/identifier.
- * @param string $password The unhashed password.
+ * The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). If
+ * the password field is not included in the conditions the password will be returned.
+ *
+ * @param Mixed $conditions The username/identifier, or an array of find conditions.
+ * @param Mixed $password The password, only use if passing as $conditions = 'username'.
* @return Mixed Either false on failure, or an array of user data.
*/
- protected function _findUser($username, $password) {
+ protected function _findUser($conditions, $password = null) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
- $conditions = array(
- $model . '.' . $fields['username'] => $username,
- $model . '.' . $fields['password'] => $this->_password($password),
- );
+ if (!is_array($conditions)) {
+ if (!$password) {
+ return false;
+ }
+ $username = $conditions;
+ $conditions = array(
+ $model . '.' . $fields['username'] => $username,
+ $model . '.' . $fields['password'] => $this->_password($password),
+ );
+ }
if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}
@@ -91,7 +100,12 @@ protected function _findUser($username, $password) {
return false;
}
$user = $result[$model];
- unset($user[$fields['password']]);
+ if (
+ isset($conditions[$model . '.' . $fields['password']]) ||
+ isset($conditions[$fields['password']])
+ ) {
+ unset($user[$fields['password']]);
+ }
unset($result[$model]);
return array_merge($user, $result);
}
75 lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php
View
@@ -0,0 +1,75 @@
+<?php
+/**
+ * PHP 5
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of the files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://cakephp.org CakePHP(tm) Project
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+App::uses('FormAuthenticate', 'Controller/Component/Auth');
+
+/**
+ * An authentication adapter for AuthComponent. Provides the ability to authenticate using POST data using Blowfish
+ * hashing. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
+ *
+ * {{{
+ * $this->Auth->authenticate = array(
+ * 'Blowfish' => array(
+ * 'scope' => array('User.active' => 1)
+ * )
+ * )
+ * }}}
+ *
+ * When configuring BlowfishAuthenticate you can pass in settings to which fields, model and additional conditions
+ * are used. See BlowfishAuthenticate::$settings for more information.
+ *
+ * @package Cake.Controller.Component.Auth
+ * @since CakePHP(tm) v 2.3
+ * @see AuthComponent::$authenticate
+ */
+class BlowfishAuthenticate extends FormAuthenticate {
+
+/**
+ * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
+ * to find POST data that is used to find a matching record in the`settings.userModel`. Will return false if
+ * there is no post data, either username or password is missing, or if the scope conditions have not been met.
+ *
+ * @param CakeRequest $request The request that contains login information.
+ * @param CakeResponse $response Unused response object.
+ * @return mixed False on login failure. An array of User data on success.
+ */
+ public function authenticate(CakeRequest $request, CakeResponse $response) {
+ $userModel = $this->settings['userModel'];
+ list($plugin, $model) = pluginSplit($userModel);
+
+ $fields = $this->settings['fields'];
+ if (!$this->_checkFields($request, $model, $fields)) {
+ return false;
+ }
+ $user = $this->_findUser(
+ array(
+ $model . '.' . $fields['username'] => $request->data[$model][$fields['username']],
+ )
+ );
+ if (!$user) {
+ return false;
+ }
+ $password = Security::hash(
+ $request->data[$model][$fields['password']],
+ 'blowfish',
+ $user[$fields['password']]
+ );
+ if ($password === $user[$fields['password']]) {
+ unset($user[$fields['password']]);
+ return $user;
+ }
+ return false;
+ }
+}
29 lib/Cake/Controller/Component/Auth/FormAuthenticate.php
View
@@ -37,6 +37,27 @@
class FormAuthenticate extends BaseAuthenticate {
/**
+ * Checks the fields to ensure they are supplied.
+ *
+ * @param CakeRequest $request The request that contains login information.
+ * @param string $model The model used for login verification.
+ * @param array $fields The fields to be checked.
+ * @return boolean False if the fields have not been supplied. True if they exist.
+ */
+ protected function _checkFields(CakeRequest $request, $model, $fields) {
+ if (empty($request->data[$model])) {
+ return false;
+ }
+ if (
+ empty($request->data[$model][$fields['username']]) ||
+ empty($request->data[$model][$fields['password']])
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+/**
* Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
* to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
* there is no post data, either username or password is missing, of if the scope conditions have not been met.
@@ -50,13 +71,7 @@ public function authenticate(CakeRequest $request, CakeResponse $response) {
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
- if (empty($request->data[$model])) {
- return false;
- }
- if (
- empty($request->data[$model][$fields['username']]) ||
- empty($request->data[$model][$fields['password']])
- ) {
+ if (!$this->_checkFields($request, $model, $fields)) {
return false;
}
return $this->_findUser(
206 lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php
View
@@ -0,0 +1,206 @@
+<?php
+/**
+ * BlowfishAuthenticateTest file
+ *
+ * PHP 5
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under the MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://cakephp.org CakePHP(tm) Project
+ * @package Cake.Test.Case.Controller.Component.Auth
+ * @since CakePHP(tm) v 2.3
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+App::uses('AuthComponent', 'Controller/Component');
+App::uses('BlowfishAuthenticate', 'Controller/Component/Auth');
+App::uses('AppModel', 'Model');
+App::uses('CakeRequest', 'Network');
+App::uses('CakeResponse', 'Network');
+App::uses('Security', 'Utility');
+
+require_once CAKE . 'Test' . DS . 'Case' . DS . 'Model' . DS . 'models.php';
+
+/**
+ * Test case for BlowfishAuthentication
+ *
+ * @package Cake.Test.Case.Controller.Component.Auth
+ */
+class BlowfishAuthenticateTest extends CakeTestCase {
+
+ public $fixtures = array('core.user', 'core.auth_user');
+
+/**
+ * setup
+ *
+ * @return void
+ */
+ public function setUp() {
+ parent::setUp();
+ $this->Collection = $this->getMock('ComponentCollection');
+ $this->auth = new BlowfishAuthenticate($this->Collection, array(
+ 'fields' => array('username' => 'user', 'password' => 'password'),
+ 'userModel' => 'User'
+ ));
+ $password = Security::hash('password', 'blowfish');
+ $User = ClassRegistry::init('User');
+ $User->updateAll(array('password' => $User->getDataSource()->value($password)));
+ $this->response = $this->getMock('CakeResponse');
+ }
+
+/**
+ * test applying settings in the constructor
+ *
+ * @return void
+ */
+ public function testConstructor() {
+ $Object = new BlowfishAuthenticate($this->Collection, array(
+ 'userModel' => 'AuthUser',
+ 'fields' => array('username' => 'user', 'password' => 'password')
+ ));
+ $this->assertEquals('AuthUser', $Object->settings['userModel']);
+ $this->assertEquals(array('username' => 'user', 'password' => 'password'), $Object->settings['fields']);
+ }
+
+/**
+ * testAuthenticateNoData method
+ *
+ * @return void
+ */
+ public function testAuthenticateNoData() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array();
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateNoUsername method
+ *
+ * @return void
+ */
+ public function testAuthenticateNoUsername() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array('password' => 'foobar'));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateNoPassword method
+ *
+ * @return void
+ */
+ public function testAuthenticateNoPassword() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array('user' => 'mariano'));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticatePasswordIsFalse method
+ *
+ * @return void
+ */
+ public function testAuthenticatePasswordIsFalse() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array(
+ 'User' => array(
+ 'user' => 'mariano',
+ 'password' => null
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateInjection method
+ *
+ * @return void
+ */
+ public function testAuthenticateInjection() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array(
+ 'user' => '> 1',
+ 'password' => "' OR 1 = 1"
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testAuthenticateSuccess method
+ *
+ * @return void
+ */
+ public function testAuthenticateSuccess() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array(
+ 'user' => 'mariano',
+ 'password' => 'password'
+ ));
+ $result = $this->auth->authenticate($request, $this->response);
+ $expected = array(
+ 'id' => 1,
+ 'user' => 'mariano',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31',
+ );
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * testAuthenticateScopeFail method
+ *
+ * @return void
+ */
+ public function testAuthenticateScopeFail() {
+ $this->auth->settings['scope'] = array('user' => 'nate');
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('User' => array(
+ 'user' => 'mariano',
+ 'password' => 'password'
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
+ * testPluginModel method
+ *
+ * @return void
+ */
+ public function testPluginModel() {
+ Cache::delete('object_map', '_cake_core_');
+ App::build(array(
+ 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
+ ), App::RESET);
+ CakePlugin::load('TestPlugin');
+
+ $PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser');
+ $user['id'] = 1;
+ $user['username'] = 'gwoo';
+ $user['password'] = Security::hash('password', 'blowfish');
+ $PluginModel->save($user, false);
+
+ $this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser';
+ $this->auth->settings['fields']['username'] = 'username';
+
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array('TestPluginAuthUser' => array(
+ 'username' => 'gwoo',
+ 'password' => 'password'
+ ));
+
+ $result = $this->auth->authenticate($request, $this->response);
+ $expected = array(
+ 'id' => 1,
+ 'username' => 'gwoo',
+ 'created' => '2007-03-17 01:16:23'
+ );
+ $this->assertEquals(self::date(), $result['updated']);
+ unset($result['updated']);
+ $this->assertEquals($expected, $result);
+ CakePlugin::unload();
+ }
+}
15 lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
View
@@ -100,6 +100,21 @@ public function testAuthenticateNoPassword() {
}
/**
+ * test authenticate password is false method
+ *
+ * @return void
+ */
+ public function testAuthenticatePasswordIsFalse() {
+ $request = new CakeRequest('posts/index', false);
+ $request->data = array(
+ 'User' => array(
+ 'user' => 'mariano',
+ 'password' => null
+ ));
+ $this->assertFalse($this->auth->authenticate($request, $this->response));
+ }
+
+/**
* test the authenticate method
*
* @return void
Please sign in to comment.
Something went wrong with that request. Please try again.