blacklight-access_controls 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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