checkpoint 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +15 -0
- data/.travis.yml +8 -0
- data/README.md +6 -0
- data/db/migrations/{1_create_permits.rb → 1_create_grants.rb} +1 -1
- data/docs/index.rst +6 -1
- data/lib/checkpoint/agent.rb +32 -31
- data/lib/checkpoint/agent/resolver.rb +45 -15
- data/lib/checkpoint/agent/token.rb +8 -3
- data/lib/checkpoint/authority.rb +126 -14
- data/lib/checkpoint/credential.rb +21 -8
- data/lib/checkpoint/credential/permission.rb +6 -5
- data/lib/checkpoint/credential/resolver.rb +63 -62
- data/lib/checkpoint/credential/role.rb +2 -3
- data/lib/checkpoint/credential/role_map_resolver.rb +65 -0
- data/lib/checkpoint/credential/token.rb +7 -2
- data/lib/checkpoint/db.rb +8 -1
- data/lib/checkpoint/db/cartesian_select.rb +71 -0
- data/lib/checkpoint/db/{permit.rb → grant.rb} +4 -4
- data/lib/checkpoint/db/params.rb +36 -0
- data/lib/checkpoint/db/query/ac.rb +47 -0
- data/lib/checkpoint/db/query/acr.rb +54 -0
- data/lib/checkpoint/db/query/ar.rb +47 -0
- data/lib/checkpoint/db/query/cr.rb +47 -0
- data/lib/checkpoint/grants.rb +116 -0
- data/lib/checkpoint/query/role_granted.rb +1 -1
- data/lib/checkpoint/resource.rb +16 -19
- data/lib/checkpoint/resource/all_of_any_type.rb +0 -8
- data/lib/checkpoint/resource/all_of_type.rb +0 -22
- data/lib/checkpoint/resource/resolver.rb +34 -11
- data/lib/checkpoint/resource/token.rb +7 -2
- data/lib/checkpoint/version.rb +1 -1
- metadata +12 -7
- data/docs/authentication.rst +0 -18
- data/lib/checkpoint/permission_mapper.rb +0 -29
- data/lib/checkpoint/permits.rb +0 -133
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a736e9a0fc810c9323dcd7612aee0cb27af02521c59ef448c62c4e5dac3e15c
|
4
|
+
data.tar.gz: b4ab5365b4cae8e5f0040af209bea2c6b9da1e1e19f856d2ae088081188df1b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9f4e9ddda32c366b2402333cf8e43f52da41ad4c7d5ec5a77b66ec524d43c9a9ed521f533e28a27c5c8a96a5382f08a3212db1b4ebe38c12d8b6ea3042b9151
|
7
|
+
data.tar.gz: ec1130f73c436b07751d09b7a7f74e9975da9ac2d6fdd29908878150e5053e9e15f9ba8916861b82a784aa8dafc28f0aee2bc1a7fb99046f68868a6f5dc1873d
|
data/.rubocop.yml
CHANGED
@@ -15,6 +15,9 @@ AllCops:
|
|
15
15
|
- 'bin/**/*'
|
16
16
|
- 'vendor/**/*'
|
17
17
|
|
18
|
+
Layout/EmptyLineAfterGuardClause:
|
19
|
+
Enabled: false
|
20
|
+
|
18
21
|
Layout/MultilineMethodDefinitionBraceLayout:
|
19
22
|
EnforcedStyle: same_line
|
20
23
|
|
@@ -26,5 +29,17 @@ Metrics/BlockLength:
|
|
26
29
|
- '*.gemspec'
|
27
30
|
ExcludedMethods: ['describe', 'context', 'xdescribe', 'xcontext']
|
28
31
|
|
32
|
+
Layout/SpaceInsideBlockBraces:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Layout/IndentArray:
|
36
|
+
EnforcedStyle: consistent
|
37
|
+
|
38
|
+
Style/ClassAndModuleChildren:
|
39
|
+
Enabled: false
|
40
|
+
|
29
41
|
Style/StringLiterals:
|
30
42
|
Enabled: false
|
43
|
+
|
44
|
+
Style/SymbolArray:
|
45
|
+
EnforcedStyle: brackets
|
data/.travis.yml
CHANGED
@@ -3,3 +3,11 @@ language: ruby
|
|
3
3
|
rvm:
|
4
4
|
- 2.4.2
|
5
5
|
before_install: gem install bundler -v 1.16.0
|
6
|
+
before_script:
|
7
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
8
|
+
- chmod +x ./cc-test-reporter
|
9
|
+
- ./cc-test-reporter before-build
|
10
|
+
script:
|
11
|
+
- bin/rspec
|
12
|
+
after_script:
|
13
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
[![Build Status](https://travis-ci.org/mlibrary/checkpoint.svg?branch=master)](https://travis-ci.org/mlibrary/checkpoint?branch=master)
|
2
2
|
[![Coverage Status](https://coveralls.io/repos/github/mlibrary/checkpoint/badge.svg?branch=master)](https://coveralls.io/github/mlibrary/checkpoint?branch=master)
|
3
|
+
[![Documentation Status](https://readthedocs.org/projects/checkpoint/badge/?version=latest)](https://checkpoint.readthedocs.io/en/latest/?badge=latest)
|
3
4
|
|
4
5
|
# Checkpoint
|
5
6
|
|
@@ -18,6 +19,11 @@ And then execute:
|
|
18
19
|
|
19
20
|
$ bundle
|
20
21
|
|
22
|
+
## Documentation
|
23
|
+
|
24
|
+
User documentation source is available in the `docs` directory, and in rendered format
|
25
|
+
on [readthedocs](https://checkpoint.readthedocs.io/en/latest/).
|
26
|
+
|
21
27
|
## License
|
22
28
|
|
23
29
|
Checkpoint is licensed under the BSD-3-Clause license. See [LICENSE.md](LICENSE.md).
|
data/docs/index.rst
CHANGED
@@ -17,12 +17,17 @@ where enterprise, legacy, and new systems must all interoperate.
|
|
17
17
|
Checkpoint emphasizes the use of policies and object-oriented design, giving
|
18
18
|
examples from very simple rules through complex group- and role-based scenarios.
|
19
19
|
|
20
|
+
Checkpoint does not handle authentication at all. See Keycard_ for a library
|
21
|
+
that does so and provides identity attributes that can be used as the basis for
|
22
|
+
grants and policies.
|
23
|
+
|
24
|
+
|
20
25
|
Table of Contents
|
21
26
|
-----------------
|
22
27
|
|
23
28
|
.. toctree::
|
24
29
|
:maxdepth: 2
|
25
30
|
|
26
|
-
authentication
|
27
31
|
policies
|
28
32
|
|
33
|
+
.. _Keycard: https://github.com/mlibrary/keycard
|
data/lib/checkpoint/agent.rb
CHANGED
@@ -5,43 +5,46 @@ require 'checkpoint/agent/token'
|
|
5
5
|
|
6
6
|
module Checkpoint
|
7
7
|
# An Agent is an any person or entity that might be granted various
|
8
|
-
#
|
8
|
+
# credentials, such as a user, group, or institution.
|
9
9
|
#
|
10
10
|
# The application objects that an agent represents may be of any type; this
|
11
11
|
# is more of an interface or role than a base class. The important concept is
|
12
|
-
# that
|
12
|
+
# that credentials are granted to agents, and that agents may be representative
|
13
13
|
# of multiple concrete actors, such as any person affiliated with a given
|
14
14
|
# institution or any member of a given group.
|
15
|
+
#
|
16
|
+
# In an application, agents will typically be created by the
|
17
|
+
# {Agent::Resolver} registered with an {Checkpoint::Authority}. This keeps
|
18
|
+
# most of the application code decoupled from the Agent type, allowing the
|
19
|
+
# binding to happen in an isolated component. It will also generally not be
|
20
|
+
# required to subclass Agent, since it delegates to the concrete actor in
|
21
|
+
# flexible, well-defined ways, detailed on the individual methods here.
|
15
22
|
class Agent
|
16
23
|
attr_accessor :actor
|
17
24
|
|
18
|
-
# Create an Agent
|
25
|
+
# Create an Agent, wrapping a concrete actor.
|
26
|
+
#
|
27
|
+
# When retrieving the ID or type, we will delegate to the the actor at that
|
28
|
+
# time. See the {#id} and {#type} methods for exact semantics.
|
19
29
|
def initialize(actor)
|
20
30
|
@actor = actor
|
21
31
|
end
|
22
32
|
|
23
|
-
#
|
33
|
+
# Convert this object to an Agent.
|
24
34
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
def self.from(actor)
|
33
|
-
if actor.respond_to?(:to_agent)
|
34
|
-
actor.to_agent
|
35
|
-
else
|
36
|
-
new(actor)
|
37
|
-
end
|
35
|
+
# For Checkpoint-supplied Agents, this is an identity operation,
|
36
|
+
# but it allows consistent handling of the built-in types and
|
37
|
+
# application-supplied types that will either implement this interface or
|
38
|
+
# convert themselves to a built-in type. This removes the requirement to
|
39
|
+
# extend Checkpoint types or bind to a specific conversion method.
|
40
|
+
def to_agent
|
41
|
+
self
|
38
42
|
end
|
39
43
|
|
40
|
-
# Get the
|
44
|
+
# Get the wrapped actor's type.
|
41
45
|
#
|
42
|
-
# If the
|
43
|
-
#
|
44
|
-
# will use that. Otherwise, we use the actors's class name.
|
46
|
+
# If the actor implements `#agent_type`, we will return that. Otherwise,
|
47
|
+
# we use the actors's class name.
|
45
48
|
#
|
46
49
|
# @return [String] the name of the actor's type after calling `#to_s` on it.
|
47
50
|
def type
|
@@ -52,14 +55,13 @@ module Checkpoint
|
|
52
55
|
end.to_s
|
53
56
|
end
|
54
57
|
|
55
|
-
# Get the
|
58
|
+
# Get the wrapped actor's ID.
|
56
59
|
#
|
57
|
-
# If the
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# implement any of these methods, we raise a {NoIdentifierError}.
|
60
|
+
# If the actor implements `#agent_id`, we will call it and return that
|
61
|
+
# value. Otherwise, we call `#id`. If the the actor does not implement
|
62
|
+
# either of these methods, we raise a {NoIdentifierError}.
|
61
63
|
#
|
62
|
-
# @return [String] the
|
64
|
+
# @return [String] the actor's ID after calling `#to_s` on it.
|
63
65
|
def id
|
64
66
|
if actor.respond_to?(:agent_id)
|
65
67
|
actor.agent_id
|
@@ -82,12 +84,11 @@ module Checkpoint
|
|
82
84
|
other.is_a?(Agent) && actor.eql?(other.actor)
|
83
85
|
end
|
84
86
|
|
85
|
-
# Check whether two Agents refer to the same concrete actor.
|
87
|
+
# Check whether two Agents refer to the same concrete actor by type and id.
|
86
88
|
# @param other [Agent] Another Agent to compare with
|
87
|
-
# @return [Boolean] true when the other Agent's
|
88
|
-
# determined by comparing them with `==`.
|
89
|
+
# @return [Boolean] true when the other Agent's type and id are equal.
|
89
90
|
def ==(other)
|
90
|
-
other.is_a?(Agent) &&
|
91
|
+
other.is_a?(Agent) && type == other.type && id == other.id
|
91
92
|
end
|
92
93
|
end
|
93
94
|
end
|
@@ -2,16 +2,24 @@
|
|
2
2
|
|
3
3
|
module Checkpoint
|
4
4
|
class Agent
|
5
|
-
# An Agent Resolver
|
6
|
-
#
|
7
|
-
# effect of allowing a Permit to any of those agents to take effect when
|
8
|
-
# authorizing an action by this user.
|
5
|
+
# An Agent Resolver is the bridge between a concrete user (or other
|
6
|
+
# account/actor) and {Agent}s that the user represents.
|
9
7
|
#
|
10
|
-
#
|
11
|
-
# conversion.
|
8
|
+
# There are two basic operations:
|
12
9
|
#
|
13
|
-
#
|
14
|
-
#
|
10
|
+
# - Conversion maps an actor to a single Agent
|
11
|
+
# - Expansion maps an actor to all of the Agents it represents
|
12
|
+
#
|
13
|
+
# These allow credentials to be granted, matched, or revoked with the
|
14
|
+
# appropriate semantics, depending on the operation. In general, a Grant
|
15
|
+
# is given to or revoked from a single Agent, while matching is applied
|
16
|
+
# to all Agents the actor represents.
|
17
|
+
#
|
18
|
+
# This implementation does not implement any expansion semantics other
|
19
|
+
# than to convert the actor into an Agent and return it as a list.
|
20
|
+
#
|
21
|
+
# To extend the set of {Agent}s resolved, implement a subclass
|
22
|
+
# that returns an array of agents from #expand. This customized
|
15
23
|
# implementation would typically be injected to an application-wide
|
16
24
|
# {Checkpoint::Authority}, rather than being used directly.
|
17
25
|
#
|
@@ -19,14 +27,36 @@ module Checkpoint
|
|
19
27
|
# the user is a member of, or IP address-based geographical regions or
|
20
28
|
# organizational affiliations.
|
21
29
|
class Resolver
|
22
|
-
#
|
30
|
+
# Expand an actor to a list of Agents it represents.
|
31
|
+
#
|
32
|
+
# This implementation simply converts the actor and wraps the resulting
|
33
|
+
# Agent in an array.
|
34
|
+
#
|
35
|
+
# If extending or overriding, you will likely want to call super or
|
36
|
+
# {#convert} on the concrete actor to make sure that the most specific
|
37
|
+
# Agent is included. It is acceptable to return subclasses of Agent,
|
38
|
+
# though that is generally unnecessary because of its design of
|
39
|
+
# delegating to actor methods.
|
40
|
+
#
|
41
|
+
# @return [Agent] an array of agents for this actor
|
42
|
+
def expand(actor)
|
43
|
+
[convert(actor)]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Default conversion from an actor to an {Agent}.
|
47
|
+
#
|
48
|
+
# If the actor implements #to_agent, we will delegate to it. Otherwise,
|
49
|
+
# we will instantiate an {Agent} with the supplied actor.
|
50
|
+
#
|
51
|
+
# Override this method to use a different or conditional Agent type.
|
23
52
|
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
53
|
+
# @return [Agent] the actor converted to an agent
|
54
|
+
def convert(actor)
|
55
|
+
if actor.respond_to?(:to_agent)
|
56
|
+
actor.to_agent
|
57
|
+
else
|
58
|
+
Agent.new(actor)
|
59
|
+
end
|
30
60
|
end
|
31
61
|
end
|
32
62
|
end
|
@@ -3,9 +3,9 @@
|
|
3
3
|
module Checkpoint
|
4
4
|
class Agent
|
5
5
|
# An Agent::Token is an identifier object for an Agent. It
|
6
|
-
# includes a type and an identifier. A {
|
6
|
+
# includes a type and an identifier. A {Grant} can be created for a Token.
|
7
7
|
# Concrete actors are resolved into a number of agents, and those agents'
|
8
|
-
# tokens will be checked for matching
|
8
|
+
# tokens will be checked for matching grants.
|
9
9
|
class Token
|
10
10
|
attr_reader :type, :id
|
11
11
|
|
@@ -34,7 +34,7 @@ module Checkpoint
|
|
34
34
|
self
|
35
35
|
end
|
36
36
|
|
37
|
-
# @return [String] a token string suitable for granting or matching
|
37
|
+
# @return [String] a token string suitable for granting or matching grants for this agent
|
38
38
|
def to_s
|
39
39
|
"#{type}:#{id}"
|
40
40
|
end
|
@@ -45,6 +45,11 @@ module Checkpoint
|
|
45
45
|
other.is_a?(Token) && type == other.type && id == other.id
|
46
46
|
end
|
47
47
|
|
48
|
+
# @return [Integer] hash code based on to_s
|
49
|
+
def hash
|
50
|
+
to_s.hash
|
51
|
+
end
|
52
|
+
|
48
53
|
alias == eql?
|
49
54
|
alias inspect uri
|
50
55
|
end
|
data/lib/checkpoint/authority.rb
CHANGED
@@ -3,36 +3,52 @@
|
|
3
3
|
require 'checkpoint/agent/resolver'
|
4
4
|
require 'checkpoint/credential/resolver'
|
5
5
|
require 'checkpoint/resource/resolver'
|
6
|
-
require 'checkpoint/
|
6
|
+
require 'checkpoint/grants'
|
7
7
|
|
8
8
|
module Checkpoint
|
9
9
|
# An Authority is the central point of contact for authorization questions in
|
10
|
-
# Checkpoint. It checks whether there are
|
10
|
+
# Checkpoint. It checks whether there are grants that would allow a given
|
11
11
|
# action to be taken.
|
12
12
|
class Authority
|
13
13
|
def initialize(
|
14
14
|
agent_resolver: Agent::Resolver.new,
|
15
15
|
credential_resolver: Credential::Resolver.new,
|
16
16
|
resource_resolver: Resource::Resolver.new,
|
17
|
-
|
17
|
+
grants: Grants.new)
|
18
18
|
|
19
19
|
@agent_resolver = agent_resolver
|
20
20
|
@credential_resolver = credential_resolver
|
21
21
|
@resource_resolver = resource_resolver
|
22
|
-
@
|
22
|
+
@grants = grants
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
# Check whether there are any matching grants that would allow this actor
|
26
|
+
# to take the action on the target entity.
|
27
|
+
#
|
28
|
+
# The parameters are generally intended to be the most convenient forms for
|
29
|
+
# the application. For example, user and resource model objects would be
|
30
|
+
# typical in a Rails application, for the actor and entity, respectively.
|
31
|
+
# Using a symbol for a named action is typical.
|
32
|
+
#
|
33
|
+
# Each of these will be converted and expanded by the corresponding
|
34
|
+
# resolver to sets of {Agent}s, {Credential}s, and {Resource}s. In the case
|
35
|
+
# where you already have an Agent, Credential, or Resource, it can be
|
36
|
+
# passed; the expectation is that those types have an identity conversion.
|
37
|
+
#
|
38
|
+
# @param actor [Object|Agent] The person/account taking the action.
|
39
|
+
# @param action [Symbol|String|Credential] The action to authorize or
|
40
|
+
# Credential to check for.
|
41
|
+
# @param entity [Object|Resource] The entity/resource to be acted upon.
|
42
|
+
def permits?(actor, action, entity)
|
26
43
|
# Conceptually equivalent to:
|
27
|
-
# can?(
|
28
|
-
# can?(current_user, 'edit', @listing)
|
44
|
+
# can?(current_user, :edit, @listing)
|
29
45
|
|
30
46
|
# user => agent tokens
|
31
47
|
# action => credential tokens
|
32
48
|
# target => resource tokens
|
33
49
|
|
34
|
-
#
|
35
|
-
# SELECT * FROM
|
50
|
+
# Grant.where(agent: agents, credential: credentials, resource: resources)
|
51
|
+
# SELECT * FROM grants
|
36
52
|
# WHERE agent IN('user:gkostin', 'account-type:umich', 'affiliation:lib-staff')
|
37
53
|
# AND credential IN('permission:edit', 'role:editor')
|
38
54
|
# AND resource IN('listing:17', 'type:listing')
|
@@ -46,13 +62,109 @@ module Checkpoint
|
|
46
62
|
# ^^^ ^^^^ ^^^^
|
47
63
|
# if current_user has at least one row in each of of these columns,
|
48
64
|
# they have been "granted permission"
|
49
|
-
|
50
|
-
agent_resolver.
|
51
|
-
credential_resolver.
|
52
|
-
resource_resolver.
|
65
|
+
grants.for(
|
66
|
+
agent_resolver.expand(actor),
|
67
|
+
credential_resolver.expand(action),
|
68
|
+
resource_resolver.expand(entity)
|
53
69
|
).any?
|
54
70
|
end
|
55
71
|
|
72
|
+
# Find agents who have grants to take an action on an entity.
|
73
|
+
#
|
74
|
+
# The action and entity are expanded for matching more general grants.
|
75
|
+
#
|
76
|
+
# @return [Array<Agent::Token>] The distinct set of tokens for agents permitted to
|
77
|
+
# take the given action on the given entity
|
78
|
+
def who(action, entity)
|
79
|
+
credentials = credential_resolver.expand(action)
|
80
|
+
resources = resource_resolver.expand(entity)
|
81
|
+
|
82
|
+
grants.who(credentials, resources).map do |grant|
|
83
|
+
Agent::Token.new(grant.agent_type, grant.agent_id)
|
84
|
+
end.uniq
|
85
|
+
end
|
86
|
+
|
87
|
+
# Find credentials granted to an actor on an entity.
|
88
|
+
#
|
89
|
+
# The actor and entity are expanded for matching more general grants.
|
90
|
+
#
|
91
|
+
# @return [Array<Credential::Token>] The distinct set of tokens for credentials
|
92
|
+
# that the actor is granted on the entity
|
93
|
+
def what(actor, entity)
|
94
|
+
agents = agent_resolver.expand(actor)
|
95
|
+
resources = resource_resolver.expand(entity)
|
96
|
+
|
97
|
+
grants.what(agents, resources).map do |grant|
|
98
|
+
Credential::Token.new(grant.credential_type, grant.credential_id)
|
99
|
+
end.uniq
|
100
|
+
end
|
101
|
+
|
102
|
+
# Find resources on which the actor is permitted to take the given action.
|
103
|
+
#
|
104
|
+
# The actor and action are expanded for matching more general grants.
|
105
|
+
#
|
106
|
+
# @return [Array<Resource::Token>] The distinct set of tokens for resources
|
107
|
+
# on which the actor is permitted to take the given action
|
108
|
+
def which(actor, action)
|
109
|
+
agents = agent_resolver.expand(actor)
|
110
|
+
credentials = credential_resolver.expand(action)
|
111
|
+
|
112
|
+
grants.which(agents, credentials).map do |grant|
|
113
|
+
Resource::Token.new(grant.resource_type, grant.resource_id)
|
114
|
+
end.uniq
|
115
|
+
end
|
116
|
+
|
117
|
+
# Grant a single credential to a specific actor on an entity.
|
118
|
+
#
|
119
|
+
# The parameters are converted to Agent, Credential, and Resource types,
|
120
|
+
# but not expanded. This allows very specific grants to be made. The
|
121
|
+
# default conversion of a symbol or string as the action is to a
|
122
|
+
# {Credential::Permission} of the same name.
|
123
|
+
#
|
124
|
+
# If you want to use more general grants (for example, for an account type
|
125
|
+
# rather than for a given user), you should pass a more general Agent or an
|
126
|
+
# object that will be converted to one. Another example would be using a
|
127
|
+
# wildcard Resource as the entity to grant the credential for all objects
|
128
|
+
# of some given type.
|
129
|
+
#
|
130
|
+
# @param actor [Object|Agent] The actor to whom the grant should be made.
|
131
|
+
# @param action [Symbol|String|Credential] The action or Credential to grant.
|
132
|
+
# @param entity [Object|Resource] The entity or Resource to which the
|
133
|
+
# grant will apply.
|
134
|
+
# @return [Boolean] True if the grant was made; false if it failed.
|
135
|
+
def grant!(actor, action, entity)
|
136
|
+
grant = grants.grant!(
|
137
|
+
agent_resolver.convert(actor),
|
138
|
+
credential_resolver.convert(action),
|
139
|
+
resource_resolver.convert(entity)
|
140
|
+
)
|
141
|
+
|
142
|
+
!grant.nil?
|
143
|
+
end
|
144
|
+
|
145
|
+
# Revoke a credential from a specific actor on an entity.
|
146
|
+
#
|
147
|
+
# Like {#permit!}, the parameters are converted to Agent, Credential, and
|
148
|
+
# Resource types, but not expanded. This means that specific grants can be
|
149
|
+
# revoked without revoking more general ones. For example, if a user was
|
150
|
+
# granted read permission on an object, and then granted the same credential
|
151
|
+
# on all objects of that type, the more specific grant could be revoked
|
152
|
+
# individually.
|
153
|
+
#
|
154
|
+
# @param actor [Object|Agent] The actor from whom the grant should be revoked.
|
155
|
+
# @param action [Symbol|String|Credential] The action or Credential to revoke.
|
156
|
+
# @param entity [Object|Resource] The entity or Resource upon which the
|
157
|
+
# @return [Boolean] True if any grants were revoked; false if none were revoked.
|
158
|
+
def revoke!(actor, action, entity)
|
159
|
+
revoked = grants.revoke!(
|
160
|
+
agent_resolver.convert(actor),
|
161
|
+
credential_resolver.convert(action),
|
162
|
+
resource_resolver.convert(entity)
|
163
|
+
)
|
164
|
+
|
165
|
+
revoked.positive?
|
166
|
+
end
|
167
|
+
|
56
168
|
# Dummy authority that rejects everything
|
57
169
|
class RejectAll
|
58
170
|
def permits?(*)
|
@@ -62,6 +174,6 @@ module Checkpoint
|
|
62
174
|
|
63
175
|
private
|
64
176
|
|
65
|
-
attr_reader :agent_resolver, :credential_resolver, :resource_resolver, :
|
177
|
+
attr_reader :agent_resolver, :credential_resolver, :resource_resolver, :grants
|
66
178
|
end
|
67
179
|
end
|