ddr-models 1.2.1 → 1.3.0

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