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.
- checksums.yaml +4 -4
- data/README.md +75 -1
- data/app/models/attachment.rb +6 -1
- data/app/models/collection.rb +19 -1
- data/app/models/component.rb +6 -1
- data/app/models/item.rb +6 -1
- data/app/models/solr_document.rb +3 -0
- data/app/models/target.rb +8 -1
- data/config/initializers/devise.rb~ +245 -0
- data/db/migrate/20141104181418_create_users.rb~ +6 -0
- data/lib/ddr/auth.rb +6 -1
- data/lib/ddr/auth.rb~ +47 -0
- data/lib/ddr/auth/ability.rb +5 -0
- data/lib/ddr/auth/ability.rb~ +204 -0
- data/lib/ddr/auth/group_service.rb~ +53 -0
- data/lib/ddr/auth/grouper_service.rb~ +77 -0
- data/lib/ddr/auth/remote_group_service.rb~ +35 -0
- data/lib/ddr/auth/superuser.rb~ +9 -0
- data/lib/ddr/auth/user.rb~ +65 -0
- data/lib/ddr/index_fields.rb +2 -2
- data/lib/ddr/models.rb +21 -4
- data/lib/ddr/models/engine.rb +26 -13
- data/lib/ddr/models/version.rb +1 -1
- data/lib/ddr/services/id_service.rb +4 -2
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/log/development.log +2727 -1701
- data/spec/dummy/log/test.log +56845 -35270
- data/spec/factories/attachment_factories.rb +0 -4
- data/spec/factories/collection_factories.rb +0 -8
- data/spec/factories/component_factories.rb +1 -6
- data/spec/factories/item_factories.rb +0 -8
- data/spec/factories/user_factories.rb~ +7 -0
- data/spec/features/grouper_integration_spec.rb~ +21 -0
- data/spec/models/ability_spec.rb +11 -24
- data/spec/models/ability_spec.rb~ +245 -0
- data/spec/models/superuser_spec.rb~ +13 -0
- data/spec/models/user_spec.rb~ +56 -0
- data/spec/services/group_service_spec.rb~ +71 -0
- data/spec/spec_helper.rb +16 -25
- metadata +23 -18
- data/config/initializers/ddr.rb +0 -8
- data/lib/ddr/configurable.rb +0 -34
data/lib/ddr/auth.rb
CHANGED
@@ -9,9 +9,12 @@ module Ddr
|
|
9
9
|
autoload :GrouperService
|
10
10
|
autoload :RemoteGroupService
|
11
11
|
|
12
|
-
#
|
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
|
data/lib/ddr/auth.rb~
ADDED
@@ -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
|
data/lib/ddr/auth/ability.rb
CHANGED
@@ -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
|