blacklight-access_controls 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/Gemfile +32 -0
  4. data/README.textile +74 -0
  5. data/Rakefile +47 -0
  6. data/VERSION +1 -0
  7. data/blacklight-access_controls.gemspec +29 -0
  8. data/lib/blacklight-access_controls.rb +23 -0
  9. data/lib/blacklight/access_controls.rb +14 -0
  10. data/lib/blacklight/access_controls/ability.rb +148 -0
  11. data/lib/blacklight/access_controls/catalog.rb +27 -0
  12. data/lib/blacklight/access_controls/config.rb +39 -0
  13. data/lib/blacklight/access_controls/enforcement.rb +103 -0
  14. data/lib/blacklight/access_controls/permissions_cache.rb +19 -0
  15. data/lib/blacklight/access_controls/permissions_query.rb +53 -0
  16. data/lib/blacklight/access_controls/permissions_solr_document.rb +2 -0
  17. data/lib/blacklight/access_controls/user.rb +23 -0
  18. data/lib/generators/blacklight/ability.rb +4 -0
  19. data/lib/generators/blacklight/access_controls_generator.rb +49 -0
  20. data/solr_conf/conf/abc123 +0 -0
  21. data/solr_conf/conf/admin-extra.html +24 -0
  22. data/solr_conf/conf/admin-extra.menu-bottom.html +25 -0
  23. data/solr_conf/conf/admin-extra.menu-top.html +25 -0
  24. data/solr_conf/conf/clustering/carrot2/kmeans-attributes.xml +19 -0
  25. data/solr_conf/conf/clustering/carrot2/lingo-attributes.xml +24 -0
  26. data/solr_conf/conf/clustering/carrot2/stc-attributes.xml +19 -0
  27. data/solr_conf/conf/currency.xml +67 -0
  28. data/solr_conf/conf/dataimport.properties +3 -0
  29. data/solr_conf/conf/db-data-config.xml +93 -0
  30. data/solr_conf/conf/elevate.xml +38 -0
  31. data/solr_conf/conf/lang/contractions_ca.txt +8 -0
  32. data/solr_conf/conf/lang/contractions_fr.txt +15 -0
  33. data/solr_conf/conf/lang/contractions_ga.txt +5 -0
  34. data/solr_conf/conf/lang/contractions_it.txt +23 -0
  35. data/solr_conf/conf/lang/hyphenations_ga.txt +5 -0
  36. data/solr_conf/conf/lang/stemdict_nl.txt +6 -0
  37. data/solr_conf/conf/lang/stoptags_ja.txt +420 -0
  38. data/solr_conf/conf/lang/stopwords_ar.txt +125 -0
  39. data/solr_conf/conf/lang/stopwords_bg.txt +193 -0
  40. data/solr_conf/conf/lang/stopwords_ca.txt +220 -0
  41. data/solr_conf/conf/lang/stopwords_ckb.txt +136 -0
  42. data/solr_conf/conf/lang/stopwords_cz.txt +172 -0
  43. data/solr_conf/conf/lang/stopwords_da.txt +110 -0
  44. data/solr_conf/conf/lang/stopwords_de.txt +294 -0
  45. data/solr_conf/conf/lang/stopwords_el.txt +78 -0
  46. data/solr_conf/conf/lang/stopwords_en.txt +54 -0
  47. data/solr_conf/conf/lang/stopwords_es.txt +356 -0
  48. data/solr_conf/conf/lang/stopwords_eu.txt +99 -0
  49. data/solr_conf/conf/lang/stopwords_fa.txt +313 -0
  50. data/solr_conf/conf/lang/stopwords_fi.txt +97 -0
  51. data/solr_conf/conf/lang/stopwords_fr.txt +186 -0
  52. data/solr_conf/conf/lang/stopwords_ga.txt +110 -0
  53. data/solr_conf/conf/lang/stopwords_gl.txt +161 -0
  54. data/solr_conf/conf/lang/stopwords_hi.txt +235 -0
  55. data/solr_conf/conf/lang/stopwords_hu.txt +211 -0
  56. data/solr_conf/conf/lang/stopwords_hy.txt +46 -0
  57. data/solr_conf/conf/lang/stopwords_id.txt +359 -0
  58. data/solr_conf/conf/lang/stopwords_it.txt +303 -0
  59. data/solr_conf/conf/lang/stopwords_ja.txt +127 -0
  60. data/solr_conf/conf/lang/stopwords_lv.txt +172 -0
  61. data/solr_conf/conf/lang/stopwords_nl.txt +119 -0
  62. data/solr_conf/conf/lang/stopwords_no.txt +194 -0
  63. data/solr_conf/conf/lang/stopwords_pt.txt +253 -0
  64. data/solr_conf/conf/lang/stopwords_ro.txt +233 -0
  65. data/solr_conf/conf/lang/stopwords_ru.txt +243 -0
  66. data/solr_conf/conf/lang/stopwords_sv.txt +133 -0
  67. data/solr_conf/conf/lang/stopwords_th.txt +119 -0
  68. data/solr_conf/conf/lang/stopwords_tr.txt +212 -0
  69. data/solr_conf/conf/lang/userdict_ja.txt +29 -0
  70. data/solr_conf/conf/mapping-FoldToASCII.txt +3813 -0
  71. data/solr_conf/conf/mapping-ISOLatin1Accent.txt +246 -0
  72. data/solr_conf/conf/protwords.txt +21 -0
  73. data/solr_conf/conf/schema.blacklight.xml +724 -0
  74. data/solr_conf/conf/schema.xml +1268 -0
  75. data/solr_conf/conf/schema.xml.orig +1524 -0
  76. data/solr_conf/conf/solrconfig.adams.xml +1903 -0
  77. data/solr_conf/conf/solrconfig.blacklight.xml +411 -0
  78. data/solr_conf/conf/solrconfig.old.xml +1634 -0
  79. data/solr_conf/conf/solrconfig.xml +332 -0
  80. data/solr_conf/conf/solrconfig.xml.orig +3531 -0
  81. data/solr_conf/conf/spellings.txt +2 -0
  82. data/solr_conf/conf/stopwords.txt +14 -0
  83. data/solr_conf/conf/synonyms.txt +29 -0
  84. data/solr_conf/conf/update-script.js +53 -0
  85. data/solr_conf/conf/xslt/example.xsl +132 -0
  86. data/solr_conf/conf/xslt/example_atom.xsl +67 -0
  87. data/solr_conf/conf/xslt/example_rss.xsl +66 -0
  88. data/solr_conf/conf/xslt/luke.xsl +337 -0
  89. data/solr_conf/conf/xslt/updateXml.xsl +70 -0
  90. data/spec/factories/user.rb +6 -0
  91. data/spec/spec_helper.rb +29 -0
  92. data/spec/support/solr_support.rb +11 -0
  93. data/spec/test_app_templates/blacklight.yml +18 -0
  94. data/spec/test_app_templates/lib/generators/test_app_generator.rb +25 -0
  95. data/spec/unit/ability_spec.rb +202 -0
  96. data/spec/unit/catalog_spec.rb +41 -0
  97. data/spec/unit/config_spec.rb +69 -0
  98. data/spec/unit/enforcement_spec.rb +147 -0
  99. metadata +265 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 715bccb2faf2cc502417ad8d1f9052baf98c2c2e
4
+ data.tar.gz: c011219a6d76e3c0e6bba5640c9f5c92eb5fe300
5
+ SHA512:
6
+ metadata.gz: d80acc63c003ee2d3b84b5790bd5a755cea409efb58ee4311fd6e5b236712c3fbbb92e9609f6e93e948bc7cfae7bd0938dfad4f51e6d109a603ce3dc4ea4dfdd
7
+ data.tar.gz: 54dfe0310b6df052616602eb53d0f916e431717f0a918b0d436e992d8ee9eacb03312d5b69de7be2d880f62bfc0ee1d10db2b653c66b60195321790a526cafad
@@ -0,0 +1,10 @@
1
+ .rvmrc
2
+ Gemfile.lock
3
+
4
+ # Used by solr_wrapper
5
+ solr
6
+ tmp
7
+
8
+ # Test app generated by engine_cart
9
+ .internal_test_app
10
+
data/Gemfile ADDED
@@ -0,0 +1,32 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify gem dependencies in blacklight-access_controls.gemspec
4
+ gemspec
5
+
6
+ # -------------------------
7
+ # BEGIN ENGINE_CART BLOCK
8
+ # engine_cart: 0.8.0
9
+ # engine_cart stanza: 0.8.0
10
+ # the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
11
+ file = File.expand_path("Gemfile", ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path(".internal_test_app", File.dirname(__FILE__)))
12
+ if File.exist?(file)
13
+ begin
14
+ eval_gemfile file
15
+ rescue Bundler::GemfileError => e
16
+ Bundler.ui.warn '[EngineCart] Skipping Rails application dependencies:'
17
+ Bundler.ui.warn e.message
18
+ end
19
+ else
20
+ Bundler.ui.warn "[EngineCart] Unable to find test application dependencies in #{file}, using placeholder dependencies"
21
+
22
+ gem 'rails', ENV['RAILS_VERSION'] if ENV['RAILS_VERSION']
23
+
24
+ if ENV['RAILS_VERSION'].nil? || ENV['RAILS_VERSION'] =~ /^4.2/
25
+ gem 'responders', "~> 2.0"
26
+ gem 'sass-rails', ">= 5.0"
27
+ else
28
+ gem 'sass-rails', "< 5.0"
29
+ end
30
+ end
31
+ # END ENGINE_CART BLOCK
32
+ # -------------------------
@@ -0,0 +1,74 @@
1
+ h1. Blacklight Access Controls
2
+
3
+ Provides access controls for Blacklight-based applications.
4
+
5
+ *Background*: Much of this code was extracted from "hydra-access-controls":https://github.com/projecthydra/hydra-head/tree/master/hydra-access-controls
6
+
7
+
8
+ h2. Adding Access Controls to a Blacklight App
9
+
10
+ h3. Install the gem
11
+
12
+ * Add blacklight-access_controls to your Gemfile
13
+ * bundle install
14
+
15
+ h3. Configure solr
16
+
17
+ * Make sure your solrconfig.xml has a requestHandler for "permissions". For an example, see solr_conf/conf/solrconfig.xml.
18
+
19
+ * If you use solr field names that don't match the default field names used in Blacklight::AccessControls::Config for the "permissions" handler, you'll need to create a Rails initializer to set those values in Blacklight::AccessControls::Config.
20
+
21
+ h3. Run the generator
22
+
23
+ <pre>
24
+ rails generate blacklight:access_controls
25
+ </pre>
26
+
27
+
28
+ h2. Using Access Controls
29
+
30
+ Some notes about using blacklight-access_controls within your Blacklight app:
31
+
32
+ * You can grant access to a record to specific users or groups by adding them to the correct fields in the solr document. For example, discover_access_group_ssim: "public" or read_access_person_ssim: "frodo@example.com".
33
+
34
+ * The gem expects user.groups to return a list of groups that the user belongs to. By default, all users belong to a group called "public", and all logged-in users belong to a group called "registered".
35
+
36
+ * If you want a record to be readable by the public, you need to add "public" to the "read_access_group_ssim" field in the solr document, or if you want discover-only access, add "public" to "discover_access_group_ssim". (Discover-only means that the user can see that the record exists in a catalog search, but won't be able to view the record itself.)
37
+
38
+
39
+ h2. Developer Notes
40
+
41
+ This section contains information about working on the blacklight-access_controls gem itself.
42
+
43
+ h3. Set up Solr
44
+
45
+ <pre>
46
+ $ bundle exec rake solr:clean
47
+ $ bundle exec rake solr:config
48
+ $ bundle exec rake solr:start
49
+ $ bundle exec rake solr:stop
50
+ </pre>
51
+
52
+ h3. Generate a Rails test app
53
+
54
+ <pre>
55
+ $ bundle exec rake engine_cart:clean
56
+ $ bundle exec rake engine_cart:generate
57
+ </pre>
58
+
59
+ h3. Run the test suite
60
+
61
+ <pre>
62
+ $ bundle exec rake engine_cart:clean
63
+ $ bundle exec rake engine_cart:generate
64
+ $ bundle exec rake solr:spec
65
+ </pre>
66
+
67
+ h3. Run the Rails server in development mode
68
+
69
+ <pre>
70
+ $ bundle exec rake solr:start
71
+ $ bundle exec rake engine_cart:generate
72
+ $ bundle exec rake engine_cart:server
73
+ </pre>
74
+
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'solr_wrapper'
4
+
5
+ SOLR_OPTIONS = {
6
+ verbose: true,
7
+ cloud: false,
8
+ port: '8983',
9
+ version: '5.3.1',
10
+ instance_dir: 'solr',
11
+ download_dir: 'tmp'
12
+ }
13
+
14
+ SolrWrapper.default_instance_options = SOLR_OPTIONS
15
+
16
+ require 'solr_wrapper/rake_task'
17
+ require 'engine_cart/rake_task'
18
+
19
+ require 'rspec/core/rake_task'
20
+ RSpec::Core::RakeTask.new(:spec)
21
+
22
+ task :default => 'solr:spec'
23
+
24
+ def solr_config_dir
25
+ File.join(File.expand_path(File.dirname(__FILE__)), "solr_conf", "conf")
26
+ end
27
+
28
+ namespace :solr do
29
+
30
+ desc 'Configure solr cores'
31
+ task :config do
32
+ SolrWrapper.wrap do |solr|
33
+ core = solr.create(name: 'development', dir: solr_config_dir)
34
+ core = solr.create(name: 'test', dir: solr_config_dir)
35
+ end
36
+ end
37
+
38
+ desc "Run test suite (with solr wrapper)"
39
+ task :spec do
40
+ SolrWrapper.wrap do |solr|
41
+ solr.with_collection(name:'test', dir: solr_config_dir) do |collection_name|
42
+ Rake::Task['spec'].invoke
43
+ end
44
+ end
45
+ end
46
+
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,29 @@
1
+ version = File.read(File.expand_path("../VERSION", __FILE__)).strip
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "blacklight-access_controls"
5
+
6
+ gem.description = %q{Access controls for blacklight-based applications}
7
+ gem.summary = %q{Access controls for blacklight-based applications}
8
+ gem.homepage = "https://github.com/projectblacklight/blacklight-access_controls"
9
+ gem.email = ["blacklight-development@googlegroups.com"]
10
+ gem.authors = ["Chris Beer", "Justin Coyne", "Matt Zumwalt", "Valerie Maher"]
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.require_paths = ["lib"]
15
+ gem.version = version
16
+ gem.license = "APACHE2"
17
+
18
+ gem.required_ruby_version = '>= 1.9.3'
19
+
20
+ gem.add_dependency 'cancancan', '~> 1.8'
21
+ gem.add_dependency "blacklight", '~> 5.16'
22
+
23
+ gem.add_development_dependency "rake", '~> 10.1'
24
+ gem.add_development_dependency 'rspec', '~> 3.1'
25
+ gem.add_development_dependency "engine_cart", "~> 0.8"
26
+ gem.add_development_dependency "solr_wrapper"
27
+ gem.add_development_dependency "factory_girl_rails", "~> 4.0"
28
+ gem.add_development_dependency "database_cleaner"
29
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails'
2
+ require 'cancan'
3
+ require 'blacklight'
4
+ require 'blacklight/access_controls'
5
+
6
+ module Blacklight::AccessControls
7
+ extend ActiveSupport::Autoload
8
+
9
+ class << self
10
+ def configure
11
+ @config ||= Config.new
12
+ yield @config if block_given?
13
+ @config
14
+ end
15
+ alias :config :configure
16
+ end
17
+
18
+ # This error is raised when a user isn't allowed to access a given controller action.
19
+ # This usually happens within a call to Enforcement#enforce_access_controls but can be
20
+ # raised manually.
21
+ class AccessDenied < ::CanCan::AccessDenied; end
22
+
23
+ end
@@ -0,0 +1,14 @@
1
+ module Blacklight
2
+ module AccessControls
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Config
6
+ autoload :User
7
+ autoload :PermissionsQuery
8
+ autoload :PermissionsCache
9
+ autoload :PermissionsSolrDocument
10
+ autoload :Ability
11
+ autoload :Enforcement
12
+ autoload :Catalog
13
+ end
14
+ end
@@ -0,0 +1,148 @@
1
+ require 'cancan'
2
+
3
+ module Blacklight
4
+ module AccessControls
5
+ module Ability
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include CanCan::Ability
10
+ include Blacklight::AccessControls::PermissionsQuery
11
+
12
+ # Once you include this module, you can add custom
13
+ # permission methods to ability_logic, like so:
14
+ # self.ability_logic +=[:setup_my_permissions]
15
+ class_attribute :ability_logic
16
+ self.ability_logic = [:discover_permissions, :read_permissions]
17
+ end
18
+
19
+ def initialize(user, options={})
20
+ @current_user = user || guest_user
21
+ @options = options
22
+ @cache = Blacklight::AccessControls::PermissionsCache.new
23
+ grant_permissions
24
+ end
25
+
26
+ attr_reader :current_user, :options, :cache
27
+
28
+ def self.user_class
29
+ Blacklight::AccessControls.config.user_model.constantize
30
+ end
31
+
32
+ # A user who isn't logged in
33
+ def guest_user
34
+ Blacklight::AccessControls::Ability.user_class.new
35
+ end
36
+
37
+ def grant_permissions
38
+ Rails.logger.debug("Usergroups are " + user_groups.inspect)
39
+ self.ability_logic.each do |method|
40
+ send(method)
41
+ end
42
+ end
43
+
44
+ def discover_permissions
45
+ can :discover, String do |id|
46
+ test_discover(id)
47
+ end
48
+
49
+ can :discover, SolrDocument do |obj|
50
+ cache.put(obj.id, obj)
51
+ test_discover(obj.id)
52
+ end
53
+ end
54
+
55
+ def read_permissions
56
+ can :read, String do |id|
57
+ test_read(id)
58
+ end
59
+
60
+ can :read, SolrDocument do |obj|
61
+ cache.put(obj.id, obj)
62
+ test_read(obj.id)
63
+ end
64
+ end
65
+
66
+ def test_discover(id)
67
+ Rails.logger.debug("[CANCAN] Checking discover permissions for user: #{current_user.user_key} with groups: #{user_groups.inspect}")
68
+ group_intersection = user_groups & discover_groups(id)
69
+ !group_intersection.empty? || discover_users(id).include?(current_user.user_key)
70
+ end
71
+
72
+ def test_read(id)
73
+ Rails.logger.debug("[CANCAN] Checking read permissions for user: #{current_user.user_key} with groups: #{user_groups.inspect}")
74
+ group_intersection = user_groups & read_groups(id)
75
+ !group_intersection.empty? || read_users(id).include?(current_user.user_key)
76
+ end
77
+
78
+ # You can override this method if you are using a different AuthZ (such as LDAP)
79
+ def user_groups
80
+ return @user_groups if @user_groups
81
+
82
+ @user_groups = default_user_groups
83
+ @user_groups |= current_user.groups if current_user.respond_to? :groups
84
+ @user_groups |= ['registered'] unless current_user.new_record?
85
+ @user_groups
86
+ end
87
+
88
+ # Everyone is automatically a member of group 'public'
89
+ def default_user_groups
90
+ ['public']
91
+ end
92
+
93
+ # read implies discover, so discover_groups is the union of read and discover groups
94
+ def discover_groups(id)
95
+ doc = permissions_doc(id)
96
+ return [] if doc.nil?
97
+ dg = read_groups(id) | (doc[self.class.discover_group_field] || [])
98
+ Rails.logger.debug("[CANCAN] discover_groups: #{dg.inspect}")
99
+ dg
100
+ end
101
+
102
+ # read implies discover, so discover_users is the union of read and discover users
103
+ def discover_users(id)
104
+ doc = permissions_doc(id)
105
+ return [] if doc.nil?
106
+ dp = read_users(id) | (doc[self.class.discover_user_field] || [])
107
+ Rails.logger.debug("[CANCAN] discover_users: #{dp.inspect}")
108
+ dp
109
+ end
110
+
111
+ def read_groups(id)
112
+ doc = permissions_doc(id)
113
+ return [] if doc.nil?
114
+ rg = Array(doc[self.class.read_group_field])
115
+ Rails.logger.debug("[CANCAN] read_groups: #{rg.inspect}")
116
+ rg
117
+ end
118
+
119
+ def read_users(id)
120
+ doc = permissions_doc(id)
121
+ return [] if doc.nil?
122
+ rp = Array(doc[self.class.read_user_field])
123
+ Rails.logger.debug("[CANCAN] read_users: #{rp.inspect}")
124
+ rp
125
+ end
126
+
127
+ module ClassMethods
128
+
129
+ def discover_group_field
130
+ Blacklight::AccessControls.config.discover_group_field
131
+ end
132
+
133
+ def discover_user_field
134
+ Blacklight::AccessControls.config.discover_user_field
135
+ end
136
+
137
+ def read_group_field
138
+ Blacklight::AccessControls.config.read_group_field
139
+ end
140
+
141
+ def read_user_field
142
+ Blacklight::AccessControls.config.read_user_field
143
+ end
144
+
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,27 @@
1
+ # This is behavior for the catalog controller.
2
+
3
+ module Blacklight
4
+ module AccessControls
5
+ module Catalog
6
+ extend ActiveSupport::Concern
7
+
8
+ # Override blacklight to produce a search_builder that has
9
+ # the current ability in context
10
+ def search_builder processor_chain = search_params_logic
11
+ super(true).tap { |builder| builder.current_ability = current_ability }
12
+ end
13
+
14
+ # Controller "before" filter for enforcing access controls
15
+ # on show actions.
16
+ # @param [Hash] opts (optional, not currently used)
17
+ def enforce_show_permissions(opts={})
18
+ permissions = current_ability.permissions_doc(params[:id])
19
+ unless can? :read, permissions
20
+ raise Blacklight::AccessControls::AccessDenied.new("You do not have sufficient access privileges to read this document, which has been marked private.", :read, params[:id])
21
+ end
22
+ permissions
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ module Blacklight
2
+ module AccessControls
3
+ class Config
4
+
5
+ def initialize
6
+ @user_model = default_user_model
7
+ @discover_group_field = default_discover_group_field
8
+ @discover_user_field = default_discover_user_field
9
+ @read_group_field = default_read_group_field
10
+ @read_user_field = default_read_user_field
11
+ end
12
+
13
+ attr_accessor :user_model
14
+ attr_accessor :discover_group_field, :discover_user_field
15
+ attr_accessor :read_group_field, :read_user_field
16
+
17
+ def default_user_model
18
+ 'User'
19
+ end
20
+
21
+ def default_discover_group_field
22
+ "discover_access_group_ssim"
23
+ end
24
+
25
+ def default_discover_user_field
26
+ "discover_access_person_ssim"
27
+ end
28
+
29
+ def default_read_group_field
30
+ "read_access_group_ssim"
31
+ end
32
+
33
+ def default_read_user_field
34
+ "read_access_person_ssim"
35
+ end
36
+
37
+ end
38
+ end
39
+ end