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

Whitelisting controller actions #35

Closed JeanMertz closed 11 years ago

JeanMertz commented 11 years ago

First of all, great gem. I've recently switched over from CanCan to Authority because of the lack of updates for CanCan, but even more so because of the awesome structure of Authority. So two :+1: 's up.

Having implemented Authority in my first model, I really like the flow of the authorization, and especially like the unit tests that are possible with this gem (here's a short example):

require 'spec_helper'

describe AccountAuthorizer do
  include_examples 'AuthorizedModel'
  Given(:account) { authorizer_account }

  context 'for account with active membership' do
    context '#updatable_by?' do
      Then { account.authorizer.should be_updatable_by(owner) }
    end

    context '#creatable_by?' do
      Then { account.authorizer.should restrict_all_access_to(:creatable) }
    end
  end

  context 'blocks all access for guests' do
    Then { account.authorizer.should restrict_all_access_for(guest) }
  end

  context 'blocks all access for user of different account' do
    Given(:account) { Account.new }
    Then { account.authorizer.should restrict_all_access_for(owner) }
  end
end

I just started implementing Authority for my controllers, but I couldn't find any mention in the documentation regarding whitelisting (even though it is possible on a model level, with the ApplicationAuthorizer.

Is there a nice and clean way to enable whitelisting? From what I could read, I have to manually add authorize_actions_for for class-level authorization. I would like all access to be restricted by default and open the gates from there.

adamhunter commented 11 years ago

Hey @JeanMertz,

I think the best way (and @nathanl may correct me) to handle this would be to add authorize_actions_for ApplicationAuthorizor in your ApplicationController base class. This should setup all actions with a before_filter that will evenually run ApplicationAuthorizer.can_verb?(user).

The only issue I can imagine at the moment would be if you call authorize_actions_for Blah in another controller, the before filter may be added twice. You would then have to call skip_before_filter :run_authorization_check before redeclaring authorize_actions_for.

Let me know if this helps!

JeanMertz commented 11 years ago

@adamhunter Thank you for your help. Looking at your solution, wouldn't requiring ApplicationAuthorizer bypass the model specific authorizer like AccountAuthorizer, given that those specific authorizers normally inherit from ApplicationAuthorizer?

adamhunter commented 11 years ago

@JeanMertz,

It would. That is the core problem with enabling whitelisting, each controller needs to specify the authorizer it is going to use. In my example you would specify the controllers which had their own authorizers.

One other thing to mention is that the before_filter that authorization_actions_for creates ultimately calls Authority.enforce. (see: https://github.com/nathanl/authority/blob/v2.5.0/lib/authority.rb#L34). You can create any kind of custom whitelisting scheme you want by combing before filters with calling Authority.enforce.

I'm happy to answer any other questions you have.

JeanMertz commented 11 years ago

Sorry about that. Of course it would, and of course that's the whole point of it :smile:

Thank you again for explaining. Looks like I asked too soon, it's indeed easy to enable whitelisting.

Also, given that I am using the Focussed Controllers gem, I might need to override the Authority.enforce method to make Authority work with that gem. Thank you for pointing me in the right direction.

adamhunter commented 11 years ago

No problem. You shouldn't need to override Authority.enforce specifically because all it is doing is sewing together the resource, verb, and user. You may however need to change how the controller uses it, as well as mapping the controller class to a verb. Feel free to post any other questions!