Where should the responsibility for ACL be placed in MVC?

I am rebuilding one of my favorite intranet apps in Rails. I use a lot
of access control - not just on model-level, but down to specific fields
inside one model.

For example:

User A is allowed to modify the field “Meeting.modulex”, because he is
member of a certain group
User B is not allowed to modify the same field.

Three things sping into my mind at this:

a) The standard CRUD setup actually uses the view to dictate, which
fields, a user may edit (which of course could be compromised)

b) The model validation scheme only cares about filling the fields with
valid values

c) There is a convention saying that the controller should be “thin”,
and the model “fat”

I am very much in doubt, where i should place my Access control. On one
hand it is easier to put it into the controller, since it sometimes
spans multiple models. On the other hand, this isn’t very DRY.

I am interested in hearing how other users have tackled this problem.

  • Carsten

For those of us too lazy to figure it out, it belongs in the
acl_system2 plugin :slight_smile:

On May 6, 3:50 am, Carsten G. [email protected]

Carsten G. wrote:

a) The standard CRUD setup actually uses the view to dictate, which
fields, a user may edit (which of course could be compromised)

The view shouldn’t contain any business logic. It is just there to
create something visual for the user. The controller should setup any
state for the view to use to decide what to render and, hence,
potentially restrict what a user can see. It is also up to the
controller to decide what to accept from a user (say from submitting a
form).

c) There is a convention saying that the controller should be “thin”,
and the model “fat”

If it makes sense to a model to restrict operations based on another
model, then that logic is fine in the model, however users are generally
only relevant in the context of a controller. If you are operating in
the console, for example, you will not necessarily have a user defined
and you then wouldn’t want convoluted code in the model to handle this.
Let the model just get on with the job of being a model.

The controller is the place where you can determine users and so seems a
very natural place to put access limitations. After all, you are really
wanting to limit what users of the application can do, not what users of
the model can do (having direct access to the model probably means
having direct access to the database and you lose your access control
anyway).

What I do is create a set of predicates in the application controller
(possibly in a module that can be mixed in) so that code becomes more
readable. For example, using a before_filter to always ensure you have
a @user instance variable, then have an admin? method which checks for
@user having admin rights, then in your controller you can use “if
admin?” where necessary.

Then, if you want to use any of these predicates in a view, “export”
them as helpers using “helper_method”.

Brilliant explanation Mark! Thank you so much for that. :slight_smile:

I had serverly misunderstood where the model’s responsibilites stop and
the controller’s start, but your arguments make it logical.

If I have a model like this:

Meeting

id
date
from
to
subject
show_on_screen *

  • This atribute may only be written if user has the role “secretary”

What is best practice for this? Would you make one “update” controller
method like this:

def update
white_list = [‘id’, ‘date’, ‘from’, ‘to’, ‘subject’]
if @user.secretary?
white_list << ‘show_on_screen’
end

end

This would be the best way, if I also want to make a RESTful controller,
right?

  • Carsten

The approach that we’d typically take would be to only render the
input field for the secretary. That could mean either:

  • Views for Users in the secretary role have some conditional logic
    that renders the ‘show_on_screen’ field
  • A unique view specifically tasked for ‘show_on_screen’ is created
    and only Users in the secretary role are given access

In either case, the #update action can remain the same.

Obviously that approach is not bulletproof. Someone who really
wants to set the value could find a way to hack an http request with
the appropriate attributes. If you want to lock it down even tighter,
you could work along the lines of creating a method to update the
attributes that takes roles into account, and then invoke that method
from the controller (where the user is in context as Mark explains
above). It probably makes sense to wrap the method in using
alias_method_chain:

class Meeting
def update_attributes_with_role(role, attributes={})
attributes.each_pair{|attr, val| attributes.delete(:attr)
unless …authorized…}
update_attributes_without_role attributes
end
alias_method_chain :update_attributes, :role

end

On May 7, 4:20 am, Carsten G. [email protected]

AndyV wrote:

For those of us too lazy to figure it out, it belongs in the
acl_system2 plugin :slight_smile:

I took a look at acl_system2. If I understand it correctly, it creates
access-control on the controller. Thereby signifying, that
access-limitation to specific model-fields should be placed in the
controller.

Is this the common-way approach?

  • Carsten

On 7 May 2008, at 14:05, Carsten G. wrote:

Andy: My intial concern was exactly that I wanted to guard against
phony HTML-forms, where the user has added the extra field himself. So
just rendering the view without “show_on_screen” attribute would not
be
enough IMHO.

Do you want attr_protected ?

Fred

Andy: My intial concern was exactly that I wanted to guard against
phony HTML-forms, where the user has added the extra field himself. So
just rendering the view without “show_on_screen” attribute would not be
enough IMHO.

I didn’t know this aliass_method_chain - nice touch. I will research
this some more. Thank you.

  • Carsten

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs