-
Notifications
You must be signed in to change notification settings - Fork 3
Authorization
We are using CanCan to manage authorization in our management websites. Our public websites allow anonymous access. In this page we will go into details into the way we are using CanCan.
Our specifications define two type of users:
- Managers: can manage all the data in the application, including Trade data;
and
- Contributors: Can view, edit and add data to taxon concepts and associated pages. Contributors can not manage what is identified as Core Data (e.g.: Taxonomies, Ranks, Species Listings, etc), nor can they change data in bulk. They can not visit the Trade Database management page.
As we only have two roles and each user can only have one of those roles, we decided to use only a boolean attribute in the User model. This attribute is named is_manager
and it defaults to false for newly created users.
We define the authorization rules in CanCan's ability file: app/models/ability.rb
can :manage, :all
For Contributors we first grant access to the read, update, and create actions on all objects, leaving out the destroy action and thus preventing them from deleting any type of data:
can :read, :all
can :update, :all
can :create, :all
We then specify some exceptions to these rules.
Contributors can only update their own accounts.
cannot :update, User do |u|
u.id != user.id
end
Contributors cannot manage Core Data, and do bulk updates (eg: admin_quotas_path
, admin_eu_regulations_path
)
cannot :manage, [
Taxonomy, Rank, Designation,
Instrument, SpeciesListing,
ChangeType, EuDecisionType,
Language, GeoEntity, GeoEntityType,
TradeCode, Trade::TaxonConceptTermPair,
TermTradeCodesPair, Event, CitesSuspension,
Quota, EuRegulation, EuSuspensionRegulation,
Trade::Shipment, Trade::Permit, Trade::AnnualReportUpload,
Trade::ValidationRule
]
Access to the Trade Management page is controlled in app/controllers/trade_controller.rb
, by calling the before filter verify_manager
, which prevents non managers from accessing the trade namespace pages.
In the Species+ Admin the authorize_resource
method is called in app/controllers/admin/standard_authorization_controller.rb
which inherits from Admin::SimpleCrudController
, and which then is used by most of the other controllers (e.g.: app/controllers/admin/taxonomies_controller.rb
).
Some controllers that don't have a direct association with a Model are not inheriting from the StandardAuthorizationController, and call the authorization method like this:
authorize_resource :class => false
Otherwise a wrong name exception was being thrown, as CanCan was trying to get to a model with the name derived from the controller (e.g.: Admin::TaxonQuotasController
=> TaxonQuota
, instead of Quota
, as defined in the defaults
method in the head of the controller file).
Another special case is the Admin::UsersController
which has one rule:
cannot :update, User do |u|
u.id != user.id
end
that needs to take into consideration the object being accessed by the edit
method, and so instead of just calling authorize_resource
the method load_and_authorize_resource
needs to be called. As we are using the InheritedResources
gem and are overwriting the collection
method we need to pass in :except => :index
into the load_and_authorize_resource
method otherwise it doesn't work as per the CanCan documentation. As we allow contributors to view all other users, we don't need to add accessible_by
to the collection method.
To avoid confusion we hide some of the links from users depending on their role or on their level of access, like in app/views/shared/_topbar.html.erb
In app/controllers/application_controller.rb
we added the following method:
rescue_from CanCan::AccessDenied do |exception|
rescue_path = if request.referrer && request.referrer != request.url
request.referer
else
admin_root_path
end
redirect_to rescue_path, :alert => case exception.action
when :destroy
"You are not authorized to destroy that record"
else
exception.message
end
end
Which will catch the AccessDenied exception and redirect the users either to the referrer page, if not the same, or to the Admin root page.