ddr-models 1.2.1 → 1.3.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +75 -1
  3. data/app/models/attachment.rb +6 -1
  4. data/app/models/collection.rb +19 -1
  5. data/app/models/component.rb +6 -1
  6. data/app/models/item.rb +6 -1
  7. data/app/models/solr_document.rb +3 -0
  8. data/app/models/target.rb +8 -1
  9. data/config/initializers/devise.rb~ +245 -0
  10. data/db/migrate/20141104181418_create_users.rb~ +6 -0
  11. data/lib/ddr/auth.rb +6 -1
  12. data/lib/ddr/auth.rb~ +47 -0
  13. data/lib/ddr/auth/ability.rb +5 -0
  14. data/lib/ddr/auth/ability.rb~ +204 -0
  15. data/lib/ddr/auth/group_service.rb~ +53 -0
  16. data/lib/ddr/auth/grouper_service.rb~ +77 -0
  17. data/lib/ddr/auth/remote_group_service.rb~ +35 -0
  18. data/lib/ddr/auth/superuser.rb~ +9 -0
  19. data/lib/ddr/auth/user.rb~ +65 -0
  20. data/lib/ddr/index_fields.rb +2 -2
  21. data/lib/ddr/models.rb +21 -4
  22. data/lib/ddr/models/engine.rb +26 -13
  23. data/lib/ddr/models/version.rb +1 -1
  24. data/lib/ddr/services/id_service.rb +4 -2
  25. data/spec/dummy/db/development.sqlite3 +0 -0
  26. data/spec/dummy/log/development.log +2727 -1701
  27. data/spec/dummy/log/test.log +56845 -35270
  28. data/spec/factories/attachment_factories.rb +0 -4
  29. data/spec/factories/collection_factories.rb +0 -8
  30. data/spec/factories/component_factories.rb +1 -6
  31. data/spec/factories/item_factories.rb +0 -8
  32. data/spec/factories/user_factories.rb~ +7 -0
  33. data/spec/features/grouper_integration_spec.rb~ +21 -0
  34. data/spec/models/ability_spec.rb +11 -24
  35. data/spec/models/ability_spec.rb~ +245 -0
  36. data/spec/models/superuser_spec.rb~ +13 -0
  37. data/spec/models/user_spec.rb~ +56 -0
  38. data/spec/services/group_service_spec.rb~ +71 -0
  39. data/spec/spec_helper.rb +16 -25
  40. metadata +23 -18
  41. data/config/initializers/ddr.rb +0 -8
  42. data/lib/ddr/configurable.rb +0 -34
@@ -0,0 +1,6 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ end
5
+ end
6
+ end
@@ -9,9 +9,12 @@ module Ddr
9
9
  autoload :GrouperService
10
10
  autoload :RemoteGroupService
11
11
 
12
- # Superuser group
12
+ # Group authorized to act as superuser
13
13
  mattr_accessor :superuser_group
14
14
 
15
+ # Group authorized to create Collections
16
+ mattr_accessor :collection_creators_group
17
+
15
18
  ## Remote groups (i.e., Grouper) config settings
16
19
  # request.env key for group memberships
17
20
  mattr_accessor :remote_groups_env_key do
@@ -33,10 +36,12 @@ module Ddr
33
36
  "duke:library:repository:ddr:"
34
37
  end
35
38
 
39
+ # Name of group of which everyone (including anonymous users) is a member
36
40
  mattr_accessor :everyone_group do
37
41
  "public"
38
42
  end
39
43
 
44
+ # Group of authenticated users
40
45
  mattr_accessor :authenticated_users_group do
41
46
  "registered"
42
47
  end
@@ -0,0 +1,47 @@
1
+ module Ddr
2
+ module Auth
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :User
6
+ autoload :Superuser
7
+ autoload :Ability
8
+ autoload :GroupService
9
+ autoload :GrouperService
10
+ autoload :RemoteGroupService
11
+
12
+ # Superuser group
13
+ mattr_accessor :superuser_group do
14
+ ENV['SUPERUSER_GROUP']
15
+ end
16
+
17
+ ## Remote groups (i.e., Grouper) config settings
18
+ # request.env key for group memberships
19
+ mattr_accessor :remote_groups_env_key do
20
+ "ismemberof"
21
+ end
22
+
23
+ # request.env value internal delimiter
24
+ mattr_accessor :remote_groups_env_value_delim do
25
+ ";"
26
+ end
27
+
28
+ # pattern/repl for converting request.env membership values to proper (Grouper) group names
29
+ mattr_accessor :remote_groups_env_value_sub do
30
+ [/^urn:mace:duke\.edu:groups/, "duke"]
31
+ end
32
+
33
+ # Filter for getting list of remote groups for the repository - String, not Regexp
34
+ mattr_accessor :remote_groups_name_filter do
35
+ "duke:library:repository:ddr:"
36
+ end
37
+
38
+ mattr_accessor :everyone_group do
39
+ "public"
40
+ end
41
+
42
+ mattr_accessor :authenticated_users_group do
43
+ "registered"
44
+ end
45
+
46
+ end
47
+ end
@@ -6,6 +6,7 @@ module Ddr
6
6
 
7
7
  def custom_permissions
8
8
  action_aliases
9
+ collection_permissions
9
10
  discover_permissions
10
11
  events_permissions
11
12
  attachment_permissions
@@ -20,6 +21,10 @@ module Ddr
20
21
  alias_action :permissions, :default_permissions, to: :update
21
22
  end
22
23
 
24
+ def collection_permissions
25
+ can :create, Collection if current_user.member_of?(Ddr::Auth.collection_creators_group)
26
+ end
27
+
23
28
  def read_permissions
24
29
  super
25
30
  can :read, ActiveFedora::Datastream do |ds|
@@ -0,0 +1,204 @@
1
+ module Ddr
2
+ module Auth
3
+ class Ability
4
+
5
+ include Hydra::PolicyAwareAbility
6
+
7
+ def custom_permissions
8
+ action_aliases
9
+ discover_permissions
10
+ export_sets_permissions
11
+ events_permissions
12
+ batches_permissions
13
+ ingest_folders_permissions
14
+ metadata_files_permissions
15
+ attachment_permissions
16
+ children_permissions
17
+ upload_permissions
18
+ end
19
+
20
+ def action_aliases
21
+ # read aliases
22
+ alias_action :attachments, :collection_info, :components, :event, :events, :items, :targets, to: :read
23
+ # edit/update aliases
24
+ alias_action :permissions, :default_permissions, to: :update
25
+ end
26
+
27
+ def read_permissions
28
+ super
29
+ can :read, ActiveFedora::Datastream do |ds|
30
+ can? :read, ds.pid
31
+ end
32
+ end
33
+
34
+ def edit_permissions
35
+ super
36
+ can [:edit, :update, :destroy], ActiveFedora::Datastream do |action, ds|
37
+ can? action, ds.pid
38
+ end
39
+ end
40
+
41
+ def export_sets_permissions
42
+ can :create, ExportSet if authenticated_user?
43
+ can :manage, ExportSet, user: current_user
44
+ end
45
+
46
+ def events_permissions
47
+ can :read, Ddr::Events::Event, user: current_user
48
+ can :read, Ddr::Events::Event do |e|
49
+ can? :read, e.pid
50
+ end
51
+ end
52
+
53
+ def batches_permissions
54
+ can :manage, DulHydra::Batch::Models::Batch, :user_id => current_user.id
55
+ can :manage, DulHydra::Batch::Models::BatchObject do |batch_object|
56
+ can? :manage, batch_object.batch
57
+ end
58
+ end
59
+
60
+ def ingest_folders_permissions
61
+ can :create, IngestFolder if IngestFolder.permitted_folders(current_user).present?
62
+ can [:show, :procezz], IngestFolder, user: current_user
63
+ end
64
+
65
+ def metadata_files_permissions
66
+ can [:show, :procezz], MetadataFile, user: current_user
67
+ end
68
+
69
+ def download_permissions
70
+ can :download, ActiveFedora::Base do |obj|
71
+ if obj.is_a? Component
72
+ can?(:edit, obj) || (can?(:read, obj) && current_user.has_role?(obj, :downloader))
73
+ else
74
+ can? :read, obj
75
+ end
76
+ end
77
+ can :download, SolrDocument do |doc|
78
+ if doc.active_fedora_model == "Component"
79
+ can?(:edit, doc) || (can?(:read, doc) && current_user.has_role?(doc, :downloader))
80
+ else
81
+ can? :read, doc
82
+ end
83
+ end
84
+ can :download, ActiveFedora::Datastream do |ds|
85
+ if ds.dsid == Ddr::Datastreams::CONTENT and ds.digital_object.original_class == Component
86
+ can?(:edit, ds.pid) || (can?(:read, ds.pid) && current_user.has_role?(solr_doc(ds.pid), :downloader))
87
+ else
88
+ can? :read, ds.pid
89
+ end
90
+ end
91
+ end
92
+
93
+ def upload_permissions
94
+ can :upload, Ddr::Models::HasContent do |obj|
95
+ can?(:edit, obj)
96
+ end
97
+ end
98
+
99
+ def children_permissions
100
+ can :add_children, Ddr::Models::HasChildren do |obj|
101
+ can?(:edit, obj)
102
+ end
103
+ end
104
+
105
+ # Mimics Hydra::Ability#read_permissions
106
+ def discover_permissions
107
+ can :discover, String do |pid|
108
+ test_discover(pid)
109
+ end
110
+
111
+ can :discover, ActiveFedora::Base do |obj|
112
+ test_discover(obj.pid)
113
+ end
114
+
115
+ can :discover, SolrDocument do |obj|
116
+ cache.put(obj.id, obj)
117
+ test_discover(obj.id)
118
+ end
119
+ end
120
+
121
+ def attachment_permissions
122
+ can :add_attachment, Ddr::Models::HasAttachments do |obj|
123
+ can?(:edit, obj)
124
+ end
125
+ end
126
+
127
+ # Mimics Hydra::Ability#test_read + Hydra::PolicyAwareAbility#test_read in one method
128
+ def test_discover(pid)
129
+ Rails.logger.debug("[CANCAN] Checking discover permissions for user: #{current_user.user_key} with groups: #{user_groups.inspect}")
130
+ group_intersection = user_groups & discover_groups(pid)
131
+ result = !group_intersection.empty? || discover_persons(pid).include?(current_user.user_key)
132
+ result || test_discover_from_policy(pid)
133
+ end
134
+
135
+ # Mimics Hydra::PolicyAwareAbility#test_read_from_policy
136
+ def test_discover_from_policy(object_pid)
137
+ policy_pid = policy_pid_for(object_pid)
138
+ if policy_pid.nil?
139
+ return false
140
+ else
141
+ Rails.logger.debug("[CANCAN] -policy- Does the POLICY #{policy_pid} provide DISCOVER permissions for #{current_user.user_key}?")
142
+ group_intersection = user_groups & discover_groups_from_policy(policy_pid)
143
+ result = !group_intersection.empty? || discover_persons_from_policy(policy_pid).include?(current_user.user_key)
144
+ Rails.logger.debug("[CANCAN] -policy- decision: #{result}")
145
+ result
146
+ end
147
+ end
148
+
149
+ # Mimics Hydra::Ability#read_groups
150
+ def discover_groups(pid)
151
+ doc = permissions_doc(pid)
152
+ return [] if doc.nil?
153
+ dg = edit_groups(pid) | read_groups(pid) | (doc[self.class.discover_group_field] || [])
154
+ Rails.logger.debug("[CANCAN] discover_groups: #{dg.inspect}")
155
+ return dg
156
+ end
157
+
158
+ # Mimics Hydra::PolicyAwareAbility#read_groups_from_policy
159
+ def discover_groups_from_policy(policy_pid)
160
+ policy_permissions = policy_permissions_doc(policy_pid)
161
+ discover_group_field = Hydra.config[:permissions][:inheritable][:discover][:group]
162
+ dg = edit_groups_from_policy(policy_pid) | read_groups_from_policy(policy_pid) | ((policy_permissions == nil || policy_permissions.fetch(discover_group_field, nil) == nil) ? [] : policy_permissions.fetch(discover_group_field, nil))
163
+ Rails.logger.debug("[CANCAN] -policy- discover_groups: #{dg.inspect}")
164
+ return dg
165
+ end
166
+
167
+ # Mimics Hydra::Ability#read_persons
168
+ def discover_persons(pid)
169
+ doc = permissions_doc(pid)
170
+ return [] if doc.nil?
171
+ dp = edit_persons(pid) | read_persons(pid) | (doc[self.class.discover_person_field] || [])
172
+ Rails.logger.debug("[CANCAN] discover_persons: #{dp.inspect}")
173
+ return dp
174
+ end
175
+
176
+ def discover_persons_from_policy(policy_pid)
177
+ policy_permissions = policy_permissions_doc(policy_pid)
178
+ discover_individual_field = Hydra.config[:permissions][:inheritable][:discover][:individual]
179
+ dp = edit_persons_from_policy(policy_pid) | read_persons_from_policy(policy_pid) | ((policy_permissions == nil || policy_permissions.fetch(discover_individual_field, nil) == nil) ? [] : policy_permissions.fetch(discover_individual_field, nil))
180
+ Rails.logger.debug("[CANCAN] -policy- discover_persons: #{dp.inspect}")
181
+ return dp
182
+ end
183
+
184
+ def self.discover_person_field
185
+ Hydra.config[:permissions][:discover][:individual]
186
+ end
187
+
188
+ def self.discover_group_field
189
+ Hydra.config[:permissions][:discover][:group]
190
+ end
191
+
192
+ private
193
+
194
+ def authenticated_user?
195
+ current_user.persisted?
196
+ end
197
+
198
+ def solr_doc(pid)
199
+ SolrDocument.new(ActiveFedora::SolrService.query("id:\"#{pid}\"", rows: 1).first)
200
+ end
201
+
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,53 @@
1
+ module Ddr
2
+ module Auth
3
+ class GroupService
4
+
5
+ class_attribute :include_role_mapper_groups
6
+ self.include_role_mapper_groups = RoleMapper.role_names.present? rescue false
7
+
8
+ def role_mapper_user_groups(user)
9
+ RoleMapper.roles(user) rescue []
10
+ end
11
+
12
+ def role_mapper_groups
13
+ RoleMapper.role_names rescue []
14
+ end
15
+
16
+ def groups
17
+ default_groups | append_groups
18
+ end
19
+
20
+ def user_groups(user)
21
+ default_user_groups(user) | append_user_groups(user)
22
+ end
23
+
24
+ def superuser_group
25
+ Ddr::Auth.superuser_group
26
+ end
27
+
28
+ def append_groups
29
+ []
30
+ end
31
+
32
+ def append_user_groups(user)
33
+ []
34
+ end
35
+
36
+ def default_groups
37
+ dg = [Ddr::Auth.everyone_group, Ddr::Auth.authenticated_users_group]
38
+ dg += role_mapper_groups if include_role_mapper_groups
39
+ dg
40
+ end
41
+
42
+ def default_user_groups(user)
43
+ dug = [Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC]
44
+ if user && user.persisted?
45
+ dug << Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED
46
+ dug += role_mapper_user_groups(user) if include_role_mapper_groups
47
+ end
48
+ dug
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,77 @@
1
+ require 'dul_hydra'
2
+ require 'grouper-rest-client'
3
+
4
+ module DulHydra
5
+ module Services
6
+ class GrouperService
7
+
8
+ class_attribute :config
9
+
10
+ def self.configured?
11
+ !config.nil?
12
+ end
13
+
14
+ # List of all grouper groups for the repository
15
+ def self.repository_groups
16
+ groups = []
17
+ begin
18
+ client do |c|
19
+ g = c.groups(DulHydra.remote_groups_name_filter)
20
+ groups = g if c.ok?
21
+ end
22
+ rescue Ddr::Models::Error
23
+ end
24
+ groups
25
+ end
26
+
27
+ def self.repository_group_names
28
+ repository_groups.collect { |g| g["name"] }
29
+ end
30
+
31
+ def self.user_groups(user)
32
+ groups = []
33
+ begin
34
+ client do |c|
35
+ request_body = {
36
+ "WsRestGetGroupsRequest" => {
37
+ "subjectLookups" => [{"subjectIdentifier" => subject_id(user)}]
38
+ }
39
+ }
40
+ # Have to use :call b/c grouper-rest-client :subjects method doesn't support POST
41
+ response = c.call("subjects", :post, request_body)
42
+ if c.ok?
43
+ result = response["WsGetGroupsResults"]["results"].first
44
+ # Have to manually filter results b/c Grouper WS version 1.5 does not support filter parameter
45
+ if result && result["wsGroups"]
46
+ groups = result["wsGroups"].select { |g| g["name"] =~ /^#{DulHydra.remote_groups_name_filter}/ }
47
+ end
48
+ end
49
+ end
50
+ rescue StandardError => e
51
+ Rails.logger.error e
52
+ end
53
+ groups
54
+ end
55
+
56
+ def self.user_group_names(user)
57
+ user_groups(user).collect { |g| g["name"] }
58
+ end
59
+
60
+ def self.subject_id(user)
61
+ user.user_key.split('@').first
62
+ end
63
+
64
+ private
65
+
66
+ def self.client
67
+ raise Ddr::Models::Error unless configured?
68
+ yield Grouper::Rest::Client::Resource.new(config["url"],
69
+ user: config["user"],
70
+ password: config["password"],
71
+ timeout: config.fetch("timeout", 5).to_i
72
+ )
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,35 @@
1
+ module DulHydra
2
+ module Services
3
+ class RemoteGroupService < GroupService
4
+
5
+ attr_reader :env
6
+
7
+ def initialize(env = nil)
8
+ @env = env
9
+ end
10
+
11
+ def append_groups
12
+ GrouperService.repository_group_names
13
+ end
14
+
15
+ def append_user_groups(user)
16
+ if env && env.key?(DulHydra.remote_groups_env_key)
17
+ remote_groups
18
+ else
19
+ GrouperService.user_group_names(user)
20
+ end
21
+ end
22
+
23
+ def remote_groups
24
+ # get the raw list of values
25
+ groups = env[DulHydra.remote_groups_env_key].split(DulHydra.remote_groups_env_value_delim)
26
+ # munge values to proper Grouper group names, if necessary
27
+ groups = groups.collect { |g| g.sub(*DulHydra.remote_groups_env_value_sub) } if DulHydra.remote_groups_env_value_sub
28
+ # filter group list as configured
29
+ groups = groups.select { |g| g =~ /^#{DulHydra.remote_groups_name_filter}/ } if DulHydra.remote_groups_name_filter
30
+ groups
31
+ end
32
+
33
+ end
34
+ end
35
+ end