@bjolling said:
@savar said:
I believe these items should go into the model, because...
@savar said:My co-worker thinks this logic should be in the model;
Typo? Or do you actually agree to put it in the model? Anyway, to answer the question: in my opinion, the ACL could be part of the model, but it is up to the controller to enforce it by properly managing the views. Wouldn't MVP be a better choice when using "Passive View"? In this case the Presenter can call the view directly through an interface to indicate which fields are enabled/visible/readonly etc...
Doh.. yeah it was a typo. He wants to put all of the ACL querying logic into the controller. So the controller would say if ($user->hasPrivilege($resource, $privilege)) {$resource->modifyData()}, and then $resource->modifyData() would purely contain business logic and would make a call to the ORM to persist the data.
Never heard the term MVP before, but reading the Wikipedia article, it sounds similar to what I want, except for this part: "The View is an interface that displays data (the Model) and routes user commands to the Presenter to act upon that data." That doesn't make sense to me in a [server-side] web app, where all of the user input is ultimately going to come in the form of HTTP requests.
And you're right, the controllers and views obviously consume ACL information, in order to know how to properly route events, and what controls and to display on the screen. But all of our ideas of privileges (in this application) ultimately pertain directly to [i]data[/i], generally just the simple CRUD operations. While the view may hide the "edit" button when a user is looking at an object, and the controller may reject a request to load the "edit" page for an object, I still think the model has the ultimate responsibility for enforcing ACL.
Any developer who writes a new controller or a new view will have to explicitly know what ACL logic to include, unless that ACL logic is built into the model. Say there's an existing functionality that allows a user to edit an object from a web interface. This new developer wants to write a controller which allows the user to edit an object using a SOAP interface. There are a series of fine grained access control checks, such as which fields a user can set, and what time of day they can set them, etc. It would be quite easy for this developer to write the controller in such a way that it actually had different access control properties than the original controller, even though both are based on the same underlying model.
@stratos said:
MVC paradigm has very little to do with this. afaik security should be seperatly implemented in it's own class structure. Your model and controller can then just call the security object to verify rights.
Definitely. I didn't make it clear in my post, but we're actually using the Zend_Acl module in Zend Framework to handle the ACL queries. Zend_Acl allows us to build a tree of roles and resources and then enumerate rights between the two. Once the tree is constructed, that instance can be persisted and then queried throughout the application. My original question should really have been: "Where should we QUERY the ACL?"
@drachenstern said:
I get the concept of separating security into a different class, but shouldn't what you have access to change what you see on the Presentation aspect of the system? For instance, if you are in group Sales, then you probably need to see the CRM stuff, but not the payroll stuff. If you're in a Manager role, you probably should see Payroll Approval, but not Tax Codes. Or do you just show everything, and then bounce back a message of "that's not for you" when they try and use it?
You're definitely right.
In my app, we have two ACL primitives: $acl->hasPrivilege($resource, $privilege) and $acl->requirePrivilege($resource, $privilege). The former performs a query to see if the ACL contains the rights to do something, and this is used in the views to determine what data and controls to show on screen. The latter is similar, except instead of returning a boolean, it throws an exception. This is used in the model (and/or controller) as an assertion that a user is actually allowed to do something.
The reason it throws an exception is because the application is designed so that in normal usage, each call to requirePrivilege will always succeed. The UI shouldn't show the user an controls which he isn't allowed to use. There are two cases where requirePrivilege would fail:
- application bug. you showed the user a control you weren't supposed to show them.
- malicious user. somebody typed in their own URI query or modified form data before it was posted to try to access something that the view wouldn't reveal to them.
My app is open source, so people will be able to see what form values are allowed and what controller actions can be invoked.
Anyway, thanks for the feedback. I'm still a bit lost, but now at least I've got some ideas to chew on.