From 8d1c5720e9796a34994d76bbdb7ec09f7d3c345a Mon Sep 17 00:00:00 2001 From: Justin Coyne Date: Tue, 29 Jan 2013 20:38:02 -0600 Subject: [PATCH] Extract permission querying from AccessControlsEnforcement --- .../lib/hydra-access-controls.rb | 5 +- hydra-access-controls/lib/hydra/ability.rb | 6 +-- .../lib/hydra/access_controls_enforcement.rb | 50 ++----------------- .../lib/hydra/permissions_query.rb | 45 +++++++++++++++++ .../lib/hydra/permissions_solr_document.rb | 19 +++++++ .../unit/access_controls_enforcement_spec.rb | 8 +-- 6 files changed, 76 insertions(+), 57 deletions(-) create mode 100644 hydra-access-controls/lib/hydra/permissions_query.rb create mode 100644 hydra-access-controls/lib/hydra/permissions_solr_document.rb diff --git a/hydra-access-controls/lib/hydra-access-controls.rb b/hydra-access-controls/lib/hydra-access-controls.rb index 6964b3816..b219e3433 100644 --- a/hydra-access-controls/lib/hydra-access-controls.rb +++ b/hydra-access-controls/lib/hydra-access-controls.rb @@ -1,7 +1,4 @@ require 'active_support' -# TODO would it be possible to put the require fedora in an after_initialize block like this? -#ActiveSupport.on_load(:after_initialize) do -# This would allow solrizer to load it's config files after the rails logger is up. require 'active-fedora' require 'cancan' require 'rails' @@ -17,6 +14,8 @@ module Hydra autoload :PolicyAwareAbility autoload :AdminPolicy autoload :RoleMapperBehavior + autoload :PermissionsQuery + autoload :PermissionsSolrDocument class Engine < Rails::Engine end diff --git a/hydra-access-controls/lib/hydra/ability.rb b/hydra-access-controls/lib/hydra/ability.rb index 1be6fe58d..0de7689e6 100644 --- a/hydra-access-controls/lib/hydra/ability.rb +++ b/hydra-access-controls/lib/hydra/ability.rb @@ -9,7 +9,7 @@ module Hydra::Ability included do include CanCan::Ability - include Hydra::AccessControlsEnforcement + include Hydra::PermissionsQuery include Blacklight::SolrHelper class_attribute :ability_logic self.ability_logic = [:create_permissions, :edit_permissions, :read_permissions, :custom_permissions] @@ -93,10 +93,6 @@ def custom_permissions protected - def permissions_doc(pid) - @permission_doc_cache[pid] ||= get_permissions_solr_response_for_doc_id(pid) - end - def test_edit(pid) permissions_doc(pid) logger.debug("[CANCAN] Checking edit permissions for user: #{current_user.user_key} with groups: #{user_groups.inspect}") diff --git a/hydra-access-controls/lib/hydra/access_controls_enforcement.rb b/hydra-access-controls/lib/hydra/access_controls_enforcement.rb index 591ea1c2a..42a344eec 100644 --- a/hydra-access-controls/lib/hydra/access_controls_enforcement.rb +++ b/hydra-access-controls/lib/hydra/access_controls_enforcement.rb @@ -4,6 +4,7 @@ module Hydra::AccessControlsEnforcement included do include Hydra::AccessControlsEvaluation include Blacklight::SolrHelper # for force_to_utf8 + include Hydra::PermissionsQuery class_attribute :solr_access_filters_logic # Set defaults. Each symbol identifies a _method_ that must be in @@ -16,48 +17,6 @@ module Hydra::AccessControlsEnforcement end - # - # Solr integration - # - - # returns a params hash with the permissions info for a single solr document - # If the id arg is nil, then the value is fetched from params[:id] - # This method is primary called by the get_permissions_solr_response_for_doc_id method. - # Modeled on Blacklight::SolrHelper.solr_doc_params - # @param [String] id of the documetn to retrieve - def permissions_solr_doc_params(id=nil) - id ||= params[:id] - # just to be consistent with the other solr param methods: - { - :qt => :permissions, - :id => id # this assumes the document request handler will map the 'id' param to the unique key field - } - end - - # a solr query method - # retrieve a solr document, given the doc id - # Modeled on Blacklight::SolrHelper.get_permissions_solr_response_for_doc_id - # @param [String] id of the documetn to retrieve - # @param [Hash] extra_controller_params (optional) - def get_permissions_solr_response_for_doc_id(id=nil, extra_controller_params={}) - raise Blacklight::Exceptions::InvalidSolrID.new("The application is trying to retrieve permissions without specifying an asset id") if id.nil? - #solr_response = Blacklight.solr.get permissions_solr_doc_params(id).merge(extra_controller_params) - #path = blacklight_config.solr_path - solr_opts = permissions_solr_doc_params(id).merge(extra_controller_params) - response = Blacklight.solr.get('select', :params=> solr_opts) - solr_response = Blacklight::SolrResponse.new(force_to_utf8(response), solr_opts) - - raise Blacklight::Exceptions::InvalidSolrID.new("The solr permissions search handler didn't return anything for id \"#{id}\"") if solr_response.docs.empty? - SolrDocument.new(solr_response.docs.first, solr_response) - end - - # Loads permissions info into @permissions_solr_response and @permissions_solr_document - def load_permissions_from_solr(id=params[:id], extra_controller_params={}) - if @permissions_solr_document.nil? - @permissions_solr_document = get_permissions_solr_response_for_doc_id(id, extra_controller_params) - end - end - protected def gated_discovery_filters @@ -100,12 +59,13 @@ def is_public? # Controller "before" filter for enforcing access controls on show actions # @param [Hash] opts (optional, not currently used) def enforce_show_permissions(opts={}) - unless is_public? + permissions = permissions_doc(params[:id]) + unless permissions.is_public? #its not 'public' - if under_embargo? && !can?(:edit, params[:id]) + if permissions.under_embargo? && !can?(:edit, permissions) raise Hydra::AccessDenied.new("This item is under embargo. You do not have sufficient access privileges to read this document.", :edit, params[:id]) end - unless can? :read, params[:id] + unless can? :read, permissions raise Hydra::AccessDenied.new("You do not have sufficient access privileges to read this document, which has been marked private.", :read, params[:id]) end end diff --git a/hydra-access-controls/lib/hydra/permissions_query.rb b/hydra-access-controls/lib/hydra/permissions_query.rb new file mode 100644 index 000000000..13dfb6699 --- /dev/null +++ b/hydra-access-controls/lib/hydra/permissions_query.rb @@ -0,0 +1,45 @@ +module Hydra::PermissionsQuery + + def permissions_doc(pid) + @permission_doc_cache[pid] ||= get_permissions_solr_response_for_doc_id(pid) + end + + + protected + + # a solr query method + # retrieve a solr document, given the doc id + # Modeled on Blacklight::SolrHelper.get_permissions_solr_response_for_doc_id + # @param [String] id of the documetn to retrieve + # @param [Hash] extra_controller_params (optional) + def get_permissions_solr_response_for_doc_id(id=nil, extra_controller_params={}) + raise Blacklight::Exceptions::InvalidSolrID.new("The application is trying to retrieve permissions without specifying an asset id") if id.nil? + #solr_response = Blacklight.solr.get permissions_solr_doc_params(id).merge(extra_controller_params) + #path = blacklight_config.solr_path + solr_opts = permissions_solr_doc_params(id).merge(extra_controller_params) + response = Blacklight.solr.get('select', :params=> solr_opts) + solr_response = Blacklight::SolrResponse.new(force_to_utf8(response), solr_opts) + + raise Blacklight::Exceptions::InvalidSolrID.new("The solr permissions search handler didn't return anything for id \"#{id}\"") if solr_response.docs.empty? + Hydra::PermissionsSolrDocument.new(solr_response.docs.first, solr_response) + end + + # + # Solr integration + # + + # returns a params hash with the permissions info for a single solr document + # If the id arg is nil, then the value is fetched from params[:id] + # This method is primary called by the get_permissions_solr_response_for_doc_id method. + # Modeled on Blacklight::SolrHelper.solr_doc_params + # @param [String] id of the documetn to retrieve + def permissions_solr_doc_params(id=nil) + id ||= params[:id] + # just to be consistent with the other solr param methods: + { + :qt => :permissions, + :id => id # this assumes the document request handler will map the 'id' param to the unique key field + } + end + +end diff --git a/hydra-access-controls/lib/hydra/permissions_solr_document.rb b/hydra-access-controls/lib/hydra/permissions_solr_document.rb new file mode 100644 index 000000000..041ef048d --- /dev/null +++ b/hydra-access-controls/lib/hydra/permissions_solr_document.rb @@ -0,0 +1,19 @@ +class Hydra::PermissionsSolrDocument < SolrDocument + def under_embargo? + #permissions = permissions_doc(params[:id]) + embargo_key = ActiveFedora::SolrService.solr_name("embargo_release_date", Hydra::Datastream::RightsMetadata.date_indexer) + if self[embargo_key] + embargo_date = Date.parse(self[embargo_key].split(/T/)[0]) + return embargo_date > Date.parse(Time.now.to_s) + end + false + end + + def is_public? + access_key = ActiveFedora::SolrService.solr_name("access", Hydra::Datastream::RightsMetadata.indexer) + self[access_key].present? && self[access_key].first.downcase == "public" + end + + +end + diff --git a/hydra-access-controls/spec/unit/access_controls_enforcement_spec.rb b/hydra-access-controls/spec/unit/access_controls_enforcement_spec.rb index 572a3e8e9..a0803955e 100644 --- a/hydra-access-controls/spec/unit/access_controls_enforcement_spec.rb +++ b/hydra-access-controls/spec/unit/access_controls_enforcement_spec.rb @@ -72,11 +72,11 @@ def session user = User.new :uid=>'testuser@example.com' RoleMapper.stub(:roles).with(user.user_key).and_return(["archivist"]) subject.stub(:current_user).and_return(user) - subject.should_receive(:can?).with(:edit, nil).and_return(true) subject.stub(:can?).with(:read, nil).and_return(true) - stub_doc = SolrDocument.new({"edit_access_person_tsim"=>["testuser@example.com"], "embargo_release_date_dtsi"=>(Date.parse(Time.now.to_s)+2).to_s}) + stub_doc = Hydra::PermissionsSolrDocument.new({"edit_access_person_tsim"=>["testuser@example.com"], "embargo_release_date_dtsi"=>(Date.parse(Time.now.to_s)+2).to_s}) subject.params = {} + subject.should_receive(:can?).with(:edit, stub_doc).and_return(true) subject.should_receive(:get_permissions_solr_response_for_doc_id).and_return(stub_doc) lambda {subject.send(:enforce_show_permissions, {}) }.should_not raise_error Hydra::AccessDenied end @@ -84,10 +84,10 @@ def session user = User.new :uid=>'testuser@example.com' RoleMapper.stub(:roles).with(user.user_key).and_return([]) subject.stub(:current_user).and_return(user) - subject.should_receive(:can?).with(:edit, nil).and_return(false) subject.stub(:can?).with(:read, nil).and_return(true) subject.params = {} - stub_doc = SolrDocument.new({"edit_access_person_tsim"=>["testuser@example.com"], "embargo_release_date_dtsi"=>(Date.parse(Time.now.to_s)+2).to_s}) + stub_doc = Hydra::PermissionsSolrDocument.new({"edit_access_person_tsim"=>["testuser@example.com"], "embargo_release_date_dtsi"=>(Date.parse(Time.now.to_s)+2).to_s}) + subject.should_receive(:can?).with(:edit, stub_doc).and_return(false) subject.should_receive(:get_permissions_solr_response_for_doc_id).and_return(stub_doc) lambda {subject.send(:enforce_show_permissions, {})}.should raise_error Hydra::AccessDenied, "This item is under embargo. You do not have sufficient access privileges to read this document." end