-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DirectAuthenticate adapter #949
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
App::uses('BaseAuthenticate', 'Controller/Component/Auth'); | ||
|
||
/** | ||
* An authentication adapter for AuthComponent to directly log in a user by username, id or | ||
* any other distinct identification. | ||
* | ||
* Inside a controller(/component): | ||
* | ||
* $this->request->data = array('User' => array('id' => $userId)); | ||
* $this->Auth->authenticate = array('Direct' => array('contain' => array('Role.id'), 'fields'=>array('username' => 'id'))); | ||
* $result = $this->Auth->login(); | ||
* | ||
* This has several advantages over using Auth->login($data) directly: | ||
* - You keep it dry, especially when using contain ($data would have to have the exact same data). | ||
* - No overhead - retrieving the data prior to the login is not necessary. It's short and easy. | ||
* - You keep it centralized, only one single mechanism to login (using your Authentication adapters | ||
* and its common _findUser() method). It also respects the scope and contain settings specified | ||
* in your AppController just as any other adapter. | ||
* | ||
*/ | ||
class DirectAuthenticate extends BaseAuthenticate { | ||
|
||
/** | ||
* 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, username is missing, of 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; | ||
} | ||
$conditions = array( | ||
$model . '.' . $fields['username'] => $request->data[$model][$fields['username']] | ||
); | ||
return $this->_findUser($conditions); | ||
} | ||
|
||
/** | ||
* 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']])) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* Find a user record using the standard options. | ||
* | ||
* The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). | ||
* | ||
* @param array $conditions An array of find conditions. | ||
* @return Mixed Either false on failure, or an array of user data. | ||
*/ | ||
protected function _findUser($conditions, $password = null) { | ||
$userModel = $this->settings['userModel']; | ||
list($plugin, $model) = pluginSplit($userModel); | ||
$fields = $this->settings['fields']; | ||
|
||
$user = parent::_findUser($conditions); | ||
if (isset($user[$fields['password']])) { | ||
unset($user[$fields['password']]); | ||
} | ||
return $user; | ||
} | ||
|
||
} |
177 changes: 177 additions & 0 deletions
177
lib/Cake/Test/Case/Controller/Component/Auth/DirectAuthenticateTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
<?php | ||
/** | ||
* DirectAuthenticateTest file | ||
* | ||
*/ | ||
|
||
App::uses('AuthComponent', 'Controller/Component'); | ||
App::uses('DirectAuthenticate', 'Controller/Component/Auth'); | ||
App::uses('AppModel', 'Model'); | ||
App::uses('CakeRequest', 'Network'); | ||
App::uses('CakeResponse', 'Network'); | ||
|
||
require_once CAKE . 'Test' . DS . 'Case' . DS . 'Model' . DS . 'models.php'; | ||
|
||
/** | ||
* Test case for DirectAuthentication | ||
* | ||
* @package Cake.Test.Case.Controller.Component.Auth | ||
*/ | ||
class DirectAuthenticateTest 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 DirectAuthenticate($this->Collection, array( | ||
'fields' => array('username' => 'user'), | ||
'userModel' => 'User' | ||
)); | ||
$User = ClassRegistry::init('User'); | ||
$this->response = $this->getMock('CakeResponse'); | ||
} | ||
|
||
/** | ||
* test applying settings in the constructor | ||
* | ||
* @return void | ||
*/ | ||
public function testConstructor() { | ||
$object = new DirectAuthenticate($this->Collection, array( | ||
'userModel' => 'AuthUser', | ||
'fields' => array('username' => 'user') | ||
)); | ||
$this->assertEquals('AuthUser', $object->settings['userModel']); | ||
$this->assertEquals(array('username' => 'user', 'password' => 'password'), $object->settings['fields']); | ||
} | ||
|
||
/** | ||
* test the authenticate method | ||
* | ||
* @return void | ||
*/ | ||
public function testAuthenticateNoData() { | ||
$request = new CakeRequest('posts/index', false); | ||
$request->data = array(); | ||
$this->assertFalse($this->auth->authenticate($request, $this->response)); | ||
} | ||
|
||
/** | ||
* test the authenticate method | ||
* | ||
* @return void | ||
*/ | ||
public function testAuthenticateNoUsername() { | ||
$request = new CakeRequest('posts/index', false); | ||
$request->data = array('User' => array('x' => 'foobar')); | ||
$this->assertFalse($this->auth->authenticate($request, $this->response)); | ||
} | ||
|
||
/** | ||
* test authenticate password is false method | ||
* | ||
* @return void | ||
*/ | ||
public function testAuthenticateUsernameDoesNotExist() { | ||
$request = new CakeRequest('posts/index', false); | ||
$request->data = array( | ||
'User' => array( | ||
'user' => 'foo', | ||
)); | ||
$this->assertFalse($this->auth->authenticate($request, $this->response)); | ||
} | ||
|
||
/** | ||
* test the authenticate method | ||
* | ||
* @return void | ||
*/ | ||
public function testAuthenticateInjection() { | ||
$request = new CakeRequest('posts/index', false); | ||
$request->data = array( | ||
'User' => array( | ||
'user' => "> 1 ' OR 1 = 1", | ||
)); | ||
$this->assertFalse($this->auth->authenticate($request, $this->response)); | ||
} | ||
|
||
/** | ||
* test authenticate success | ||
* | ||
* @return void | ||
*/ | ||
public function testAuthenticateSuccess() { | ||
$request = new CakeRequest('posts/index', false); | ||
$request->data = array('User' => array( | ||
'user' => 'mariano', | ||
)); | ||
$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); | ||
} | ||
|
||
/** | ||
* test scope failure. | ||
* | ||
* @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', | ||
)); | ||
|
||
$this->assertFalse($this->auth->authenticate($request, $this->response)); | ||
} | ||
|
||
/** | ||
* test a model in a plugin. | ||
* | ||
* @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'; | ||
$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', | ||
|
||
)); | ||
|
||
$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(); | ||
} | ||
|
||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesnt the parent already unset the pw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only if its passed - which it isnt here, of course. we pass the conditions array directly, hence no unset triggered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, you are right about that, i think we should always unset it in BaseAuthenticate if present in the userdata, not only if its in the conditions.