hydra-access-controls

The hydra-access-controls gem provides access controls models and functionality for Hydra Heads. See the hydra-head gem and the Hydra Project website for more info.

Some background information is available on the wiki at https://github.com/projecthydra/hydra-head/wiki/Access-Controls

Installation

The easiest way to make your code use this gem is to run the hydra generator that comes with the hydra-head gem. That will set up everything you need:

  • adds include Hydra::User to your User class
  • modifies the filters in your CatalogController class to inject access controls into solr queries
  • adds the YAML files that are used by the default RoleMapper class
  • adds section to hydra_config initializer that sets names used to look up enforcement info in solr (see “Modifying solr field names for enforcement” below)
  • adds ability.rb under app/models

Usage

Enforcing Hydra-based Access Controls using CanCan and Hydra::Ability

The hydra generator handles part of this for you – it sets up the CatalogController (Blacklight’s main controller for searches) to do gated discovery for you and creates an ability.rb file under app/models.

Beyond enabling gated discovery, everything is done using CanCan. For more information on CanCan, how to use it, and how to define access controls policies (aka abilities), refer to the CanCan documentation.

Within your CanCan ability definitions, app/models/ability.rb, the Hydra::Ability module is already included. This module has :read, :edit, and :discover permissions defined for you, along with some convenience methods that help you evaluate permssions against info in the rightsMetadata datastream.

In your custom controllers, you will need to enforce access controls using CanCan. There are a number of ways to do this. The easiest way is to use the cancan controller action ‘load_and_authorize_resource’, however on show and edit, this also causes a load the resource from fedora, which you may want to avoid. If you want to authorize from solr, you ought to be able to call the cancan methods `authorize!` or `can?` which just checks the solr permissions handler.

Examples of using authorize! and can? in controller methods:


def show
  authorize! :show, params[:id] # raises CanCan::Access denied if they don't have permission
  ...
end

def edit
  if can? :edit, params[:id]
    ## User is authorized
  else
    ## not authorized
  end
end

Modifying solr field names for enforcement

Hydra uses its own set of default solr field names to track rights-related metadata in solr. If you want to use your own field names, you can change them in your Hydra config. You will also have to modify the permissions response handler in your solrconfig.xml to return those fields.

Note: The hydra generator sets up the defaults for you in this file. You only need to edit it if you want to change the field names.

In config/initializers/hydra_config.rb


  Hydra.configure(:shared) do |config|
    # ... other stuff ...
    indexer = Solrizer::Descriptor.new(:string, :stored, :indexed, :multivalued)
    config[:permissions] = {
      :discover => {:group =>ActiveFedora::SolrQueryBuilder.solr_name("discover_access_group", indexer), :individual=>ActiveFedora::SolrQueryBuilder.solr_name("discover_access_person", indexer)},
      :read => {:group =>ActiveFedora::SolrQueryBuilder.solr_name("read_access_group", indexer), :individual=>ActiveFedora::SolrQueryBuilder.solr_name("read_access_person", indexer)},
      :edit => {:group =>ActiveFedora::SolrQueryBuilder.solr_name("edit_access_group", indexer), :individual=>ActiveFedora::SolrQueryBuilder.solr_name("edit_access_person", indexer)},
      :owner => ActiveFedora::SolrQueryBuilder.solr_name("depositor", indexer),
      :embargo_release_date => ActiveFedora::SolrQueryBuilder.solr_name("embargo_release_date", Solrizer::Descriptor.new(:date, :stored, :indexed))
    }
    indexer = Solrizer::Descriptor.new(:string, :stored, :indexed, :multivalued)
    config[:permissions][:inheritable] = {
      :discover => {:group =>ActiveFedora::SolrQueryBuilder.solr_name("inheritable_discover_access_group", indexer), :individual=>ActiveFedora::SolrQueryBuilder.solr_name("inheritable_discover_access_person", indexer)},
      :read => {:group =>ActiveFedora::SolrQueryBuilder.solr_name("inheritable_read_access_group", indexer), :individual=>ActiveFedora::SolrQueryBuilder.solr_name("inheritable_read_access_person", indexer)},
      :edit => {:group =>ActiveFedora::SolrQueryBuilder.solr_name("inheritable_edit_access_group", indexer), :individual=>ActiveFedora::SolrQueryBuilder.solr_name("inheritable_edit_access_person", indexer)},
      :owner => ActiveFedora::SolrQueryBuilder.solr_name("inheritable_depositor", indexer),
      :embargo_release_date => ActiveFedora::SolrQueryBuilder.solr_name("inheritable_embargo_release_date", Solrizer::Descriptor.new(:date, :stored, :indexed))
    }
  end

Policy-based Enforcement (or Collecton-level enforcement)

If you have Policy-based enforcement enabled, then objects will inherit extra GRANT permissions from AdminPolicy objects (APOs) they are linked to with an isGovernedBy RDF relationship (stored in solr as isGovernedBy_ssim field). This allows you to grant discover/read/edit access for a whole set of objects by changing the policy they are governed by.

AdminPolicy objects store their inheritable rightsMetadata in a datastream called defaultRights. This datastream uses the regular Hydra rightsMetadata schema. Each AdminPolicy object also has its own rightsMetadata datasream, like all other Hydra assets, which specifies who is able to edit the Policy or use it (associate it with objects).

Object-level permissions and Policy-level permissions are combined to produce the list of Individuals & Groups who have access to the object. This means that if either the object’s rightsMetadata or the Policy’s defaultRights grants access to an Individual or Group, that access will be allowed.

  • Currently, an asset can have only one Policy associated with it — you can’t associate objects with multiple policies

To turn on Policy-based enforcement,

  • include the Hydra::PolicyAwareAbility module in your Ability class (Make sure to remove `include Hydra::Ability`)
  • include the Hydra::PolicyAwareAccessControlsEnforcement module into any appropriate Controllers (or into ApplicationController)

Example app/models/ability.rb


  class Ability
    include Hydra::PolicyAwareAbility
  end

Example app/controllers/catalog_controller.rb


  class CatalogController < ApplicationController  

    include Blacklight::Catalog
    include Hydra::Controller::ControllerBehavior
    include Hydra::PolicyAwareAccessControlsEnforcement
    
    # ...
  end

Contributing

1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am ‘Added some feature’`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request

Testing

$ bundle exec rake spec