access_roles 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +12 -0
- data/README.md +36 -0
- data/Rakefile +6 -0
- data/access_roles.gemspec +30 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/access_roles.rb +16 -0
- data/lib/access_roles/detached_role_set.rb +56 -0
- data/lib/access_roles/permissions.rb +16 -0
- data/lib/access_roles/property_role_set.rb +42 -0
- data/lib/access_roles/role.rb +119 -0
- data/lib/access_roles/role_set.rb +104 -0
- data/lib/access_roles/role_set_query.rb +83 -0
- data/lib/access_roles/role_type.rb +19 -0
- data/lib/access_roles/role_types.rb +48 -0
- data/lib/access_roles/roles.rb +21 -0
- data/lib/access_roles/roles_vocabulary.rb +25 -0
- data/lib/access_roles/version.rb +3 -0
- metadata +178 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 91cf664298c08ca0b5395696453206d0b573e09e
|
4
|
+
data.tar.gz: 355b638c263cd0323f6b563656d963c3847cfa2f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f384c27417bb992ddfada04ed2a0cad5ce1583d24116624006ea4ae990c39510487156f833c5b0a83a753e614cb151ce641d8699005e09502a7b8f3bddd4e039
|
7
|
+
data.tar.gz: 4ee35f09f45373b67b649fe9a2d79abebf321e695cb114ce85b113da7f7bc11f7b0787ef2e5f01b0f51c1bfe8a88f32de48e5640fe056837e9a3d1f01b3ec057
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Copyright (c) 2014, Duke University
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
9
|
+
|
10
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# AccessRoles
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/access_roles`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'access_roles'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install access_roles
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/access_roles.
|
36
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'access_roles/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "access_roles"
|
8
|
+
spec.version = AccessRoles::VERSION
|
9
|
+
spec.authors = ["David Chandek-Stark"]
|
10
|
+
spec.email = ["dchandekstark@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Access role management library for role-based access control.}
|
13
|
+
spec.description = %q{Access role management library for role-based access control, based on RDF and ActiveTriples.}
|
14
|
+
spec.homepage = "https://github.com/duke-libraries/access_roles"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "hashie"
|
22
|
+
spec.add_dependency "active-triples", "~> 0.6.1"
|
23
|
+
spec.add_dependency "hydra-validations"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "rspec-its"
|
29
|
+
spec.add_development_dependency "factory_girl"
|
30
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "access_roles"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/access_roles.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "access_roles/version"
|
2
|
+
|
3
|
+
module AccessRoles
|
4
|
+
|
5
|
+
autoload :DetachedRoleSet, "access_roles/detached_role_set"
|
6
|
+
autoload :Permissions, "access_roles/permissions"
|
7
|
+
autoload :PropertyRoleSet, "access_roles/property_role_set"
|
8
|
+
autoload :Role, "access_roles/role"
|
9
|
+
autoload :Roles, "access_roles/roles"
|
10
|
+
autoload :RolesVocabulary, "access_roles/roles_vocabulary"
|
11
|
+
autoload :RoleSet, "access_roles/role_set"
|
12
|
+
autoload :RoleSetQuery, "access_roles/role_set_query"
|
13
|
+
autoload :RoleType, "access_roles/role_type"
|
14
|
+
autoload :RoleTypes, "access_roles/role_types"
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "set"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module AccessRoles
|
5
|
+
#
|
6
|
+
# Wraps a set of Roles detached from a repository object
|
7
|
+
#
|
8
|
+
class DetachedRoleSet < RoleSet
|
9
|
+
|
10
|
+
def_delegator :role_set, :each
|
11
|
+
|
12
|
+
class << self
|
13
|
+
# Deserialize a serialized RoleSet into a DetachedRoleSet
|
14
|
+
def deserialize(serialized)
|
15
|
+
role_set = serialized.map { |role_data| Role.deserialize(role_data) }
|
16
|
+
new(role_set)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Deserialize a JSON representation of a set of Roles into a DetachedRoleSet
|
20
|
+
def from_json(json)
|
21
|
+
deserialize JSON.parse(json)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_writer :role_set
|
26
|
+
|
27
|
+
def initialize(role_set = Set.new)
|
28
|
+
super role_set.to_set
|
29
|
+
end
|
30
|
+
|
31
|
+
def grant(*roles)
|
32
|
+
role_set.merge coerce(roles)
|
33
|
+
end
|
34
|
+
|
35
|
+
def revoke(*roles)
|
36
|
+
self.role_set -= coerce(roles)
|
37
|
+
end
|
38
|
+
|
39
|
+
def revoke_all
|
40
|
+
clear
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_a
|
44
|
+
role_set.to_a
|
45
|
+
end
|
46
|
+
|
47
|
+
# Merges the roles from another role set into the role set
|
48
|
+
# @param other [Enumerable<Role>]
|
49
|
+
# @return [DetachedRoleSet] self
|
50
|
+
def merge(other)
|
51
|
+
role_set.merge other
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
class Permissions
|
3
|
+
|
4
|
+
READ = :read
|
5
|
+
DOWNLOAD = :download
|
6
|
+
ADD_CHILDREN = :add_children
|
7
|
+
UPDATE = :update
|
8
|
+
REPLACE = :replace
|
9
|
+
ARRANGE = :arrange
|
10
|
+
AUDIT = :audit
|
11
|
+
GRANT = :grant
|
12
|
+
|
13
|
+
ALL = [ READ, DOWNLOAD, ADD_CHILDREN, UPDATE, REPLACE, ARRANGE, AUDIT, GRANT ]
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
#
|
3
|
+
# Wraps a set of Roles implemented as an ActiveTriples::Term.
|
4
|
+
#
|
5
|
+
class PropertyRoleSet < RoleSet
|
6
|
+
|
7
|
+
def grant(*roles)
|
8
|
+
if roles.present?
|
9
|
+
role_set << coerce(roles)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @note We have to destroy resources on the ActiveTriples::Term
|
14
|
+
# because Term#delete does not support isomorphism.
|
15
|
+
# @see https://github.com/ActiveTriples/ActiveTriples/issues/42
|
16
|
+
def revoke(*roles)
|
17
|
+
coerce(roles).each do |role|
|
18
|
+
if role_index = find_index(role)
|
19
|
+
role_set[role_index].destroy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @note We have to destroy resources on the
|
25
|
+
# ActiveTriples::Term because Term#delete does not
|
26
|
+
# support isomorphism.
|
27
|
+
# @see https://github.com/ActiveTriples/ActiveTriples/issues/42
|
28
|
+
def revoke_all
|
29
|
+
each(&:destroy)
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def each(&block)
|
34
|
+
role_set.map.each(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_set
|
38
|
+
map.to_set
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'active_triples'
|
2
|
+
require 'hydra/validations'
|
3
|
+
|
4
|
+
module AccessRoles
|
5
|
+
#
|
6
|
+
# The assignment of a role to an agent within a scope.
|
7
|
+
#
|
8
|
+
class Role < ActiveTriples::Resource
|
9
|
+
|
10
|
+
DEFAULT_SCOPE = Roles::RESOURCE_SCOPE
|
11
|
+
|
12
|
+
include Hydra::Validations
|
13
|
+
|
14
|
+
configure type: RolesVocabulary.Role
|
15
|
+
property :role_type, predicate: RolesVocabulary.type
|
16
|
+
property :agent, predicate: RolesVocabulary.agent
|
17
|
+
property :scope, predicate: RolesVocabulary.scope
|
18
|
+
|
19
|
+
validates :agent, presence: true, cardinality: { is: 1 }
|
20
|
+
validates :role_type, inclusion: { in: Roles.type_map.keys }, cardinality: { is: 1 }
|
21
|
+
validates :scope, inclusion: { in: Roles::SCOPES }, cardinality: { is: 1 }
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Build a Role instance from hash attributes
|
26
|
+
# @param args [Hash] the attributes
|
27
|
+
# @return [Role] the role
|
28
|
+
# @example
|
29
|
+
# Role.build type: "Curator", agent: "bob", scope: "resource"
|
30
|
+
def build(args={})
|
31
|
+
new.tap do |role|
|
32
|
+
role.attributes = build_attributes(args)
|
33
|
+
if role.invalid?
|
34
|
+
raise "Invalid #{self.name}: #{role.errors.full_messages.join('; ')}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :deserialize, :build
|
40
|
+
|
41
|
+
# Deserialize a Role from JSON
|
42
|
+
# @param json [String] the JSON string
|
43
|
+
# @return [Role] the role
|
44
|
+
def from_json(json)
|
45
|
+
deserialize JSON.parse(json)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def build_attributes(args={})
|
51
|
+
# symbolize keys and stringify values
|
52
|
+
attrs = args.each_with_object({}) do |(k, v), memo|
|
53
|
+
memo[k.to_sym] = Array(v).first.to_s
|
54
|
+
end
|
55
|
+
# set default scope if necessary
|
56
|
+
attrs[:scope] ||= DEFAULT_SCOPE
|
57
|
+
# accept :type key for role_type attribute
|
58
|
+
if attrs.key?(:type)
|
59
|
+
attrs[:role_type] = attrs.delete(:type)
|
60
|
+
end
|
61
|
+
attrs
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Roles are considered equivalent (== and eql?) if they
|
67
|
+
# are of the same type and have the same agent and scope.
|
68
|
+
# @param other [Object] the object of comparison
|
69
|
+
# @return [Boolean] the result
|
70
|
+
def ==(other)
|
71
|
+
if self.class == other.class
|
72
|
+
self.to_h == other.to_h
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def eql?(other)
|
79
|
+
(self == other) && (hash == other.hash)
|
80
|
+
end
|
81
|
+
|
82
|
+
def hash
|
83
|
+
to_h.hash
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_s
|
87
|
+
to_h.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
def in_resource_scope?
|
91
|
+
scope.first == Roles::RESOURCE_SCOPE
|
92
|
+
end
|
93
|
+
|
94
|
+
def in_policy_scope?
|
95
|
+
scope.first == Roles::POLICY_SCOPE
|
96
|
+
end
|
97
|
+
|
98
|
+
def inspect
|
99
|
+
"#<#{self.class.name} role_type=#{role_type.first.inspect}, " \
|
100
|
+
"agent=#{agent.first.inspect}, scope=#{scope.first.inspect}>"
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_h
|
104
|
+
{ "role_type"=>role_type,
|
105
|
+
"agent"=>agent,
|
106
|
+
"scope"=>scope,
|
107
|
+
}
|
108
|
+
end
|
109
|
+
alias_method :to_hash, :to_h
|
110
|
+
alias_method :serialize, :to_h
|
111
|
+
|
112
|
+
# Returns the permissions associated with the role
|
113
|
+
# @return [Array<Symbol>] the permissions
|
114
|
+
def permissions
|
115
|
+
Roles.type_map[role_type.first].permissions
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module AccessRoles
|
4
|
+
#
|
5
|
+
# Wraps a set of Roles
|
6
|
+
#
|
7
|
+
# @abstract
|
8
|
+
#
|
9
|
+
class RoleSet
|
10
|
+
include Enumerable
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
attr_reader :role_set
|
14
|
+
|
15
|
+
def_delegators :query,
|
16
|
+
:where, :agent, :scope, :role_type, :type, :agents, :permissions,
|
17
|
+
:in_policy_scope, :in_resource_scope
|
18
|
+
|
19
|
+
def_delegators :role_set,
|
20
|
+
:empty?, :clear
|
21
|
+
|
22
|
+
def initialize(role_set)
|
23
|
+
@role_set = role_set
|
24
|
+
end
|
25
|
+
|
26
|
+
# Grants roles - i.e., adds them to the role set
|
27
|
+
# @example - default scope ("resource")
|
28
|
+
# grant type: "Curator", agent: "bob"
|
29
|
+
# @example - explicit scope
|
30
|
+
# grant type: "Curator", agent: "sue", scope: "policy"
|
31
|
+
# @param roles [Role, Hash, RoleSet, Array] the role(s) to grant
|
32
|
+
def grant(*roles)
|
33
|
+
raise NotImplementedError, "Subclasses must implement `grant`."
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return true/false depending on whether the role has been granted
|
37
|
+
# @param role [Role, Hash] the role
|
38
|
+
# @return [Boolean] whether the role has been granted
|
39
|
+
def granted?(role)
|
40
|
+
include? coerce(role)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Revokes roles - i.e., removes them from the role set
|
44
|
+
# @example
|
45
|
+
# revoke type: "Curator", agent: "bob", scope: "resource"
|
46
|
+
# @param roles [Role, Hash, RoleSet, Array] the role(s) to revoke
|
47
|
+
def revoke(*roles)
|
48
|
+
raise NotImplementedError, "Subclasses must implement `revoke`."
|
49
|
+
end
|
50
|
+
|
51
|
+
# Replace the current roles in the role set with new roles
|
52
|
+
# @param roles [Role, Hash, RoleSet, Array] the role(s) to grant
|
53
|
+
def replace(*roles)
|
54
|
+
revoke_all
|
55
|
+
grant(*roles)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Remove all roles from the role set
|
59
|
+
# @return [RoleSet] self
|
60
|
+
def revoke_all
|
61
|
+
raise NotImplementedError, "Subclasses must implement `revoke_all`."
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return the RoleSet serialized as JSON
|
65
|
+
# @return [String] the JSON string
|
66
|
+
def to_json
|
67
|
+
serialize.to_json
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return the RoleSet serialized as an Array of serialized Roles
|
71
|
+
# @return [Array<Hash>]
|
72
|
+
def serialize
|
73
|
+
to_a.map(&:serialize)
|
74
|
+
end
|
75
|
+
|
76
|
+
def ==(other)
|
77
|
+
if other.is_a? RoleSet
|
78
|
+
self.to_set == other.to_set
|
79
|
+
else
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def query
|
87
|
+
RoleSetQuery.new(self)
|
88
|
+
end
|
89
|
+
|
90
|
+
def coerce(obj)
|
91
|
+
case obj
|
92
|
+
when RoleSet
|
93
|
+
coerce(obj.role_set)
|
94
|
+
when Array, Set
|
95
|
+
obj.map { |r| coerce(r) }.flatten
|
96
|
+
when Role
|
97
|
+
obj
|
98
|
+
else
|
99
|
+
Role.build(obj)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
#
|
3
|
+
# RoleSet query interface
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
class RoleSetQuery
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_reader :role_set
|
11
|
+
|
12
|
+
def initialize(role_set)
|
13
|
+
@role_set = role_set
|
14
|
+
end
|
15
|
+
|
16
|
+
def criteria
|
17
|
+
@criteria ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def where(conditions={})
|
21
|
+
criteria.merge!(conditions)
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def scope(s)
|
26
|
+
where(scope: s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def in_policy_scope
|
30
|
+
scope(Roles::POLICY_SCOPE)
|
31
|
+
end
|
32
|
+
|
33
|
+
def in_resource_scope
|
34
|
+
scope(Roles::RESOURCE_SCOPE)
|
35
|
+
end
|
36
|
+
|
37
|
+
def agent(a)
|
38
|
+
where(agent: a)
|
39
|
+
end
|
40
|
+
alias_method :group, :agent
|
41
|
+
|
42
|
+
def role_type(r)
|
43
|
+
where(role_type: r)
|
44
|
+
end
|
45
|
+
alias_method :type, :role_type
|
46
|
+
|
47
|
+
def each(&block)
|
48
|
+
role_set.select { |role| matches_all?(role) }.each(&block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return the list of agents for the Roles matching the criteria.
|
52
|
+
# @return [Array] the agents
|
53
|
+
def agents
|
54
|
+
map { |role| role.agent.first }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return a list of the permissions granted to the Roles matching the criteria.
|
58
|
+
# @return [Array<Symbol>] the permissions
|
59
|
+
def permissions
|
60
|
+
map(&:permissions).flatten.uniq
|
61
|
+
end
|
62
|
+
|
63
|
+
def detach
|
64
|
+
DetachedRoleSet.new(self)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Return a list of the permissions granted to any of the agents in the given scope
|
70
|
+
def permissions_for_agents_in_scope(agents, scope)
|
71
|
+
agent(agents).scope(scope).permissions
|
72
|
+
end
|
73
|
+
|
74
|
+
def matches_all?(role)
|
75
|
+
criteria.all? { |key, value| matches_one?(role, key, value) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def matches_one?(role, key, value)
|
79
|
+
Array(value).include?(role.send(key).first)
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
class RoleType
|
3
|
+
|
4
|
+
attr_reader :title, :description, :permissions
|
5
|
+
alias_method :label, :title
|
6
|
+
|
7
|
+
def initialize(title, description, permissions)
|
8
|
+
@title = title.freeze
|
9
|
+
@description = description.freeze
|
10
|
+
@permissions = permissions.freeze
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
title
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
module RoleTypes
|
3
|
+
|
4
|
+
CURATOR = RoleType.new(
|
5
|
+
"Curator",
|
6
|
+
"The Curator role conveys responsibility for curating a resource " \
|
7
|
+
"and delegating responsibilities to other agents.",
|
8
|
+
Permissions::ALL
|
9
|
+
)
|
10
|
+
|
11
|
+
EDITOR = RoleType.new(
|
12
|
+
"Editor",
|
13
|
+
"The Editor role conveys reponsibility for managing the content, " \
|
14
|
+
"description and structural arrangement of a resource.",
|
15
|
+
[ Permissions::READ, Permissions::DOWNLOAD, Permissions::ADD_CHILDREN,
|
16
|
+
Permissions::UPDATE, Permissions::REPLACE, Permissions::ARRANGE ]
|
17
|
+
)
|
18
|
+
|
19
|
+
METADATA_EDITOR = RoleType.new(
|
20
|
+
"MetadataEditor",
|
21
|
+
"The Metadata Editor role conveys responsibility for " \
|
22
|
+
"managing the description of a resource.",
|
23
|
+
[ Permissions::READ, Permissions::DOWNLOAD, Permissions::UPDATE ]
|
24
|
+
)
|
25
|
+
|
26
|
+
CONTRIBUTOR = RoleType.new(
|
27
|
+
"Contributor",
|
28
|
+
"The Contributor role conveys responsibility for adding related " \
|
29
|
+
"resources to a resource, such as works to a collection.",
|
30
|
+
[ Permissions::READ, Permissions::ADD_CHILDREN ]
|
31
|
+
)
|
32
|
+
|
33
|
+
DOWNLOADER = RoleType.new(
|
34
|
+
"Downloader",
|
35
|
+
"The Downloader role conveys access to the \"master\" file " \
|
36
|
+
"(original content bitstream) of a resource.",
|
37
|
+
[ Permissions::READ, Permissions::DOWNLOAD ]
|
38
|
+
)
|
39
|
+
|
40
|
+
VIEWER = RoleType.new(
|
41
|
+
"Viewer",
|
42
|
+
"The Viewer role conveys access to the description and \"access\" " \
|
43
|
+
"files (e.g., derivative bitstreams) of a resource.",
|
44
|
+
[ Permissions::READ ]
|
45
|
+
)
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
module Roles
|
3
|
+
|
4
|
+
include RoleTypes
|
5
|
+
|
6
|
+
RESOURCE_SCOPE = "resource".freeze
|
7
|
+
POLICY_SCOPE = "policy".freeze
|
8
|
+
SCOPES = [RESOURCE_SCOPE, POLICY_SCOPE].freeze
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def type_map
|
12
|
+
@type_map ||= role_types.map { |role_type| [role_type.to_s, role_type] }.to_h
|
13
|
+
end
|
14
|
+
|
15
|
+
def role_types
|
16
|
+
@role_types ||= RoleTypes.constants(false).map { |const| RoleTypes.const_get(const) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module AccessRoles
|
2
|
+
class RolesVocabulary < RDF::StrictVocabulary("http://repository.lib.duke.edu/vocab/roles/")
|
3
|
+
|
4
|
+
term :Role,
|
5
|
+
label: "Role",
|
6
|
+
comment: "An assertion of a role granted to an agent."
|
7
|
+
|
8
|
+
property :hasRole,
|
9
|
+
label: "Has Role",
|
10
|
+
comment: "Asserts the granting of a role on the subject to an agent."
|
11
|
+
|
12
|
+
property :type,
|
13
|
+
label: "Type",
|
14
|
+
comment: "The type of role granted to the agent."
|
15
|
+
|
16
|
+
property :agent,
|
17
|
+
label: "Agent",
|
18
|
+
comment: "The agent to whom the role is granted."
|
19
|
+
|
20
|
+
property :scope,
|
21
|
+
label: "Scope",
|
22
|
+
comment: "The scope within which the role applies."
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: access_roles
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Chandek-Stark
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hashie
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: active-triples
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.6.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hydra-validations
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-its
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: factory_girl
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Access role management library for role-based access control, based on
|
126
|
+
RDF and ActiveTriples.
|
127
|
+
email:
|
128
|
+
- dchandekstark@gmail.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rspec"
|
135
|
+
- ".travis.yml"
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- access_roles.gemspec
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- lib/access_roles.rb
|
144
|
+
- lib/access_roles/detached_role_set.rb
|
145
|
+
- lib/access_roles/permissions.rb
|
146
|
+
- lib/access_roles/property_role_set.rb
|
147
|
+
- lib/access_roles/role.rb
|
148
|
+
- lib/access_roles/role_set.rb
|
149
|
+
- lib/access_roles/role_set_query.rb
|
150
|
+
- lib/access_roles/role_type.rb
|
151
|
+
- lib/access_roles/role_types.rb
|
152
|
+
- lib/access_roles/roles.rb
|
153
|
+
- lib/access_roles/roles_vocabulary.rb
|
154
|
+
- lib/access_roles/version.rb
|
155
|
+
homepage: https://github.com/duke-libraries/access_roles
|
156
|
+
licenses: []
|
157
|
+
metadata: {}
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
requirements: []
|
173
|
+
rubyforge_project:
|
174
|
+
rubygems_version: 2.4.6
|
175
|
+
signing_key:
|
176
|
+
specification_version: 4
|
177
|
+
summary: Access role management library for role-based access control.
|
178
|
+
test_files: []
|