Skip to content
This repository
Browse code

Add BlowfishAuthenticate adapter.

  • Loading branch information...
commit d24bbcb2550aadadb6e7b2d333d559dc0bc84da5 1 parent 8e93c47
sitedyno authored August 15, 2012
30  lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
@@ -66,19 +66,28 @@ public function __construct(ComponentCollection $collection, $settings) {
66 66
 /**
67 67
  * Find a user record using the standard options.
68 68
  *
69  
- * @param string $username The username/identifier.
70  
- * @param string $password The unhashed password.
  69
+ * The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). If
  70
+ * the password field is not included in the conditions the password will be returned.
  71
+ *
  72
+ * @param Mixed $conditions The username/identifier, or an array of find conditions.
  73
+ * @param Mixed $password The password, only use if passing as $conditions = 'username'.
71 74
  * @return Mixed Either false on failure, or an array of user data.
72 75
  */
73  
-	protected function _findUser($username, $password) {
  76
+	protected function _findUser($conditions, $password = null) {
74 77
 		$userModel = $this->settings['userModel'];
75 78
 		list($plugin, $model) = pluginSplit($userModel);
76 79
 		$fields = $this->settings['fields'];
77 80
 
78  
-		$conditions = array(
79  
-			$model . '.' . $fields['username'] => $username,
80  
-			$model . '.' . $fields['password'] => $this->_password($password),
81  
-		);
  81
+		if (!is_array($conditions)) {
  82
+			if (!$password) {
  83
+				return false;
  84
+			}
  85
+			$username = $conditions;
  86
+			$conditions = array(
  87
+				$model . '.' . $fields['username'] => $username,
  88
+				$model . '.' . $fields['password'] => $this->_password($password),
  89
+			);
  90
+		}
82 91
 		if (!empty($this->settings['scope'])) {
83 92
 			$conditions = array_merge($conditions, $this->settings['scope']);
84 93
 		}
@@ -91,7 +100,12 @@ protected function _findUser($username, $password) {
91 100
 			return false;
92 101
 		}
93 102
 		$user = $result[$model];
94  
-		unset($user[$fields['password']]);
  103
+		if (
  104
+			isset($conditions[$model . '.' . $fields['password']]) ||
  105
+			isset($conditions[$fields['password']])
  106
+		) {
  107
+			unset($user[$fields['password']]);
  108
+		}
95 109
 		unset($result[$model]);
96 110
 		return array_merge($user, $result);
97 111
 	}
75  lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php
... ...
@@ -0,0 +1,75 @@
  1
+<?php
  2
+/**
  3
+ * PHP 5
  4
+ *
  5
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6
+ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  7
+ *
  8
+ * Licensed under The MIT License
  9
+ * Redistributions of the files must retain the above copyright notice.
  10
+ *
  11
+ * @copyright	Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  12
+ * @link	http://cakephp.org CakePHP(tm) Project
  13
+ * @license	MIT License (http://www.opensource.org/licenses/mit-license.php)
  14
+ */
  15
+
  16
+App::uses('FormAuthenticate', 'Controller/Component/Auth');
  17
+
  18
+/**
  19
+ * An authentication adapter for AuthComponent. Provides the ability to authenticate using POST data using Blowfish
  20
+ * hashing. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
  21
+ *
  22
+ * {{{
  23
+ * 	$this->Auth->authenticate = array(
  24
+ * 		'Blowfish' => array(
  25
+ * 			'scope' => array('User.active' => 1)
  26
+ * 		)
  27
+ * 	)
  28
+ * }}}
  29
+ *
  30
+ * When  configuring BlowfishAuthenticate you can pass in settings to which fields, model and additional conditions
  31
+ * are used. See BlowfishAuthenticate::$settings for more information.
  32
+ *
  33
+ * @package	Cake.Controller.Component.Auth
  34
+ * @since	CakePHP(tm) v 2.3
  35
+ * @see		AuthComponent::$authenticate
  36
+ */
  37
+class BlowfishAuthenticate extends FormAuthenticate {
  38
+
  39
+/**
  40
+ * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
  41
+ * to find POST data that is used to find a matching record in the`settings.userModel`. Will return false if
  42
+ * there is no post data, either username or password is missing, or if the scope conditions have not been met.
  43
+ *
  44
+ * @param CakeRequest $request The request that contains login information.
  45
+ * @param CakeResponse $response Unused response object.
  46
+ * @return mixed False on login failure. An array of User data on success.
  47
+ */
  48
+	public function authenticate(CakeRequest $request, CakeResponse $response) {
  49
+		$userModel = $this->settings['userModel'];
  50
+		list($plugin, $model) = pluginSplit($userModel);
  51
+
  52
+		$fields = $this->settings['fields'];
  53
+		if (!$this->_checkFields($request, $model, $fields)) {
  54
+			return false;
  55
+		}
  56
+		$user = $this->_findUser(
  57
+			array(
  58
+				$model . '.' . $fields['username'] => $request->data[$model][$fields['username']],
  59
+			)
  60
+		);
  61
+		if (!$user) {
  62
+			return false;
  63
+		}
  64
+		$password = Security::hash(
  65
+			$request->data[$model][$fields['password']],
  66
+			'blowfish',
  67
+			$user[$fields['password']]
  68
+		);
  69
+		if ($password === $user[$fields['password']]) {
  70
+			unset($user[$fields['password']]);
  71
+			return $user;
  72
+		}
  73
+		return false;
  74
+	}
  75
+}
29  lib/Cake/Controller/Component/Auth/FormAuthenticate.php
@@ -37,6 +37,27 @@
37 37
 class FormAuthenticate extends BaseAuthenticate {
38 38
 
39 39
 /**
  40
+ * Checks the fields to ensure they are supplied.
  41
+ *
  42
+ * @param CakeRequest $request The request that contains login information.
  43
+ * @param string $model The model used for login verification.
  44
+ * @param array $fields The fields to be checked.
  45
+ * @return boolean False if the fields have not been supplied. True if they exist.
  46
+ */
  47
+	protected function _checkFields(CakeRequest $request, $model, $fields) {
  48
+		if (empty($request->data[$model])) {
  49
+			return false;
  50
+		}
  51
+		if (
  52
+			empty($request->data[$model][$fields['username']]) ||
  53
+			empty($request->data[$model][$fields['password']])
  54
+		) {
  55
+			return false;
  56
+		}
  57
+		return true;
  58
+	}
  59
+
  60
+/**
40 61
  * Authenticates the identity contained in a request.  Will use the `settings.userModel`, and `settings.fields`
41 62
  * to find POST data that is used to find a matching record in the `settings.userModel`.  Will return false if
42 63
  * 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) {
50 71
 		list($plugin, $model) = pluginSplit($userModel);
51 72
 
52 73
 		$fields = $this->settings['fields'];
53  
-		if (empty($request->data[$model])) {
54  
-			return false;
55  
-		}
56  
-		if (
57  
-			empty($request->data[$model][$fields['username']]) ||
58  
-			empty($request->data[$model][$fields['password']])
59  
-		) {
  74
+		if (!$this->_checkFields($request, $model, $fields)) {
60 75
 			return false;
61 76
 		}
62 77
 		return $this->_findUser(
206  lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php
... ...
@@ -0,0 +1,206 @@
  1
+<?php
  2
+/**
  3
+ * BlowfishAuthenticateTest file
  4
+ *
  5
+ * PHP 5
  6
+ *
  7
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8
+ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9
+ *
  10
+ * Licensed under the MIT License
  11
+ * Redistributions of files must retain the above copyright notice.
  12
+ *
  13
+ * @copyright	Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14
+ * @link	http://cakephp.org CakePHP(tm) Project
  15
+ * @package	Cake.Test.Case.Controller.Component.Auth
  16
+ * @since	CakePHP(tm) v 2.3
  17
+ * @license	MIT License (http://www.opensource.org/licenses/mit-license.php)
  18
+ */
  19
+
  20
+App::uses('AuthComponent', 'Controller/Component');
  21
+App::uses('BlowfishAuthenticate', 'Controller/Component/Auth');
  22
+App::uses('AppModel', 'Model');
  23
+App::uses('CakeRequest', 'Network');
  24
+App::uses('CakeResponse', 'Network');
  25
+App::uses('Security', 'Utility');
  26
+
  27
+require_once CAKE . 'Test' . DS . 'Case' . DS . 'Model' . DS . 'models.php';
  28
+
  29
+/**
  30
+ * Test case for BlowfishAuthentication
  31
+ *
  32
+ * @package	Cake.Test.Case.Controller.Component.Auth
  33
+ */
  34
+class BlowfishAuthenticateTest extends CakeTestCase {
  35
+
  36
+	public $fixtures = array('core.user', 'core.auth_user');
  37
+
  38
+/**
  39
+ * setup
  40
+ *
  41
+ * @return void
  42
+ */
  43
+	public function setUp() {
  44
+		parent::setUp();
  45
+		$this->Collection = $this->getMock('ComponentCollection');
  46
+		$this->auth = new BlowfishAuthenticate($this->Collection, array(
  47
+			'fields' => array('username' => 'user', 'password' => 'password'),
  48
+			'userModel' => 'User'
  49
+		));
  50
+		$password = Security::hash('password', 'blowfish');
  51
+		$User = ClassRegistry::init('User');
  52
+		$User->updateAll(array('password' => $User->getDataSource()->value($password)));
  53
+		$this->response = $this->getMock('CakeResponse');
  54
+	}
  55
+
  56
+/**
  57
+ * test applying settings in the constructor
  58
+ *
  59
+ * @return void
  60
+ */
  61
+	public function testConstructor() {
  62
+		$Object = new BlowfishAuthenticate($this->Collection, array(
  63
+			'userModel' => 'AuthUser',
  64
+			'fields' => array('username' => 'user', 'password' => 'password')
  65
+		));
  66
+		$this->assertEquals('AuthUser', $Object->settings['userModel']);
  67
+		$this->assertEquals(array('username' => 'user', 'password' => 'password'), $Object->settings['fields']);
  68
+	}
  69
+
  70
+/**
  71
+ * testAuthenticateNoData method
  72
+ *
  73
+ * @return void
  74
+ */
  75
+	public function testAuthenticateNoData() {
  76
+		$request = new CakeRequest('posts/index', false);
  77
+		$request->data = array();
  78
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  79
+	}
  80
+
  81
+/**
  82
+ * testAuthenticateNoUsername method
  83
+ *
  84
+ * @return void
  85
+ */
  86
+	public function testAuthenticateNoUsername() {
  87
+		$request = new CakeRequest('posts/index', false);
  88
+		$request->data = array('User' => array('password' => 'foobar'));
  89
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  90
+	}
  91
+
  92
+/**
  93
+ * testAuthenticateNoPassword method
  94
+ *
  95
+ * @return void
  96
+ */
  97
+	public function testAuthenticateNoPassword() {
  98
+		$request = new CakeRequest('posts/index', false);
  99
+		$request->data = array('User' => array('user' => 'mariano'));
  100
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  101
+	}
  102
+
  103
+/**
  104
+ * testAuthenticatePasswordIsFalse method
  105
+ *
  106
+ * @return void
  107
+ */
  108
+	public function testAuthenticatePasswordIsFalse() {
  109
+		$request = new CakeRequest('posts/index', false);
  110
+		$request->data = array(
  111
+			'User' => array(
  112
+				'user' => 'mariano',
  113
+				'password' => null
  114
+		));
  115
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  116
+	}
  117
+
  118
+/**
  119
+ * testAuthenticateInjection method
  120
+ *
  121
+ * @return void
  122
+ */
  123
+	public function testAuthenticateInjection() {
  124
+		$request = new CakeRequest('posts/index', false);
  125
+		$request->data = array('User' => array(
  126
+			'user' => '> 1',
  127
+			'password' => "' OR 1 = 1"
  128
+		));
  129
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  130
+	}
  131
+
  132
+/**
  133
+ * testAuthenticateSuccess method
  134
+ *
  135
+ * @return void
  136
+ */
  137
+	public function testAuthenticateSuccess() {
  138
+		$request = new CakeRequest('posts/index', false);
  139
+		$request->data = array('User' => array(
  140
+			'user' => 'mariano',
  141
+			'password' => 'password'
  142
+		));
  143
+		$result = $this->auth->authenticate($request, $this->response);
  144
+		$expected = array(
  145
+			'id' => 1,
  146
+			'user' => 'mariano',
  147
+			'created' => '2007-03-17 01:16:23',
  148
+			'updated' => '2007-03-17 01:18:31',
  149
+		);
  150
+		$this->assertEquals($expected, $result);
  151
+	}
  152
+
  153
+/**
  154
+ * testAuthenticateScopeFail method
  155
+ *
  156
+ * @return void
  157
+ */
  158
+	public function testAuthenticateScopeFail() {
  159
+		$this->auth->settings['scope'] = array('user' => 'nate');
  160
+		$request = new CakeRequest('posts/index', false);
  161
+		$request->data = array('User' => array(
  162
+			'user' => 'mariano',
  163
+			'password' => 'password'
  164
+		));
  165
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  166
+	}
  167
+
  168
+/**
  169
+ * testPluginModel method
  170
+ *
  171
+ * @return void
  172
+ */
  173
+	public function testPluginModel() {
  174
+		Cache::delete('object_map', '_cake_core_');
  175
+		App::build(array(
  176
+			'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  177
+		), App::RESET);
  178
+		CakePlugin::load('TestPlugin');
  179
+
  180
+		$PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser');
  181
+		$user['id'] = 1;
  182
+		$user['username'] = 'gwoo';
  183
+		$user['password'] = Security::hash('password', 'blowfish');
  184
+		$PluginModel->save($user, false);
  185
+
  186
+		$this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser';
  187
+		$this->auth->settings['fields']['username'] = 'username';
  188
+
  189
+		$request = new CakeRequest('posts/index', false);
  190
+		$request->data = array('TestPluginAuthUser' => array(
  191
+			'username' => 'gwoo',
  192
+			'password' => 'password'
  193
+		));
  194
+
  195
+		$result = $this->auth->authenticate($request, $this->response);
  196
+		$expected = array(
  197
+			'id' => 1,
  198
+			'username' => 'gwoo',
  199
+			'created' => '2007-03-17 01:16:23'
  200
+		);
  201
+		$this->assertEquals(self::date(), $result['updated']);
  202
+		unset($result['updated']);
  203
+		$this->assertEquals($expected, $result);
  204
+		CakePlugin::unload();
  205
+	}
  206
+}
15  lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php
@@ -100,6 +100,21 @@ public function testAuthenticateNoPassword() {
100 100
 	}
101 101
 
102 102
 /**
  103
+ * test authenticate password is false method
  104
+ *
  105
+ * @return void
  106
+ */
  107
+	public function testAuthenticatePasswordIsFalse() {
  108
+		$request = new CakeRequest('posts/index', false);
  109
+		$request->data = array(
  110
+			'User' => array(
  111
+				'user' => 'mariano',
  112
+				'password' => null
  113
+		));
  114
+		$this->assertFalse($this->auth->authenticate($request, $this->response));
  115
+	}
  116
+
  117
+/**
103 118
  * test the authenticate method
104 119
  *
105 120
  * @return void

0 notes on commit d24bbcb

Please sign in to comment.
Something went wrong with that request. Please try again.