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:

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

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

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

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

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