Skip to content
This repository has been archived by the owner on Nov 19, 2019. It is now read-only.

Commit

Permalink
Allow authority resource class lookup at request time
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Long committed Feb 12, 2013
1 parent 509b561 commit 96bf4bf
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 11 deletions.
30 changes: 23 additions & 7 deletions lib/authority/controller.rb
Expand Up @@ -14,18 +14,23 @@ def self.security_violation_callback

included do
rescue_from(Authority::SecurityViolation, :with => Authority::Controller.security_violation_callback)
class_attribute :authority_resource
class << self
attr_accessor :authority_resource
end
end

module ClassMethods

# Sets up before_filter to ensure user is allowed to perform a given controller action
#
# @param [Class] model_class - class whose authorizer should be consulted
# @param [Hash] options - can contain :actions to be merged with existing
# @param [Class OR Symbol] resource_or_finder - class whose authorizer
# should be consulted, or instance method on the controller which will
# determine that class when the request is made
# @param [Hash] options - can contain :actions to
# be merged with existing
# ones and any other options applicable to a before_filter
def authorize_actions_for(model_class, options = {})
self.authority_resource = model_class
def authorize_actions_for(resource_or_finder, options = {})
self.authority_resource = resource_or_finder
authority_actions(options[:actions] || {})
before_filter :run_authorization_check, options
end
Expand Down Expand Up @@ -86,7 +91,17 @@ def authority_forbidden(error)
# The `before_filter` that will be setup to run when the class method
# `authorize_actions_for` is called
def run_authorization_check
authorize_action_for self.class.authority_resource
authorize_action_for authority_resource
end

def authority_resource
return self.class.authority_resource if self.class.authority_resource.is_a?(Class)
return send(self.class.authority_resource) if respond_to?(self.class.authority_resource)
raise MissingResource.new(
"Trying to authorize actions for '#{self.class.authority_resource}', but can't. \
Must be either a resource class OR the name of a controller instance method that \
returns one.".squeeze(' ')
)
end

# Convenience wrapper for sending configured `user_method` to extract the
Expand All @@ -97,6 +112,7 @@ def authority_user
send(Authority.configuration.user_method)
end

class MissingAction < StandardError ; end
class MissingAction < StandardError ; end
class MissingResource < StandardError ; end
end
end
52 changes: 48 additions & 4 deletions spec/authority/controller_spec.rb
Expand Up @@ -87,11 +87,16 @@ def self.before_filter(*args) ; end

describe "authorize_actions_for" do

it "allows specifying the model to protect" do
it "allows specifying the class of the model to protect" do
controller_class.authorize_actions_for(resource_class)
expect(controller_class.authority_resource).to eq(resource_class)
end

it "allows specifying an instance method to find the class of the model to protect" do
controller_class.authorize_actions_for(:finder_method)
expect(controller_class.authority_resource).to eq(:finder_method)
end

it "sets up a before_filter, passing the options it was given" do
filter_options = {:only => [:show, :edit, :update]}
controller_class.should_receive(:before_filter).with(:run_authorization_check, filter_options)
Expand Down Expand Up @@ -146,9 +151,48 @@ def self.before_filter(*args) ; end

describe "run_authorization_check (used as a before_filter)" do

it "checks authorization on the model specified" do
controller_instance.should_receive(:authorize_action_for).with(resource_class)
controller_instance.send(:run_authorization_check)
context "if a resource class was specified" do

it "checks authorization on the model specified" do
controller_instance.should_receive(:authorize_action_for).with(resource_class)
controller_instance.send(:run_authorization_check)
end

end

context "if a method for determining the class was specified" do

let(:resource_class) { Hash }
let(:controller_class) do
Class.new(ExampleController).tap do |c|
c.send(:include, Authority::Controller)
c.authorize_actions_for(:method_to_find_class)
end
end

context "if the controller has such an instance method" do

before :each do
controller_instance.stub(:method_to_find_class).and_return(resource_class)
end

it "checks authorization on class returned by that method" do
controller_instance.should_receive(:authorize_action_for).with(resource_class)
controller_instance.send(:run_authorization_check)
end

end

context "if the controller has no such instance method" do

it "raises an exception" do
expect{controller_instance.send(:run_authorization_check)}.to raise_error(
Authority::Controller::MissingResource
)
end

end

end

it "raises a MissingAction if there is no corresponding action for the controller" do
Expand Down

0 comments on commit 96bf4bf

Please sign in to comment.