ソースを参照

DirectAuth adapter

euromark 13 年 前
コミット
857daf6ae4

+ 91 - 0
Controller/Component/Auth/DirectAuthenticate.php

@@ -0,0 +1,91 @@
+<?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('Tools.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.
+ *
+ * @author Mark Scherer
+ * @licente MIT
+ * @cakephp 2.x (>= 2.3)
+ * 2012-11-05 ms
+ */
+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) {
+		$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;
+	}
+
+}

+ 179 - 0
Test/Case/Controller/Component/Auth/DirectAuthenticateTest.php

@@ -0,0 +1,179 @@
+<?php
+/**
+ * DirectAuthenticateTest file
+ *
+ * 2012-11-05 ms
+ */
+
+App::uses('AuthComponent', 'Controller/Component');
+App::uses('DirectAuthenticate', 'Tools.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);
+		debug($result);
+		$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();
+	}
+
+}