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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +15 -0
  3. data/.travis.yml +8 -0
  4. data/README.md +6 -0
  5. data/db/migrations/{1_create_permits.rb → 1_create_grants.rb} +1 -1
  6. data/docs/index.rst +6 -1
  7. data/lib/checkpoint/agent.rb +32 -31
  8. data/lib/checkpoint/agent/resolver.rb +45 -15
  9. data/lib/checkpoint/agent/token.rb +8 -3
  10. data/lib/checkpoint/authority.rb +126 -14
  11. data/lib/checkpoint/credential.rb +21 -8
  12. data/lib/checkpoint/credential/permission.rb +6 -5
  13. data/lib/checkpoint/credential/resolver.rb +63 -62
  14. data/lib/checkpoint/credential/role.rb +2 -3
  15. data/lib/checkpoint/credential/role_map_resolver.rb +65 -0
  16. data/lib/checkpoint/credential/token.rb +7 -2
  17. data/lib/checkpoint/db.rb +8 -1
  18. data/lib/checkpoint/db/cartesian_select.rb +71 -0
  19. data/lib/checkpoint/db/{permit.rb → grant.rb} +4 -4
  20. data/lib/checkpoint/db/params.rb +36 -0
  21. data/lib/checkpoint/db/query/ac.rb +47 -0
  22. data/lib/checkpoint/db/query/acr.rb +54 -0
  23. data/lib/checkpoint/db/query/ar.rb +47 -0
  24. data/lib/checkpoint/db/query/cr.rb +47 -0
  25. data/lib/checkpoint/grants.rb +116 -0
  26. data/lib/checkpoint/query/role_granted.rb +1 -1
  27. data/lib/checkpoint/resource.rb +16 -19
  28. data/lib/checkpoint/resource/all_of_any_type.rb +0 -8
  29. data/lib/checkpoint/resource/all_of_type.rb +0 -22
  30. data/lib/checkpoint/resource/resolver.rb +34 -11
  31. data/lib/checkpoint/resource/token.rb +7 -2
  32. data/lib/checkpoint/version.rb +1 -1
  33. metadata +12 -7
  34. data/docs/authentication.rst +0 -18
  35. data/lib/checkpoint/permission_mapper.rb +0 -29
  36. 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 takes a concrete object (like a model instance) and
6
- # resolves it into all {Resource}s for which a grant would allow an action.
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 resolves to three agents: one for the entity
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
- # Resolve an application entity into a set of Resources for which a grant
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 converted to a Resource with {Resource::from} and
39
- # {Resource::AllOfType::from}. That is, the Resolver does a
40
- # straightforward expansion, not applying any of its own conversion
41
- # semantics. The special {Resource::all} resource is also included to
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 resolve(target)
65
- [Resource.from(target), Resource::AllOfType.from(target), Resource.all]
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 {Permit} can be granted for a Token. Concrete
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 permits.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Checkpoint
4
- VERSION = "1.0.3"
4
+ VERSION = "1.1.0"
5
5
  end
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.3
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-07-19 00:00:00.000000000 Z
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/1_create_permits.rb
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/permit.rb
241
- - lib/checkpoint/permission_mapper.rb
242
- - lib/checkpoint/permits.rb
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
@@ -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
@@ -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