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
@@ -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
|