checkpoint 1.0.3 → 1.1.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/.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
@@ -2,13 +2,20 @@
|
|
2
2
|
|
3
3
|
module Checkpoint
|
4
4
|
class Resource
|
5
|
-
# A Resource Resolver
|
6
|
-
#
|
5
|
+
# A Resource Resolver is the bridge between concrete entity objects (like
|
6
|
+
# model instances) and {Resource}s that the represent them.
|
7
|
+
#
|
8
|
+
# There are two basic operations:
|
9
|
+
#
|
10
|
+
# - Conversion maps an entity to a single Resource.
|
11
|
+
# - Expansion maps an entity to all Resources for which a grant would allow
|
12
|
+
# an action.
|
13
|
+
#
|
7
14
|
# For example, this can be used to grant a credential on all items of a given
|
8
15
|
# model class or to implement cascading permissions when all credentials for
|
9
16
|
# a container should apply to the contained objects.
|
10
17
|
#
|
11
|
-
# This base implementation
|
18
|
+
# This base implementation expands to three resources: one for the entity
|
12
19
|
# itself, one for all entities of its type, and one for all entities of any
|
13
20
|
# type. This provides a convenient and familiar construct, where a broader
|
14
21
|
# grant (say, at the type level, or for "everything") implies a grant at
|
@@ -32,14 +39,14 @@ module Checkpoint
|
|
32
39
|
# there is even more complexity, Checkpoint allows its fundamental
|
33
40
|
# semantics to be extended by implementing a custom resolver.
|
34
41
|
class Resolver
|
35
|
-
#
|
42
|
+
# Expand an application entity into a set of Resources for which a grant
|
36
43
|
# would allow access.
|
37
44
|
#
|
38
|
-
# The entity will be
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# support zone-wide grants
|
45
|
+
# The entity will be expanded to three Resources:
|
46
|
+
#
|
47
|
+
# 1. A Resource for the specific entity, by conversion
|
48
|
+
# 2. A {Resource::AllOfType} for the type of the entity, as by conversion
|
49
|
+
# 3. A special {Resource::AllOfAnyType} to support zone-wide grants
|
43
50
|
#
|
44
51
|
# As an example, permission to download high quality versions of media
|
45
52
|
# assets might be granted to a given user system wide (that is, for the
|
@@ -61,8 +68,24 @@ module Checkpoint
|
|
61
68
|
# this approach may be more convenient than, for example, delegating to a
|
62
69
|
# specific policy in the same way from multiple sections of the
|
63
70
|
# application.
|
64
|
-
def
|
65
|
-
[
|
71
|
+
def expand(entity)
|
72
|
+
[convert(entity), convert(entity).all_of_type, Resource.all]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Default conversion from an entity to a {Resource}.
|
76
|
+
#
|
77
|
+
# If the entity implements #to_resource, we will delegate to it. Otherwise,
|
78
|
+
# we will instantiate a {Resource} with the supplied entity.
|
79
|
+
#
|
80
|
+
# Override this method to use a different or conditional Resource type.
|
81
|
+
#
|
82
|
+
# @return [Resource] the entity converted to a resource
|
83
|
+
def convert(entity)
|
84
|
+
if entity.respond_to?(:to_resource)
|
85
|
+
entity.to_resource
|
86
|
+
else
|
87
|
+
Resource.new(entity)
|
88
|
+
end
|
66
89
|
end
|
67
90
|
end
|
68
91
|
end
|
@@ -5,9 +5,9 @@ require 'checkpoint/resource/resolver'
|
|
5
5
|
module Checkpoint
|
6
6
|
class Resource
|
7
7
|
# A Resource::Token is an identifier object for a Resource. It includes a
|
8
|
-
# type and an identifier. A {
|
8
|
+
# type and an identifier. A {Grant} can be created for a Token. Concrete
|
9
9
|
# entities are resolved into a number of resources, and those resources'
|
10
|
-
# tokens will be checked for matching
|
10
|
+
# tokens will be checked for matching grants.
|
11
11
|
class Token
|
12
12
|
attr_reader :type, :id
|
13
13
|
|
@@ -58,6 +58,11 @@ module Checkpoint
|
|
58
58
|
other.is_a?(Resource::Token) && type == other.type && id == other.id
|
59
59
|
end
|
60
60
|
|
61
|
+
# @return [Integer] hash code based on to_s
|
62
|
+
def hash
|
63
|
+
to_s.hash
|
64
|
+
end
|
65
|
+
|
61
66
|
alias == eql?
|
62
67
|
alias inspect uri
|
63
68
|
end
|
data/lib/checkpoint/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: checkpoint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Botimer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ettin
|
@@ -217,11 +217,10 @@ files:
|
|
217
217
|
- bin/yard
|
218
218
|
- bin/yardoc
|
219
219
|
- checkpoint.gemspec
|
220
|
-
- db/migrations/
|
220
|
+
- db/migrations/1_create_grants.rb
|
221
221
|
- docs/Makefile
|
222
222
|
- docs/_static/.gitkeep
|
223
223
|
- docs/_templates/.gitkeep
|
224
|
-
- docs/authentication.rst
|
225
224
|
- docs/conf.py
|
226
225
|
- docs/index.rst
|
227
226
|
- docs/policies.rst
|
@@ -235,11 +234,17 @@ files:
|
|
235
234
|
- lib/checkpoint/credential/permission.rb
|
236
235
|
- lib/checkpoint/credential/resolver.rb
|
237
236
|
- lib/checkpoint/credential/role.rb
|
237
|
+
- lib/checkpoint/credential/role_map_resolver.rb
|
238
238
|
- lib/checkpoint/credential/token.rb
|
239
239
|
- lib/checkpoint/db.rb
|
240
|
-
- lib/checkpoint/db/
|
241
|
-
- lib/checkpoint/
|
242
|
-
- lib/checkpoint/
|
240
|
+
- lib/checkpoint/db/cartesian_select.rb
|
241
|
+
- lib/checkpoint/db/grant.rb
|
242
|
+
- lib/checkpoint/db/params.rb
|
243
|
+
- lib/checkpoint/db/query/ac.rb
|
244
|
+
- lib/checkpoint/db/query/acr.rb
|
245
|
+
- lib/checkpoint/db/query/ar.rb
|
246
|
+
- lib/checkpoint/db/query/cr.rb
|
247
|
+
- lib/checkpoint/grants.rb
|
243
248
|
- lib/checkpoint/query.rb
|
244
249
|
- lib/checkpoint/query/action_permitted.rb
|
245
250
|
- lib/checkpoint/query/role_granted.rb
|
data/docs/authentication.rst
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
Identity and Authentication
|
2
|
-
===========================
|
3
|
-
|
4
|
-
Users can be identified in any number of ways and carry with them various
|
5
|
-
attributes that determine the entirety of "who they are". Our typical needs
|
6
|
-
include identifying a person by username or email address, and building a
|
7
|
-
profile of attributes such as geographical region (as determined by IP address),
|
8
|
-
or University status (student, staff, etc.). The identifiers and attributes are
|
9
|
-
intrinsic to the user and do not, by themselves, grant any permissions within
|
10
|
-
an application. Likewise, these attributes cannot be granted within an
|
11
|
-
application, only inspected.
|
12
|
-
|
13
|
-
A&E will continue to provide the identity and attributes of users. The
|
14
|
-
specifics of whether this will be implemented with environment variables,
|
15
|
-
HTTP headers, SAML, or other means is to be determined. An application is
|
16
|
-
not expected to implement its own login process except to the degree that
|
17
|
-
it can recognize the required authentication information provided to it.
|
18
|
-
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Checkpoint
|
4
|
-
# A PermissionMapper translates an action into a set of permissions and roles
|
5
|
-
# that would allow it. Commonly, the actions and permissions will share names
|
6
|
-
# for convenience and consistency, but this is not a requirement.
|
7
|
-
#
|
8
|
-
# For example, it may make sense in an application that one permission
|
9
|
-
# implies another, so an action may have multiple permissions that would
|
10
|
-
# allow it. In another application, it may be more convenient and
|
11
|
-
# understandable for users to have separate roles encapsulate that concept
|
12
|
-
# (such as an editor role having all of the permissions of a reader role and
|
13
|
-
# more).
|
14
|
-
#
|
15
|
-
# As a separate example, it may be more appropriate to implement permission
|
16
|
-
# inheritance directly in policy code (as by delegating to another check or
|
17
|
-
# policy), relying on the matching action and permission names with no roles
|
18
|
-
# resolved, as given by the default PermissionMapper. Checkpoint does not
|
19
|
-
# take an absolute position on the best pattern for a given application.
|
20
|
-
class PermissionMapper
|
21
|
-
def permissions_for(action)
|
22
|
-
[action.to_sym]
|
23
|
-
end
|
24
|
-
|
25
|
-
def roles_granting(_action)
|
26
|
-
[]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/checkpoint/permits.rb
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Note: we do not require db/permit because Sequel requires the connection
|
4
|
-
# to be set up before defining the model classes. The arrangment here
|
5
|
-
# assumes that DB.initialize! will have been called if the default model
|
6
|
-
# is to be used. In tests, that is done by spec/sequel_helper.rb. In an
|
7
|
-
# application, there should be an initializer that reads whatever appropriate
|
8
|
-
# configuration and does the initialization.
|
9
|
-
|
10
|
-
require 'checkpoint/db'
|
11
|
-
|
12
|
-
module Checkpoint
|
13
|
-
# The repository of permits -- a simple wrapper for the Sequel Datastore / permits table.
|
14
|
-
class Permits
|
15
|
-
def initialize(permits: Checkpoint::DB::Permit)
|
16
|
-
@permits = permits
|
17
|
-
end
|
18
|
-
|
19
|
-
def for(agents, credentials, resources)
|
20
|
-
where(agents, credentials, resources).select
|
21
|
-
end
|
22
|
-
|
23
|
-
def any?(agents, credentials, resources)
|
24
|
-
where(agents, credentials, resources).first != nil
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def where(agents, credentials, resources)
|
30
|
-
Query.new(agents, credentials, resources, scope: permits)
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_reader :permits
|
34
|
-
|
35
|
-
# A query object based on agents, credentials, and resources.
|
36
|
-
#
|
37
|
-
# This is a helper to capture a set of agents, credentials, and resources,
|
38
|
-
# and manage assembly of placeholder variables and binding expressions in
|
39
|
-
# the way Sequel expects them. It can take single items or arrays and
|
40
|
-
# converts them all to their tokens for query purposes.
|
41
|
-
class Query
|
42
|
-
attr_reader :agents, :credentials, :resources, :scope
|
43
|
-
|
44
|
-
def initialize(agents, credentials, resources, scope: Checkpoint::DB::Permit)
|
45
|
-
@agents = tokenize(agents)
|
46
|
-
@credentials = tokenize(credentials)
|
47
|
-
@resources = tokenize(resources)
|
48
|
-
@scope = scope
|
49
|
-
end
|
50
|
-
|
51
|
-
def query
|
52
|
-
scope.where(conditions)
|
53
|
-
end
|
54
|
-
|
55
|
-
def select
|
56
|
-
exec(:select)
|
57
|
-
end
|
58
|
-
|
59
|
-
def first
|
60
|
-
exec(:first)
|
61
|
-
end
|
62
|
-
|
63
|
-
def conditions
|
64
|
-
{
|
65
|
-
agent_token: agent_params.placeholders,
|
66
|
-
credential_token: credential_params.placeholders,
|
67
|
-
resource_token: resource_params.placeholders,
|
68
|
-
zone_id: :$zone_id
|
69
|
-
}
|
70
|
-
end
|
71
|
-
|
72
|
-
def parameters
|
73
|
-
(agent_params.values +
|
74
|
-
credential_params.values +
|
75
|
-
resource_params.values +
|
76
|
-
[[:zone_id, DB::Permit.default_zone]]).to_h
|
77
|
-
end
|
78
|
-
|
79
|
-
def agent_params
|
80
|
-
Params.new(agents, 'at')
|
81
|
-
end
|
82
|
-
|
83
|
-
def credential_params
|
84
|
-
Params.new(credentials, 'ct')
|
85
|
-
end
|
86
|
-
|
87
|
-
def resource_params
|
88
|
-
Params.new(resources, 'rt')
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
def exec(mode)
|
94
|
-
query.call(mode, parameters)
|
95
|
-
end
|
96
|
-
|
97
|
-
def tokenize(collection)
|
98
|
-
[collection].flatten.map(&:token)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# A helper for building placeholder variable names from items in a list and
|
103
|
-
# providing a corresponding hash of values. A prefix with some mnemonic
|
104
|
-
# corresponding to the column is recommended. For example, if the column is
|
105
|
-
# `agent_token`, using the prefix `at` will yield `$at_0`, `$at_1`, etc. for
|
106
|
-
# an IN clause.
|
107
|
-
class Params
|
108
|
-
attr_reader :items, :prefix
|
109
|
-
|
110
|
-
def initialize(items, prefix)
|
111
|
-
@items = [items].flatten
|
112
|
-
@prefix = prefix
|
113
|
-
end
|
114
|
-
|
115
|
-
def placeholders
|
116
|
-
0.upto(items.size - 1).map do |i|
|
117
|
-
:"$#{prefix}_#{i}"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def values
|
122
|
-
items.map.with_index do |item, i|
|
123
|
-
value = if item.respond_to?(:sql_value)
|
124
|
-
item.sql_value
|
125
|
-
else
|
126
|
-
item.to_s
|
127
|
-
end
|
128
|
-
[:"#{prefix}_#{i}", value]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|