filter_access_to and if_attribute with has_many :through

86 views
Skip to first unread message

Matt Smith

unread,
Feb 1, 2012, 12:56:27 AM2/1/12
to declarative_authorization
I have used declarative_authorization before but not quite in the same
scenario. I greatly enjoyed it in the past! So I decided to use it
again on
this project. But I am stumped now...

I am having difficulty getting attribute checks to work. Everything
else is
great. This application only uses filter_access_to, due to a preferece
for
less magic and the fact that there are many controllers that are not
entirely
RESTful. Below is a concise example of what I am working with. Any
pointers
would be awesome!

I can't figure out two things:
1) Why the if_attribute checks are not working at all.
2) Verify that the location and the user are connected with the
appropriate
conditions. See comment in authorization block below.


class ApplicationController < ActionController::Base
before_filter { |c| Authorization.current_user =
c.send(:current_user) }

private

def current_user
# returns current user
end
end

# Note: This is a namespaced controller.
#
class Dashboard::LocationsController < ApplicationController
filter_access_to :edit, attribute_check: true

# I have also tried this:
# before_filter :find_location
# filter_access_to :all, attribute_check: true,
load_method: :find_location

def edit
@location = Location.find(params[:id])
end

private

# def find_location
# @location = Location.find(params[:id])
# end
end

class Location < ActiveRecord::Base
has_many :roles
has_many :users, :through => :roles
end

# Database attributes:
#
# roletype_id is one of the integer constants EXEC, ADMIN, etc
# active is a boolean field
#
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :vendor
belongs_to :location

EXEC = 1
ADMIN = 2

TYPES = {
EXEC => 'Exec',
ADMIN => 'Admin'
}

def type
TYPES[roletype_id]
end
end

class User < ActiveRecord::Base
has_many :roles
has_many :vendors, :through => :roles
has_many :locations, :through => :roles

def role_symbols
role_names = roles.reject{|role| !
role.active? }.map(&:type).to_set
role_names.map { |name| name.gsub(/\s/,'').underscore.to_sym }
<< :customer
end
end

authorization do

# ...

role :location_admin do
has_permission_on :dashboard_locations, to:
[:show, :edit, :update] do

# This fails even when there is not a location with an id of 999
# By failing I mean it does not filter access to the page.
#
# if_attribute :id => is { 999 }

if_attribute .... # I can't get to this point to test further!
#
# I need to check if:
# 1) The location is connected to the user through a role.
# 2) The role in #1 is active
# 3) The role in #1 has a roletype_id included in an array of
valid
# integers. [Role::Admin, Role::Blah...]
#
# I think this would be the quickest way, but not sure. Is there
an
# easier way?

end
end

# ...
end

I am happy to answer further questions!

If you can help me, that would be most appreciated!!!

Steffen Bartsch

unread,
Feb 1, 2012, 3:49:49 AM2/1/12
to declarative_...@googlegroups.com
Am Mittwoch, 1. Februar 2012 schrieb Matt Smith:
> class Dashboard::LocationsController < ApplicationController
> filter_access_to :edit, attribute_check: true
>
> # I have also tried this:
> # before_filter :find_location
> # filter_access_to :all, attribute_check: true,
> load_method: :find_location
>
> private
>
> # def find_location
> # @location = Location.find(params[:id])
> # end
> end

Three things to check: Are all requests denied? Then: What does the log say?
ApplicationController#current_user also should rather be protected than
private to be accessible from child controllers.

Second, is the context inferred correctly (is it really :dashboard_locations,
else it may e.g. be set with the :context parameter)?

Third, have you tried passing the load_method:
filter_access_to :edit, attribute_check: true, load_method: :find_location
or setting the model:
filter_access_to :edit, attribute_check: true, model: Location

http://www.tzi.org/~sbartsch/declarative_authorization/master/classes/Authorization/AuthorizationInController/ClassMethods.html#M000220

Steffen

Matt Smith

unread,
Feb 1, 2012, 11:50:25 AM2/1/12
to declarative_authorization
On Feb 1, 12:49 am, Steffen Bartsch <sbart...@tzi.de> wrote:
>
> Three things to check: Are all requests denied?  Then: What does the log say?
> ApplicationController#current_user also should rather be protected than
> private to be accessible from child controllers.
>
> Second, is the context inferred correctly (is it really :dashboard_locations,
> else it may e.g. be set with the :context parameter)?
>
> Third, have you tried passing the load_method:
>   filter_access_to :edit, attribute_check: true, load_method: :find_location
> or setting the model:
>   filter_access_to :edit, attribute_check: true, model: Location
>
> http://www.tzi.org/~sbartsch/declarative_authorization/master/classes...
>
> Steffen

Thanks Steffen! I am really impressed by your support of this gem.
Thanks for the quick response!

Are all requests denied? - No requests were being denied. But I found
my problem, thanks to your prodding! As usual it was out of scope of
my example context. I missed a higher up rule that allowed the request
to pass. Now I just need to figure out all of my conditions!

To make this useful for others... I did make my current_user method
public and I did not have to specify the :load_method or the :model.
And my context was being inferred correctly.

I do have one question. The docs say this for filter_access_to:
----
Without the :attribute_check option, no constraints from the
authorization rules are enforced because for some actions
(collections, new, create), there is no object to evaluate conditions
against. To allow attribute checks on all actions, it is a common
pattern to provide custom objects through before_filters:

class BranchesController < ApplicationController
before_filter :load_company
before_filter :new_branch_from_company_and_params,
:only => [:index, :new, :create]
filter_access_to :all, :attribute_check => true

protected
def new_branch_from_company_and_params
@branch = @company.branches.new(params[:branch])
end
end
----

While I get some of the ramifications, I am left with a few questions:
- In my example, I took away the attribute_check: true and it still
filtered on my if_attribute statements. Why? The statement "Without
the :attribute_check option, no constraints from the authorization
rules are enforced..." seems to infer that it will not check.
- Is attribute_check: true only needed on index, new, create? If so,
does declarative_authorization make assumptions about the instance
variable name? i.e. lower-case, underscored, singular of the
controller name?

Your library has proven itself to me yet again! Much thanks!
Reply all
Reply to author
Forward
0 new messages