Closed enviniom closed 4 years ago
The first argument of AuthorizationComponent::authorize()
must be a resource for which a policy can be obtained, the second argument is an optional action that should be checked for, it defaults to the current controller action.
See the example in the Cookbook, the resource is an entity and so it will use an entity policy: https://book.cakephp.org/authorization/2/en/component.html#checking-authorization.
So you first need to assess what resource you actually want to protect, the whole controller action, or maybe some other resource that the controller action is accessing/modifying, which could potentially happen in other places too.
If you want to protect the whole controller/action, you might want to look into request policies: https://book.cakephp.org/authorization/2/en/request-authorization-middleware.html
I really do not understand well how to implement the Authorization middleware, it is very complex for me, I think I will do something similar to what was in the Auth component, to check the access to resources from an action in the controllers.
@enviniom If you don't have resources to check against you likely want the request authorization middleware that NDM linked to. It is also possible that authorization middleware is not a good fit for the problem you're trying to solve. If you can do what you need with a controller method I would do just that. It is often best to start small and grow into more complex solutions as you need them.
@markstory a couple of follow-up questions
isAuthorized
methods on controllers if we are using only the RequestAuthorizationMiddleware
for authorization?is there a way to call the legacy isAuthorized methods on controllers if we are using only the RequestAuthorizationMiddleware for authorization?
No. Middleware has no access to the controller.
Can we have two types of authorization policies stacked on one another? for example, suppose I want to first check a general request policy and then a ORM policy - is that possible?
Sure, you can write a middleware to do what ever you'd like :smile: The middleware that come in this plugin can't do what you're looking for.
@markstory haha.. writing my own "authorization" middleware you say :P - thanks for the answers! Our codebase has all its RBAC authorization logic spread across controllers in the isAuthorized
methods. It's gonna be a big pain to refactor to use the new Authorization plugin with orm resolver.
It's gonna be a big pain to refactor to use the new Authorization plugin with orm resolver.
You don't have to use the ORM resolver. You can create a policy that uses your controllers instead. Your policy checks could accept the controller and then call its isAuthorized()
method.
You don't have to use the ORM resolver. You can create a policy that uses your controllers instead. Your policy checks could accept the controller and then call its
isAuthorized()
method.
Umm, stupid question: how can we use the controller in the policy? I was trying to figure that out and couldn't get anywhere. I didn't see anything in the documentation regarding that in the RequestPolicy for RequestAuthorizationMiddleware? The $request->getParam('controller')
only gives the name of controller and not the instance of the controller to access it
You can pass the controller into the policy.
// In a controller method
$this->Authorization->authorize($this);
You'll also need a policy class that calls the controller's isAuthorized()
method, and either use the MapResolver
to connect that policy class to each controller that needs it, or a custom PolicyResolver
that returns your policy for any controllers.
Something like:
namespace App\Policy;
class ControllerHookPolicy
{
public function __call($user, $controller)
{
return $controller->isAuthorized($user);
}
}
class ControllerResolver implements ResolverInterface
{
public function getPolicy($resource)
{
if ($resource instanceof Controller) {
return new ControllerHookPolicy();
}
throw new MissingPolicyException([$resource::class]);
}
}
If you have a mix of model and controller policies you can use the ResolverCollection
to join the various policy resolvers together.
This helps a lot, thanks! Will get it to work. Yeah I read about resolver collection but it didn't work with map resolver for RequestPolicy
and OrmResolver
as a backup as RequestPolicy
for RequestAuthorizationMiddleware
needs to return either true or false.
@markstory Your example should be mentioned in the docs, it was very useful to understand how to create a custom resolver! Thank you!
Note for future readers: $resource::class
should be replaced with get_class($resource)
or php will throw an error "Cannot use ::class with dynamic class name"
@mfrascati do you use the above implementation for keeping the legacy isAuthorized
methods? If yes, where do you keep the $this->Authorization->authorize($this);
for all controllers? beforeFilter
sounds good/
@mfrascati do you use the above implementation for keeping the legacy
isAuthorized
methods? If yes, where do you keep the$this->Authorization->authorize($this);
for all controllers?beforeFilter
sounds good/
Actually I used it to replace the controller logic and centralized the controller/action check in a single RequestPolicy, so when the controller function is called I'm sure the role is allowed to call it. I just have 2 roles (admin access everything, user with limited actions) and I chose to keep all user accessible actions under control in a single file.
Your example should be mentioned in the docs, it was very useful to understand how to create a custom resolver! Thank you!
You're welcome :smile: Where would you hope to find this kind of information in the docs?
You're welcome 😄 Where would you hope to find this kind of information in the docs?
Maybe it could be mentioned after the "Creating a resolver" section? It seems a useful example to help people keep using their isAuthorized methods on controllers without rewriting the whole logic!
Hi, I've created a modelless Controller named Principal, and it works like pages, but I don't know how to make policies for actions in this controller. I baked a PrincipalPolicy, and created the method
In action "configuration" in PrincipalController I called
$this->Authorization->authorize();
but, throws an error about "Too few arguments to function", and I used$this->Authorization->authorize('configuration');
and throws and error about "Policy for string has not been defined".I don know how to implementa policy for a modelles controller.