Module | Authorization::AuthorizationInController::ClassMethods |
In: |
lib/declarative_authorization/in_controller.rb
|
Returns the context for authorization checks in the current controller. Uses the controller_name and prepends any namespaces underscored and joined with underscores.
E.g.
AllThosePeopleController => :all_those_people AnyName::Space::ThingsController => :any_name_space_things
Defines a filter to be applied according to the authorization of the current user. Requires at least one symbol corresponding to an action as parameter. The special symbol :all refers to all action. The all :all statement is only employed if no specific statement is present.
class UserController < ApplicationController filter_access_to :index filter_access_to :new, :edit filter_access_to :all ... end
The default is to allow access unconditionally if no rule matches. Thus, including the filter_access_to :all statement is a good idea, implementing a default-deny policy.
When the access is denied, the method permission_denied is called on the current controller, if defined. Else, a simple "you are not allowed" string is output. Log.info is given more information on the reasons of denial.
def permission_denied flash[:error] = 'Sorry, you are not allowed to the requested page.' respond_to do |format| format.html { redirect_to(:back) rescue redirect_to('/') } format.xml { head :unauthorized } format.js { head :unauthorized } end end
By default, required privileges are inferred from the action name and the controller name. Thus, in UserController :edit requires :edit users. To specify required privilege, use the option :require
filter_access_to :new, :create, :require => :create, :context => :users
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
NOTE: before_filters need to be defined before the first filter_access_to call.
For further customization, a custom filter expression may be formulated in a block, which is then evaluated in the context of the controller on a matching request. That is, for checking two objects, use the following:
filter_access_to :merge do permitted_to!(:update, User.find(params[:original_id])) and permitted_to!(:delete, User.find(params[:id])) end
The block should raise a Authorization::AuthorizationError or return false if the access is to be denied.
Later calls to filter_access_to with overlapping actions overwrite previous ones for that action.
All options:
Any of these methods will only be employed if :attribute_check is enabled.
filter_access_to :show, :attribute_check => true, :load_method => lambda { User.find(params[:id]) }
To DRY up the filter_access_to statements in restful controllers, filter_resource_access combines typical filter_access_to and before_filter calls, which set up the instance variables.
The simplest case are top-level resource controllers with only the seven CRUD methods, e.g.
class CompanyController < ApplicationController filter_resource_access def index... end
Here, all CRUD actions are protected through a filter_access_to :all statement. :attribute_check is enabled for all actions except for the collection action :index. To have an object for attribute checks available, filter_resource_access will set the instance variable @company in before filters. For the member actions (:show, :edit, :update, :destroy) @company is set to Company.find(params[:id]). For new actions (:new, :create), filter_resource_access creates a new object from company parameters: Company.new(params[:company].
For nested resources, the parent object may be loaded automatically.
class BranchController < ApplicationController filter_resource_access :nested_in => :companies end
Again, the CRUD actions are protected. Now, for all CRUD actions, the parent object @company is loaded from params[:company_id]. It is also used when creating @branch for new actions. Here, attribute_check is enabled for the collection :index as well, checking attributes on a @company.branches.new method.
In many cases, the default seven CRUD actions are not sufficient. As in the resource definition for routing you may thus give additional member, new and collection methods. The options allow you to specify the required privileges for each action by providing a hash or an array of pairs. By default, for each action the action name is taken as privilege (action search in the example below requires the privilege :index :companies). Any controller action that is not specified and does not belong to the seven CRUD actions is handled as a member method.
class CompanyController < ApplicationController filter_resource_access :collection => [[:search, :index], :index], :additional_member => {:mark_as_key_company => :update} end
The additional_* options add to the respective CRUD actions, the other options (:member, :collection, :new) replace their respective CRUD actions.
filter_resource_access :member => { :toggle_open => :update }
Would declare :toggle_open as the only member action in the controller and require that permission :update is granted for the current user.
filter_resource_access :additional_member => { :toggle_open => :update }
Would add a member action :toggle_open to the default members, such as :show.
If :collection is an array of method names filter_resource_access will associate a permission with the method that is the same as the method name and no attribute checks will be performed unless
:attribute_check => true
is added in the options.
You can override the default object loading by implementing any of the following instance methods on the controller. Examples are given for the BranchController (with nested_in set to :companies):
All options:
By default, member actions are [:show, :edit, :update, :destroy]. Also, any action not belonging to the seven CRUD actions are handled as member actions.
There are three different syntax to specify member, collection and new actions.
If nested_in is given, the new object is created from the parent_object.controller_name proxy, e.g. company.branches.new(params[:branch]). By default, new is set to [:new, :create].