-
Notifications
You must be signed in to change notification settings - Fork 2
Access Controls
We are currently implementing the out of the box hydra access controls for Ichabod. This involves the following:
The following line as indicated by the Hydra wiki on access controls gives us the default behavior for hydra permissions, which allows us to assign access groups to these objects (Review the Hydra code):
# app/models/nyucore.rb
class Nyucore < ActiveFedora::Base
include Hydra::AccessControls::Permissions
...
end
In the DataLoader
we define edit_groups
that loaded records belong to. This means that any user belonging to this group can discover, read and edit these objects. Note that edit access includes the destroy, edit and update actions.
The way we currently implement this group assignment is in the DataLoader
when we are loading the records into Ichabod:
# lib/ichabod/data_loader.rb
if @prefix == "sdr" then
...
core.set_edit_groups(['gis_cataloger'],[])
...
elsif @prefix == "fda" then
...
core.set_edit_groups(['fda_cataloger'],[])
...
end
This doesn't cover any cases of natively created records but is the perfect candidate for a mapper from collection to access groups which could be setup in a callback on the model.
Currently we toss in a default catch-all admin_group
given edit rights to all records created in Ichabod:
# app/models/nyucore.rb
...
after_create :add_admin_group
...
def add_admin_group
self.set_edit_groups(["admin_group"],[])
self.save
end
For testing and potentially for production we can add usernames to user groups in YAML files (named each for their environment) like so:
# config/role_map_test.yml
gis_cataloger:
- gis_admin
fda_cataloger:
- fda_admin
admin_group:
- test_admin
So where we add admin_group
to each record created in Ichabod, here we specify that the user called test_admin
(when Rails.env.test?
) has edit rights to those files.
When you generate a Hydra head from the gem it will create an ability file and insert include Hydra::Ability
at the top. As far as setting default permissions on our objects this is what that line gets you (among much else that isn't relevant to this specific implementation):
# https://github.com/projecthydra/hydra-head/blob/master/hydra-access-controls/lib/hydra/ability.rb
def edit_permissions
can [:edit, :update, :destroy], String do |pid|
test_edit(pid)
end
can [:edit, :update, :destroy], ActiveFedora::Base do |obj|
test_edit(obj.pid)
end
can [:edit, :update, :destroy], SolrDocument do |obj|
cache.put(obj.id, obj)
test_edit(obj.id)
end
end
Essentially we setup our users in edit_groups
on the object and we get all this free authorization on :edit
, :update
, and :destroy
. This makes adding authorize!
statements in the related controller trivial, as you'll see below.
Hydra has a number of functions which it loads in a specific order to determine all of the application's permissions. In our local ability file we can override any of these if need be but there are two specific ones left unimplemented and which we have setup here:
# app/models/ability.rb
class Ability
include Hydra::Ability
# Define any customized permissions here.
def custom_permissions
end
# Override create permissions, which are blank by default
def create_permissions
if user_groups.include?('admin_group') || user_groups.include?('gis_cataloger')
can [:new, :create], ActiveFedora::Base
end
end
end
Ok we don't actually do anything in custom_permissions
yet because we don't need to. However, we setup the ability for users in our defined admin groups (i.e. admin_group and gis_cataloger) to create new records in Ichabod.
Hydra does not implement create_permissions
at all and leaves that bit of functionlity up to each local application.
CanCan's authorize!
function checks the rules laid out in the ability file and raises a CanCan::AccessDenied
error if the user cannot?
. We have a global rescue handler for this error in the application_controller.rb
as suggested by the CanCan wiki.
We should authorize the current user in the controller (in this case nyucores_controller.rb
) before we perform any action on an object.
The Hydra implementation of CanCan will look at the ActiveFedora object, the SolrDocument or the item's id
to see if we can perform the called action on this object. As shown above it will first check against the item id
, which is the fastest method since it checks the cache first and then the solr index.
This is why Hydra recommends constructing your authorize statements in the controller like this:
# app/controllers/nyucores_controller.rb
def edit
authorize! :edit, params[:id]
@item = Nyucore.find(params[:id])
...
end
On actions where this doesn't make sense because there is no id
in the params (e.g. a new object is being created) we can pass in the ActiveFedora::Base
object after it has been created and subsequently authorize:
# app/controllers/nyucores_controller.rb
def new
@item = Nyucore.new
authorize! :edit, @item
...
end
To be investigated: I believe that using the CanCan magic known as load_and_authorize_resource
at the top of the controller could get you the same effect but likely without the efficiency Hydra built in.
We have not activated gated access for discovery, that is, everyone can search and view the records through the Blacklight search. Because Hydra indexes the permissions into Solr they have made a way to easily activate gated access in Blacklight by uncommenting the following lines:
# app/controllers/catalog_controller.rb
class CatalogController < ApplicationController
...
# These before_filters apply the hydra access controls
# before_filter :enforce_show_permissions, :only=>:show
# This applies appropriate access controls to all solr queries
# CatalogController.solr_search_params_logic += [:add_access_controls_to_solr_params]
...
end
Most of this information is taken from the respective wikis of CanCan and Hydra-Access-Controls.