nathanl / authority

*CURRENTLY UNMAINTAINED*. Authority helps you authorize actions in your Rails app. It's ORM-neutral and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.
MIT License
1.21k stars 67 forks source link

Authority not redirecting #50

Closed denen99 closed 11 years ago

denen99 commented 11 years ago

Hi,

I have an admin_controller that other namespaced controllers inherit from. IN the admin_controller i want to have a base check (which works). current_user.can?(:login_to_admin). Then in the app authorizer i have

def self.authorizes_to_login_to_admin?(user,options = {}) user.has_role?(:admin) end

Testing on a user without that role works.

1.9.3-p327 :002 > u.can?(:login_to_admin) (0.1ms) SELECT COUNT(*) FROM roles INNER JOIN users_roles ON roles.id = users_roles.role_id WHERE users_roles.user_id = 2 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) => false

However, the user does not get redirect to a 403 in the app. Is this supposed to happen automatically ?

nathanl commented 11 years ago

authorize_action_for and authorize_actions_for are the controller methods that check permissions and redirect to 403 if an unauthorized action is being attempted. Are you using one or both of those? (You can refer to https://github.com/nathanl/authority#controllers and read the example controller code)

denen99 commented 11 years ago

Hmm no, how would i use this in an AdminController that gets inherited by all other namespaced admin controllers?

I dont have a resource or an instance in the AdminController but would like toapply a generic can?(:login_to_admin) function that gets checked there so that any namespaced controller that inherits from AdminController automatically gets this authorization applied.

Is this possible ?

nathanl commented 11 years ago

authorize_actions_for can take the name of a method to call instead of a class.

For example, maybe in AdminController you can say: authorize_actions_for :admin_resource and have the subclass controllers defined an admin_resource method to return the class they work with.

denen99 commented 11 years ago

The problem is i want to authorize just the namespaced controllers, not the Model they work with. Meaning, /venues/show/3 is OK, but /admin/venues/shows/3 is NOT for certain roles.

Is there a way to just call a generic can? method from authorizes_actions_for ?

or is it better to use your method and do authorizes_actions_for :admin_access

and then

def admin_access current_user.can?(:login_to_admin) end

denen99 commented 11 years ago

another thought, i wonder if in the admin controllers (versus the normal ones) i could override the CRUD methods to use the adminable action so index => :admin, create => :admin, etc. This way every method would call adminable_by?(user)

denen99 commented 11 years ago

OK i think i found the easiest way, just one snag. I created a new ability called admin that is adminable

Then i can do something like this in the namespaced controllers

authority_actions :index => 'admin'

I am trying to do this globally but it doesnt work, only authority_actions :index => 'admin' works.

authorize_actions_for :admin_resource, :actions => {:index => :admin } doesnt work. Any ideas ?

nathanl commented 11 years ago

Hmmm. Two things:

denen99 commented 11 years ago

Yea i realized that after I posted. When putting authorized_actions_for in the admin_controller it didnt get executed b/c the controller class name didnt match via inheritance.

Not sure if there is an easier way, but I ended up just adding one line to each of the inherited controllers, dont see a way to do this globally, outside of allowing multiple authority_action_maps (maybe I will submit a patch !)

authorize_actions_for MyModel, :actions => {:index => 'admin', :show => 'admin', :new => 'admin', :create => 'admin', :edit => 'admin', :update => 'admin', :destroy => 'admin' }

Then in ApplicationAuthorizer just define adminable_by? and seems to work great.

Is this the best way ?

nathanl commented 11 years ago

Sorry for my slow response.

Yes, I think what you're doing is fine. The controller action map is not inherited, as you've seen; each controller copies the one from the configuration and modifies its own copy as you direct it to.

Short of making these changes inheritable somehow, you might DRY your code up a bit by defining a macro on your common parent controller:

def self.require_admin_for_standard_actions_on(model_name)
  authorize_actions_for model_name, :actions => {:index => 'admin', :show => 'admin', :new => 'admin', :create => 'admin', :edit => 'admin', :update => 'admin', :destroy => 'admin' }
end

Then you could just do require_admin_for_standard_actions_on Widget in the WidgetsController.