I have implemented Authentication plugin and is working fine by itself. I am currently working on the Authorisation plugin. I am using the RequestAuthorizationMiddleware as per Request Authorization Middleware - 2.x
My middleware look like this:
public function middleware($middlewareQueue): \Cake\Http\MiddlewareQueue
{
$middlewareQueue->add(new ErrorHandlerMiddleware(Configure::read('Error')))
->add(new AssetMiddleware(['cacheTime' => Configure::read('Asset.cacheTime')]))
->add(new RoutingMiddleware($this))
->add(new BodyParserMiddleware())
->add(new AuthorizationMiddleware($this, [
'unauthorizedHandler' => [
'className' => 'Authorization.Redirect',
'url' => '/pages/permission',
'exceptions' => [
'MissingIdentityException' => 'Authorization\Exception\MissingIdentityException',
'ForbiddenException' => 'Authorization\Exception\ForbiddenException',
]
]
]))
->add(new RequestAuthorizationMiddleware());
return $middlewareQueue;
}
public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface {
$mapResolver = new MapResolver();
$mapResolver->map(ServerRequest::class, RequestPolicy::class);
return new AuthorizationService($mapResolver);
}
RequestPolicy.php
namespace App\Policy;
use Authorization\Policy\RequestPolicyInterface;
use Cake\Http\ServerRequest;
class RequestPolicy implements RequestPolicyInterface
{
/**
* Method to check if the request can be accessed
*
* @param \Authorization\IdentityInterface|null $identity Identity
* @param \Cake\Http\ServerRequest $request Server Request
* @return bool
*/
public function canAccess($identity, ServerRequest $request)
{
if ($request->getParam('plugin') === 'DebugKit') {
return true;
}
if(!empty($identity)){
$userRole = $identity->role;
$userStatus = $identity->status;
$action = $request->getParam('action');
$controller = $request->getParam('controller');
switch ($controller) {
case 'Users':
if($userRole === 'ADMIN') {
return true;
}
elseif($userRole == 'X' || $userRole == 'Y') {
if (in_array($action, ['logout','login', ....])) { //need to specify login and logout in this list even though it is declared in the skipAuthorization array in AppController; otherwise logged in users cannot logout.
return true;
}
}
break;
.....
}
return false;
}else{
return true; //works as expected only if it is return true
// return false; //redirects to unauthorized redirect url (/pages/permission) causing redirect loop
}
}
Currently, authorization is working fine for the logged in users with the following issues:
- If identity is empty, when canAccess return false, redirects to unauthorized redirect url (/pages/permission) causing redirect loop. However, if I return true, authorization is working as expected.
I read RequestAuthorizationMiddleware would check authorization policies before Authentication kicks in. In that case, is it safe to return true from canAccess when there is no identity? or, is there any other way to solve this?
- In the AppController before filter, I have declared $this->Authorization->skipAuthorization(); for all the actions that do not need authentication. This working properly for the nonauthenticated users. However, If an identity exists and is valid, the actions in the skipAuthorization list is still chekcing authorization for the logged in users. So it redirects to unauthorized redirect url (/pages/permission) unless I specify that again in the canAccess method. Why do I need to declare that again even though it is declared in the skipAuthorization array in AppController;
Could anyone please point out what I am doing wrong? Any help is much appreciated.