mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Implemented stateless login for Auth
This commit is contained in:
parent
8209097bc3
commit
b7834a2b16
7 changed files with 182 additions and 94 deletions
|
@ -155,4 +155,15 @@ abstract class BaseAuthenticate {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unauthenticated access attempt.
|
||||
*
|
||||
* @param CakeRequest $request A request object.
|
||||
* @param CakeResponse $response A response object.
|
||||
* @return mixed Either true to indicate the unauthenticated request has been
|
||||
* dealt with and no more action is required by AuthComponent or void (default).
|
||||
*/
|
||||
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -82,23 +82,15 @@ class BasicAuthenticate extends BaseAuthenticate {
|
|||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user using basic HTTP auth. Will use the configured User model and attempt a
|
||||
* login using basic HTTP auth.
|
||||
* Authenticate a user using HTTP auth. Will use the configured User model and attempt a
|
||||
* login using HTTP auth.
|
||||
*
|
||||
* @param CakeRequest $request The request to authenticate with.
|
||||
* @param CakeResponse $response The response to add headers to.
|
||||
* @return mixed Either false on failure, or an array of user data on success.
|
||||
*/
|
||||
public function authenticate(CakeRequest $request, CakeResponse $response) {
|
||||
$result = $this->getUser($request);
|
||||
|
||||
if (empty($result)) {
|
||||
$response->header($this->loginHeaders());
|
||||
$response->statusCode(401);
|
||||
$response->send();
|
||||
return false;
|
||||
}
|
||||
return $result;
|
||||
return $this->getUser($request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,6 +109,20 @@ class BasicAuthenticate extends BaseAuthenticate {
|
|||
return $this->_findUser($username, $pass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an unauthenticated access attempt by sending appropriate login headers
|
||||
*
|
||||
* @param CakeRequest $request A request object.
|
||||
* @param CakeResponse $response A response object.
|
||||
* @return boolean True
|
||||
*/
|
||||
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
|
||||
$response->header($this->loginHeaders());
|
||||
$response->statusCode(401);
|
||||
$response->send();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the login headers
|
||||
*
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
|
||||
App::uses('BasicAuthenticate', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* Digest Authentication adapter for AuthComponent.
|
||||
|
@ -55,7 +55,7 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
|
|||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
*/
|
||||
class DigestAuthenticate extends BaseAuthenticate {
|
||||
class DigestAuthenticate extends BasicAuthenticate {
|
||||
|
||||
/**
|
||||
* Settings for this object.
|
||||
|
@ -97,9 +97,6 @@ class DigestAuthenticate extends BaseAuthenticate {
|
|||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings) {
|
||||
parent::__construct($collection, $settings);
|
||||
if (empty($this->settings['realm'])) {
|
||||
$this->settings['realm'] = env('SERVER_NAME');
|
||||
}
|
||||
if (empty($this->settings['nonce'])) {
|
||||
$this->settings['nonce'] = uniqid('');
|
||||
}
|
||||
|
@ -108,26 +105,6 @@ class DigestAuthenticate extends BaseAuthenticate {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user using Digest HTTP auth. Will use the configured User model and attempt a
|
||||
* login using Digest HTTP auth.
|
||||
*
|
||||
* @param CakeRequest $request The request to authenticate with.
|
||||
* @param CakeResponse $response The response to add headers to.
|
||||
* @return mixed Either false on failure, or an array of user data on success.
|
||||
*/
|
||||
public function authenticate(CakeRequest $request, CakeResponse $response) {
|
||||
$user = $this->getUser($request);
|
||||
|
||||
if (empty($user)) {
|
||||
$response->header($this->loginHeaders());
|
||||
$response->statusCode(401);
|
||||
$response->send();
|
||||
return false;
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
|
||||
*
|
||||
|
|
|
@ -157,8 +157,9 @@ class AuthComponent extends Component {
|
|||
);
|
||||
|
||||
/**
|
||||
* The session key name where the record of the current user is stored. If
|
||||
* unspecified, it will be "Auth.User".
|
||||
* The session key name where the record of the current user is stored. Default
|
||||
* key is "Auth.User". If you are using only stateless authenticators set this
|
||||
* to false to ensure session is not started.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
|
@ -188,7 +189,7 @@ class AuthComponent extends Component {
|
|||
* Normally, if a user is redirected to the $loginAction page, the location they
|
||||
* were redirected from will be stored in the session so that they can be
|
||||
* redirected back after a successful login. If this session value is not
|
||||
* set, the user will be redirected to the page specified in $loginRedirect.
|
||||
* set, redirectUrl() method will return the url specified in $loginRedirect.
|
||||
*
|
||||
* @var mixed
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$loginRedirect
|
||||
|
@ -312,44 +313,43 @@ class AuthComponent extends Component {
|
|||
|
||||
/**
|
||||
* Checks whether current action is accessible without authentication.
|
||||
* If current action is login action referrer url is saved in session which is
|
||||
* later accessible using AuthComponent::redirectUrl().
|
||||
*
|
||||
* @param Controller $controller A reference to the instantiating controller object
|
||||
* @return boolean True if action is accessible without authentication else false
|
||||
*/
|
||||
protected function _isAllowed(Controller $controller) {
|
||||
$action = strtolower($controller->request->params['action']);
|
||||
|
||||
$url = '';
|
||||
if (isset($controller->request->url)) {
|
||||
$url = $controller->request->url;
|
||||
}
|
||||
$url = Router::normalize($url);
|
||||
$loginAction = Router::normalize($this->loginAction);
|
||||
|
||||
if ($loginAction != $url && in_array($action, array_map('strtolower', $this->allowedActions))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($loginAction == $url) {
|
||||
if (empty($controller->request->data)) {
|
||||
if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) {
|
||||
$this->Session->write('Auth.redirect', $controller->referer(null, true));
|
||||
}
|
||||
}
|
||||
if (in_array($action, array_map('strtolower', $this->allowedActions))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unauthenticated access attempt.
|
||||
* Handles unauthenticated access attempt. First the `unathenticated()` method
|
||||
* of the last authenticator in the chain will be called. The authenticator can
|
||||
* handle sending response or redirection as appropriate and return `true` to
|
||||
* indicate no furthur action is necessary. If authenticator returns null this
|
||||
* method redirects user to login action. If it's an ajax request and
|
||||
* $ajaxLogin is specified that element is rendered else a 403 http status code
|
||||
* is returned.
|
||||
*
|
||||
* @param Controller $controller A reference to the controller object
|
||||
* @return boolean Returns false
|
||||
* @param Controller $controller A reference to the controller object.
|
||||
* @return boolean True if current action is login action else false.
|
||||
*/
|
||||
protected function _unauthenticated(Controller $controller) {
|
||||
if (empty($this->_authenticateObjects)) {
|
||||
$this->constructAuthenticate();
|
||||
}
|
||||
$auth = $this->_authenticateObjects[count($this->_authenticateObjects) - 1];
|
||||
if ($auth->unauthenticated($this->request, $this->response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->_isLoginAction($controller)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$controller->request->is('ajax')) {
|
||||
$this->flash($this->authError);
|
||||
$this->Session->write('Auth.redirect', $controller->request->here());
|
||||
|
@ -366,12 +366,40 @@ class AuthComponent extends Component {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes $loginAction and checks if current request url is same as login
|
||||
* action. If current url is same as login action, referrer url is saved in session
|
||||
* which is later accessible using redirectUrl().
|
||||
*
|
||||
* @param Controller $controller A reference to the controller object.
|
||||
* @return boolean True if current action is login action else false.
|
||||
*/
|
||||
protected function _isLoginAction(Controller $controller) {
|
||||
$url = '';
|
||||
if (isset($controller->request->url)) {
|
||||
$url = $controller->request->url;
|
||||
}
|
||||
$url = Router::normalize($url);
|
||||
$loginAction = Router::normalize($this->loginAction);
|
||||
|
||||
if ($loginAction == $url) {
|
||||
if (empty($controller->request->data)) {
|
||||
if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) {
|
||||
$this->Session->write('Auth.redirect', $controller->referer(null, true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unauthorized access attempt
|
||||
*
|
||||
* @param Controller $controller A reference to the controller object
|
||||
* @return boolean Returns false
|
||||
* @throws ForbiddenException
|
||||
* @see AuthComponent::$unauthorizedRedirect
|
||||
*/
|
||||
protected function _unauthorized(Controller $controller) {
|
||||
if ($this->unauthorizedRedirect === false) {
|
||||
|
@ -395,7 +423,7 @@ class AuthComponent extends Component {
|
|||
/**
|
||||
* Attempts to introspect the correct values for object properties.
|
||||
*
|
||||
* @return boolean
|
||||
* @return boolean True
|
||||
*/
|
||||
protected function _setDefaults() {
|
||||
$defaults = array(
|
||||
|
@ -619,13 +647,12 @@ class AuthComponent extends Component {
|
|||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user
|
||||
*/
|
||||
public static function user($key = null) {
|
||||
if (empty(self::$_user) && !CakeSession::check(self::$sessionKey)) {
|
||||
return null;
|
||||
}
|
||||
if (!empty(self::$_user)) {
|
||||
$user = self::$_user;
|
||||
} else {
|
||||
} elseif (self::$sessionKey && CakeSession::check(self::$sessionKey)) {
|
||||
$user = CakeSession::read(self::$sessionKey);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if ($key === null) {
|
||||
return $user;
|
||||
|
@ -640,10 +667,6 @@ class AuthComponent extends Component {
|
|||
* @return boolean true if a user can be found, false if one cannot.
|
||||
*/
|
||||
protected function _getUser() {
|
||||
$user = $this->user();
|
||||
if ($user) {
|
||||
return true;
|
||||
}
|
||||
if (empty($this->_authenticateObjects)) {
|
||||
$this->constructAuthenticate();
|
||||
}
|
||||
|
@ -654,6 +677,11 @@ class AuthComponent extends Component {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$user = $this->user();
|
||||
if ($user) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,11 +80,10 @@ class BasicAuthenticateTest extends CakeTestCase {
|
|||
public function testAuthenticateNoData() {
|
||||
$request = new CakeRequest('posts/index', false);
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('header')
|
||||
->with('WWW-Authenticate: Basic realm="localhost"');
|
||||
$this->response->expects($this->never())
|
||||
->method('header');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
$this->assertFalse($this->auth->getUser($request));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,10 +95,6 @@ class BasicAuthenticateTest extends CakeTestCase {
|
|||
$request = new CakeRequest('posts/index', false);
|
||||
$_SERVER['PHP_AUTH_PW'] = 'foobar';
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('header')
|
||||
->with('WWW-Authenticate: Basic realm="localhost"');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
}
|
||||
|
||||
|
@ -113,10 +108,6 @@ class BasicAuthenticateTest extends CakeTestCase {
|
|||
$_SERVER['PHP_AUTH_USER'] = 'mariano';
|
||||
$_SERVER['PHP_AUTH_PW'] = null;
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('header')
|
||||
->with('WWW-Authenticate: Basic realm="localhost"');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
}
|
||||
|
||||
|
@ -132,6 +123,8 @@ class BasicAuthenticateTest extends CakeTestCase {
|
|||
$_SERVER['PHP_AUTH_USER'] = '> 1';
|
||||
$_SERVER['PHP_AUTH_PW'] = "' OR 1 = 1";
|
||||
|
||||
$this->assertFalse($this->auth->getUser($request));
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
}
|
||||
|
||||
|
@ -151,8 +144,8 @@ class BasicAuthenticateTest extends CakeTestCase {
|
|||
$this->response->expects($this->at(1))
|
||||
->method('send');
|
||||
|
||||
$result = $this->auth->authenticate($request, $this->response);
|
||||
$this->assertFalse($result);
|
||||
$result = $this->auth->unauthenticated($request, $this->response);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +194,7 @@ class BasicAuthenticateTest extends CakeTestCase {
|
|||
$this->response->expects($this->at(2))
|
||||
->method('send');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
$this->assertTrue($this->auth->unauthenticated($request, $this->response));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -94,11 +94,10 @@ class DigestAuthenticateTest extends CakeTestCase {
|
|||
public function testAuthenticateNoData() {
|
||||
$request = new CakeRequest('posts/index', false);
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('header')
|
||||
->with('WWW-Authenticate: Digest realm="localhost",qop="auth",nonce="123",opaque="123abc"');
|
||||
$this->response->expects($this->never())
|
||||
->method('header');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
$this->assertFalse($this->auth->getUser($request, $this->response));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +132,7 @@ DIGEST;
|
|||
$this->response->expects($this->at(2))
|
||||
->method('send');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
$this->assertTrue($this->auth->unauthenticated($request, $this->response));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,8 +155,8 @@ DIGEST;
|
|||
$this->response->expects($this->at(2))
|
||||
->method('send');
|
||||
|
||||
$result = $this->auth->authenticate($request, $this->response);
|
||||
$this->assertFalse($result);
|
||||
$result = $this->auth->unauthenticated($request, $this->response);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -224,7 +223,7 @@ DIGEST;
|
|||
$this->response->expects($this->at(2))
|
||||
->method('send');
|
||||
|
||||
$this->assertFalse($this->auth->authenticate($request, $this->response));
|
||||
$this->assertTrue($this->auth->unauthenticated($request, $this->response));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1348,4 +1348,78 @@ class AuthComponentTest extends CakeTestCase {
|
|||
$result = $this->Auth->user('is_admin');
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* testStatelessAuthNoRedirect method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatelessAuthNoRedirect() {
|
||||
if (CakeSession::id()) {
|
||||
session_destroy();
|
||||
CakeSession::$id = null;
|
||||
}
|
||||
$_SESSION = null;
|
||||
|
||||
AuthComponent::$sessionKey = false;
|
||||
$this->Auth->authenticate = array('Basic');
|
||||
$this->Controller->request['action'] = 'admin_add';
|
||||
|
||||
$this->Auth->response->expects($this->once())
|
||||
->method('statusCode')
|
||||
->with(401);
|
||||
|
||||
$this->Auth->response->expects($this->once())
|
||||
->method('send');
|
||||
|
||||
$result = $this->Auth->startup($this->Controller);
|
||||
$this->assertFalse($result);
|
||||
|
||||
$this->assertNull($this->Controller->testUrl);
|
||||
$this->assertNull(CakeSession::id());
|
||||
}
|
||||
|
||||
/**
|
||||
* testStatelessAuthNoSessionStart method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatelessAuthNoSessionStart() {
|
||||
if (CakeSession::id()) {
|
||||
session_destroy();
|
||||
CakeSession::$id = null;
|
||||
}
|
||||
$_SESSION = null;
|
||||
|
||||
$_SERVER['PHP_AUTH_USER'] = 'mariano';
|
||||
$_SERVER['PHP_AUTH_PW'] = 'cake';
|
||||
|
||||
$this->Auth->authenticate = array(
|
||||
'Basic' => array('userModel' => 'AuthUser')
|
||||
);
|
||||
$this->Controller->request['action'] = 'admin_add';
|
||||
|
||||
$result = $this->Auth->startup($this->Controller);
|
||||
$this->assertTrue($result);
|
||||
|
||||
$this->assertNull(CakeSession::id());
|
||||
}
|
||||
|
||||
/**
|
||||
* testStatelessAuthRedirect method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStatelessFollowedByStatefulAuth() {
|
||||
$this->Auth->authenticate = array('Basic', 'Form');
|
||||
$this->Controller->request['action'] = 'admin_add';
|
||||
|
||||
$this->Auth->response->expects($this->never())->method('statusCode');
|
||||
$this->Auth->response->expects($this->never())->method('send');
|
||||
|
||||
$result = $this->Auth->startup($this->Controller);
|
||||
$this->assertFalse($result);
|
||||
|
||||
$this->assertEquals('/users/login', $this->Controller->testUrl);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue