zf2 - zend acl dynamic assertions; when/how to load the resource?

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

zf2 - zend acl dynamic assertions; when/how to load the resource?

Martijn Korse
i'm creating a zend framework 2 application and i'm sort of trying to implement what is explained here:

http://ralphschindler.com/2009/08/13/dynamic-assertions-for-zend_acl-in-zf

The demonstration that the code works is really nice, but it doesn't really apply to how a framework (utilizing mvc) works. Or maybe i'm just on the wrong track...

i've created a RouteListener like this :

class RouteListener implements ListenerAggregateInterface 
{ 
    public function attach(EventManagerInterface $events) 
    {
        $this->listeners[] = $result = $events->attach( 
            MvcEvent::EVENT_DISPATCH, array($this, "checkAcl"), 100 
        ); 
    }
}
the method checkAcl then checks if you're allowed to do what you want to do.

The resource and action are determined like this:

$resource = $routeMatch->getParam("controller");
$action = $routeMatch->getParam("action");
And the role is determined by the identity stored in the session (which implements Zend\Permissions\Acl\Role\RoleInterface)

Following the example: how do i determine if a user is allowed to edit a certain blog-post? By the time acl is doing it's checking, the controller hasn't loaded the blogpost yet, so i'm not sure how to approach this. Unless i duplicate the retrieval of the blogpost in the assertion, but i'm hoping that there is a better way.
Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

Michael Gooden
Well there are two ways you can do this, (well three, but we will get to
that).

You can do checks based on the requested route or controller and action,
and do generic checks like, can a user of type 'guest' access the 'edit'
action of my 'postcontroller', or if user of type 'guest' can access route
'my/controller/edit'.

This is nice for just overall access control, keeping all your guests out
of user areas etc. You can use a library like BjyAuthorize to do this
automagically.

The second case, which I presume is your case, is to check whether user
1234 can edit post 567. This you use assertions for. I usually do that
check after I have done the 'does this resource even exist' check. If the
assertion fails, I either 403 them or redirect to a known accessible page.

You could do the resource exists and is allowed checks in an early dispatch
listener and then pass the resource as a parameter to the MvcEvent being
passed around. This option might be more attractive if you are worried
about coupling your authorization to your controllers directly.

Hopefully this is of some help :)

Cheers,

Michael Gooden


On 9 September 2013 10:17, Martijn Korse <[hidden email]> wrote:

> i'm creating a zend framework 2 application and i'm sort of trying to
> implement what is explained here:
>
> http://ralphschindler.com/2009/08/13/dynamic-assertions-for-zend_acl-in-zf
>
> The demonstration that the code works is really nice, but it doesn't really
> apply to how a framework (utilizing mvc) works. Or maybe i'm just on the
> wrong track...
>
> i've created a RouteListener like this :
>
>
> the method checkAcl then checks if you're allowed to do what you want to
> do.
>
> The resource and action are determined like this:
>
>
> And the role is determined by the identity stored in the session (which
> implements Zend\Permissions\Acl\Role\RoleInterface)
>
> Following the example: how do i determine if a user is allowed to edit a
> certain blog-post? By the time acl is doing it's checking, the controller
> hasn't loaded the blogpost yet, so i'm not sure how to approach this.
> Unless
> i duplicate the retrieval of the blogpost in the assertion, but i'm hoping
> that there is a better way.
>
>
>
> --
> View this message in context:
> http://zend-framework-community.634137.n4.nabble.com/zf2-zend-acl-dynamic-assertions-when-how-to-load-the-resource-tp4660933.html
> Sent from the Zend Framework mailing list archive at Nabble.com.
>
> --
> List: [hidden email]
> Info: http://framework.zend.com/archives
> Unsubscribe: [hidden email]
>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

Martijn Korse
Hi Michael

Thanks for the response. However, i'm afraid it didnt really help.
Everything works fine, except the assertion-part. My Problem is this:

1. De resource (the blog-post) is loaded in the controller. This works fine.
2. The acl-check is done _before_ the controller loads the blog-post. If i don't use assertions, this works fine as well : the acl-check loads the acl-config and determines that 'users' are allowed to access the 'edit' action of the blogpostController.
3. When i extend my acl-config to include an assertion for the edit action (p.e. verifyOwnerAssertion) this works -> the assertion is called, BUT the problem is here that the assertion needs to know which blogpost is requested and then verify if the current user is allowed to edit it (the rule for that would be that it needs to be his own blog post). But because the controller hasnt loaded it yet i don't know how to feed this information to the assertion. Of course i could modify the assertion in such a way that it loads the blog-post, but that's not really something i want to do, as i'm duplicating code that way.
Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

richard
Hi
I would bind the creation/update/editing of your models to an ACL
checking listener which can derive ACL parameters from the model(s)
associations.


On Mon, Sep 9, 2013 at 11:01 AM, Martijn Korse <[hidden email]> wrote:

> Hi Michael
>
> Thanks for the response. However, i'm afraid it didnt really help.
> Everything works fine, except the assertion-part. My Problem is this:
>
> 1. De resource (the blog-post) is loaded in the controller. This works fine.
> 2. The acl-check is done _before_ the controller loads the blog-post. If i
> don't use assertions, this works fine as well : the acl-check loads the
> acl-config and determines that 'users' are allowed to access the 'edit'
> action of the blogpostController.
> 3. When i extend my acl-config to include an assertion for the edit action
> (p.e. verifyOwnerAssertion) this works -> the assertion is called, BUT the
> problem is here that the assertion needs to know which blogpost is requested
> and then verify if the current user is allowed to edit it (the rule for that
> would be that it needs to be his own blog post). But because the controller
> hasnt loaded it yet i don't know how to feed this information to the
> assertion. Of course i could modify the assertion in such a way that it
> loads the blog-post, but that's not really something i want to do, as i'm
> duplicating code that way.
>
>
>
> --
> View this message in context: http://zend-framework-community.634137.n4.nabble.com/zf2-zend-acl-dynamic-assertions-when-how-to-load-the-resource-tp4660933p4660937.html
> Sent from the Zend Framework mailing list archive at Nabble.com.
>
> --
> List: [hidden email]
> Info: http://framework.zend.com/archives
> Unsubscribe: [hidden email]
>
>

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

Martijn Korse
Hi Richard

Sounds interesting and where it concerns database _changes_ i think it's also possible. I already have an abstract controller class with a method "writeDbChanges()" that takes a Zend-Form as argument. This form as a doctrine entity bound to it, so i see a lot of possibilities there.

The only thing i'm not too happy with is that i will need to create two seperate acl-configs for that then.

And, still one scenario remains: when i'm selecting data from the database. I wouldn't know where to implement a listener for that ... Or maybe it is just too much to ask to keep this dynamic? Since i'll be creating a seperate acl-config maybe i'll just have to do this 'manually' everytime i select something? Is that the way to go?
Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

richard
Only one ACL config / instance required, with the FQCN of the Entity
the Resource, the action (edit/update ..) the Privilege, and the role
dynamically determined by the users association to the blog post the
Role. If you are using Doctrine ORM I believe the events are already
there http://docs.doctrine-project.org/en/2.0.x/reference/events.html

On Mon, Sep 9, 2013 at 12:27 PM, Martijn Korse <[hidden email]> wrote:

> Hi Richard
>
> Sounds interesting and where it concerns database _changes_ i think it's
> also possible. I already have an abstract controller class with a method
> "writeDbChanges()" that takes a Zend-Form as argument. This form as a
> doctrine entity bound to it, so i see a lot of possibilities there.
>
> The only thing i'm not too happy with is that i will need to create two
> seperate acl-configs for that then.
>
> And, still one scenario remains: when i'm selecting data from the database.
> I wouldn't know where to implement a listener for that ... Or maybe it is
> just too much to ask to keep this dynamic? Since i'll be creating a seperate
> acl-config maybe i'll just have to do this 'manually' everytime i select
> something? Is that the way to go?
>
>
>
> --
> View this message in context: http://zend-framework-community.634137.n4.nabble.com/zf2-zend-acl-dynamic-assertions-when-how-to-load-the-resource-tp4660933p4660940.html
> Sent from the Zend Framework mailing list archive at Nabble.com.
>
> --
> List: [hidden email]
> Info: http://framework.zend.com/archives
> Unsubscribe: [hidden email]
>
>

--
List: [hidden email]
Info: http://framework.zend.com/archives
Unsubscribe: [hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

Martijn Korse
I've been able to come up with a working solution, using the doctrine events. Within these events i do an (additional) acl->isAllowed() call which will trigger the assertion, but this time with the resource that is a doctrine entity. It works ... but i'm not really happy with it:
1) I have to inject my service manager into the doctrine entities. I've been able to simplify this by letting every entity extend an abstract one and inject it into to that .. but still... I would prefer it if i wouldn't have to bother those entities with it. I like to keep them as plain and simple as possible. Then again, this is not a huge problem and something i'm willing to overlook.
What i find a much bigger problem
2) The acl-decision was in a central place and now it's getting fragmented. Also: it will be called when the RouteListener intercepts the request and later again when the doctrine event intercepts the entity being loaded. The first time i have to allow it, because it lacks the necessary information (the second time it finally does have all the information and i can let the code make a proper decision); this feels wrong.
3) I have to make my doctrine entities aware of what identities are, since i have to pass it on as a role - this is not really something i want in my entity objects. Also, it's getting messy because there are public parts (without identities) and parts behind a login (with identities) that all use the same doctrine entities.
4) And the biggest of my problems: what do i do when acl decides it's not allowed? I don't want to put this logic in my assertion nor in my entity. This is controller-logic. I guess i could throw an Exception and equip my controllers with logic to handle it, but then again: i already have a perfectly good piece of code in my RouteListener. It feels wrong having to reach the same conclusions in my controllers - even if i manage to centralize the actual logic behind it.

Is there really no better way to tackle this? It really feels like a messy work-around with a lot of drawbacks.
Or am i simply not implementing it correctly?
Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

domeb
Hey Martijn,

did you get a better solution right now? Have the same problems and cant find a better way to do it, but it feels weird...

regards
Dominik
Reply | Threaded
Open this post in threaded view
|

Re: zf2 - zend acl dynamic assertions; when/how to load the resource?

Martijn Korse
Hi Dominik

Unfortunately, this was the best thing i could find and what i implemented in the end

In case of the assertion where i want to verify if someone is the owner of a resource i did these things:

* I created a ResourceWithOwnerInterface that demands a method getOwnerId()
* Any entity that needed this assertion implements that interface and with that an implementation of getOwnerId() that can determine who the owner is
* I then added the following methods to the entity:

    /** @ORM\PostLoad */
    public function onPostLoadconsultAcl()
    {
        $this->askAcl($this, "view");
    }
    
    /** @ORM\PrePersist */
    public function onPrePersistconsultAcl()
    {
        $this->askAcl($this, "edit");
    }

(askAcl is a method in an abstract entity that is extended which takes care of getting the identity/role and acl from the servicelocator and then ultimately does $acl->isAllowed($identity, $resource, $action); -> $resource being the $this parameter and $action being "view"/"edit"
* The assertion that is being called can then perform the followin check:

       $isResourceWithOwner = ($resource instanceof ResourceWithOwnerInterface);

If that boolean is true, then getOwnerId() can be safely called.

I'm still not happy with this solution though, for reasons i gave earlier.
domeb wrote
Hey Martijn,

did you get a better solution right now? Have the same problems and cant find a better way to do it, but it feels weird...

regards
Dominik