Declarative Authorization

The declarative authorization plugin offers an authorization mechanism
inspired by RBAC. The most notable distinction to other
authorization plugins is the declarative approach. That is, authorization
rules are not defined programmatically in between business logic but in an
authorization configuration.

With programmatic authorization rules, the developer needs to specify which
roles are allowed to access a specific controller action or a part of a
view, which is not DRY. With a growing application code base roles'
permissions often change and new roles are introduced. Then, at several
places of the source code the changes have to be implemented, possibly
leading to omissions and thus hard to find errors. In these cases, a
declarative approach as offered by decl_auth increases the development and
maintenance efficiency.

Plugin features

Authorization at controller action level

Authorization helpers for Views

Authorization at model level

Authorize CRUD (Create, Read, Update, Delete) activities

Query rewriting to automatically only fetch authorized records

DSL for specifying Authorization rules in an authorization configuration

Support for Rails 4, with backwards compatibility through Rails 2

Requirements

An authentication mechanism

User object in Controller#current_user

(For model security) Setting Authorization.current_user

User objects need to respond to a method :role_symbols that returns an
array of role symbols

This installer will create a Role model, an admin and a user role, and set
a has_and_belongs_to_many relationship between the User model and the Role
model. It will also add a `role_symbols` method to the user model to meet
declarative_authorization's requirements. The default User model is
User. You can override this by simply typing the name of a model as above.

You can create the model with the fields provided by using the
`–create-user` option.

The `–commit` option will run `rake db:migrate` and `rake db:seed`.

The `–user-belongs-to-role` option will set up a one-to-many relationship
between Users and Roles. That is, each user has a role_id column and can
only have one role. Role inheritance can be used in authorization rules.

Finally, the installer also copies default authorization rules, as below.

Generate Authorization Rules

To copy a default set of authorization rules which includes CRUD
priveleges, run:

$ rails g authorization:rules

This command will copy the following to `config/authorization_rules.rb`.
Remember to implement the requirements of this gem as described in the
Installation section at the end of this README if you do not use the above
installer.

In the application domain, each User may be assigned to Roles
that should define the users' job in the application, such as
Administrator. On the right-hand side of this diagram,
application developers specify which Permissions are necessary for
users to perform activities, such as calling a controller action, viewing
parts of a View or acting on records in the database. Note that
Permissions consist of an Privilege that is to be performed, such as
read, and a Context in that the Operation takes place,
such as companies.

In the authorization configuration, Permissions are assigned to Roles and
Role and Permission hierarchies are defined. Attributes may be
employed to allow authorization according to dynamic information about the
context and the current user, e.g. “only allow access on employees that
belong to the current user's branch.”

Controller

If authentication is in place, there are two ways to enable user-specific
access control on controller actions. For resource controllers, which more
or less follow the CRUD pattern, filter_resource_access is the
simplest approach. It sets up instance variables in before filters and
calls filter_access_to with the appropriate parameters to protect the CRUD
methods.

See Authorization::AuthorizationInController::ClassMethods for options on
nested resources and custom member and collection actions.

By default, declarative_authorization will enable filter_resource_access
compatibility with strong_parameters in Rails 4. If you want to disable
this behavior, you can use the `:strong_parameters` option.

Simalarly, you can use `:strong_parameters => true` if you are using
strong_parameters in Rails 3.

If you prefer less magic or your controller has no resemblance with the
resource controllers, directly calling filter_access_to may be the better
option. Examples are given in the following. E.g. the privilege index
users is required for action index. This works as a first default
configuration for RESTful controllers, with these privileges easily handled
in the authorization configuration, which will be described below.

When custom actions are added to such a controller, it helps to define more
clearly which privileges are the respective requirements. That is when the
filter_access_to call may become more verbose:

class EmployeesController < ApplicationController
filter_access_to :all
# this one would be included in :all, but :read seems to be
# a more suitable privilege than :auto_complete_for_user_name
filter_access_to :auto_complete_for_employee_name, :require => :read
def auto_complete_for_employee_name
...
end
...
end

For some actions it might be necessary to check certain attributes of the
object the action is to be acting on. Then, the object needs to be loaded
before the action's access control is evaluated. On the other hand,
some actions might prefer the authorization to ignore specific attribute
checks as the object is unknown at checking time, so attribute checks and
thus automatic loading of objects needs to be enabled explicitly.

classEmployeesController<ApplicationControllerfilter_access_to:update,:attribute_check=>truedefupdate# @employee is already loaded from param[:id] because of :attribute_check
endend

You can provide the needed object through before_filters. This way, you
have full control over the object that the conditions are checked against.
Just make sure, your before_filters occur before any of the
filter_access_to calls.

If the access is denied, a permission_denied method is called on
the current_controller, if defined, and the issue is logged. For further
customization of the filters and object loading, have a look at the
complete API documentation of filter_access_to in
Authorization::AuthorizationInController::ClassMethods.

Views

In views, a simple permitted_to? helper makes showing blocks according to
the current user's privileges easy:

Models

There are two distinct features for model security built into this plugin:
authorizing CRUD operations on objects as well as query rewriting to limit
results according to certain privileges.

See also Authorization::AuthorizationInModel.

Model security for CRUD operations

To activate model security, all it takes is an explicit enabling for each
model that model security should be enforced on, i.e.

class Employee < ActiveRecord::Base
using_access_control
...
end

Thus,

Employee.create(...)

fails, if the current user is not allowed to :create :employees according
to the authorization rules. For the application to find out about what
happened if an operation is denied, the filters throw
Authorization::NotAuthorized exceptions.

As access control on read are costly, with possibly lots of objects being
loaded at a time in one query, checks on read need to be activated
explicitly by adding the :include_read option.

Query rewriting through named scopes

When retrieving large sets of records from databases, any authorization
needs to be integrated into the query in order to prevent inefficient
filtering afterwards and to use LIMIT and OFFSET in SQL statements. To
keep authorization rules out of the source code, this plugin offers query
rewriting mechanisms through named scopes. Thus,

Employee.with_permissions_to(:read)

returns all employee records that the current user is authorized to read.
In addition, just like normal named scopes, query rewriting may be chained
with the usual find method:

Employee.with_permissions_to(:read).find(:all, :conditions => ...)

If the current user is completely missing the permissions, an
Authorization::NotAuthorized exception is raised. Through
Model.obligation_conditions, application developers may retrieve the
conditions for manual rewrites.

There is a default role :guest that is used if a request is not
associated with any user or with a user without any roles. So, if your
application has public pages, :guest can be used to allow access
for users that are not logged in. All other roles are application defined
and need to be associated with users by the application.

If you need to change the default role, you can do so by adding an
initializer that contains the following statement:

Authorization.default_role=:anonymous

Privileges, such as :create, may be put into hierarchies to simplify
maintenance. So the example above has the same meaning as

For more complex use cases, authorizations need to be based on attributes.
Note that you then also need to set :attribute_check => true in
controllers for filter_access_to. E.g. if a branch admin should manage only
employees of his branch (see Authorization::Reader in the API docs for a
full list of available operators):

authorizationdorole:branch_admindohas_permission_on:employeesdoto:manage# user refers to the current_user when evaluating
if_attribute:branch=>is{user.branch}endendend

To reduce redundancy in has_permission_on blocks, a rule may depend on
permissions on associated objects:

Note: If you choose to generate an Account model for
restful_authentication instead of a User model as described above, you have
to customize the examples and create a ApplicationController#current_user
method.

Debugging Authorization

Currently, the main means of debugging authorization decisions is logging
and exceptions. Denied access to actions is logged to warn or
info, including some hints about what went wrong.

All bang methods throw exceptions which may be used to retrieve more
information about a denied access than a Boolean value.

Authorization Development Support

If your authorization rules become more complex, you might be glad to use
the authorization rules browser that comes with declarative_authorization.
It has a syntax-highlighted and a graphical view with filtering of the
current authorization rules.

By default, it will only be available in development mode. To use it, add
the following lines to your authorization_rules.rb for the appropriate
role:

has_permission_on:authorization_rules,:to=>:read

Then, point your browser to

http://localhost/authorization_rules

The browser needs Rails 2.3 (for Engine support). The graphical view
requires Graphviz (which e.g. can be installed through the graphviz
package under Debian and Ubuntu) and has only been tested under Linux.
Note: for Change Support you'll need to have a User#login method that
returns a non-ambiguous user name for identification.

Help and Contact

We have an issue tracker
for bugs and feature requests as well as a Google Group
for discussions on the usage of the plugin. You are very welcome to
contribute. Just fork the git repository and create a new issue, send a
pull request or contact me personally.