ingress 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edbb4efc674725b3fcb18ed2651773ecab7af973940f185cb93a94251858a4da
4
- data.tar.gz: aadc4a71a1946a19227b1b1a09d37372d056d19020c721a55a1c6cb63a251d20
3
+ metadata.gz: 3e36e293b713b0e3f9d61c612149d5436dae4ffaa64182965d1287712fcb4608
4
+ data.tar.gz: 2f04d772ae27844e77ed9d84e9a9213e9a112e58b4cf6636a627c2a04f9b9349
5
5
  SHA512:
6
- metadata.gz: a63048555be635ef620c670e5f3fe39db3bc56bce272734141e391834b82cf42f3f8bce5e4ab9f7f752cc71b9b76e50307aa2d163bec8c901f5be9ad2fcacbdb
7
- data.tar.gz: 555623681279ba944737bbbb77e2b7b5fd65b365dcd840b83581fdb04527839203669977b1d602fe94e720f91fb7e0ab120c889883109a1a89a65490ac357410
6
+ metadata.gz: 610c7363ed6ce0ec1b0b6a5f7c134631582ca76e269dcf97109d11964cf7e6f919bfff03948bef55b4d11a667d85b1df9b54811c65a80a7359cd2a836cae624e
7
+ data.tar.gz: 30234c3a466e62ecc4d50b76d38528add8195faf5a1bf722912d86bc34ab5efe2ad17f5af4a7c9ff303bf658ed7ec12bfd0ba67fb32c00ac76bbba89fae948f2
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ tags
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.3
1
+ 2.7.2
data/README.md CHANGED
@@ -283,6 +283,66 @@ So now the authorization in your system can be defined in a much more OO way, wi
283
283
 
284
284
  This framework has no hooks into Rails (these would be trivial to write if necessary, e.g. you can instantiate the `user_permissions` object on your `ApplicationController` and then do the `can?` checks anywhere you want) and can therefore be used with any web framework, or even outside of the context of a web framework (if such a use case makes sense).
285
285
 
286
+ ### Conditional Lambda
287
+
288
+ Ingress by default does not know about the subject that is given in the conditional lambda. The given subject can be a Class or an Object and it depends on the user to define the correct lambda to handle the given subject.
289
+
290
+ For example, given the following `UserPermissions`:
291
+
292
+ ```
293
+ class UserPermissions < Ingress::Permissions
294
+ define_role_permissions do
295
+ can :read, Post, if: ->(user, given_subject) do
296
+ case [user, given_subject]
297
+ in [_, Post]
298
+ user.id == given_subject.user_id
299
+ in [_, Class]
300
+ true
301
+ else
302
+ false
303
+ end
304
+ end
305
+ end
306
+ ```
307
+
308
+ This is the result of the defined permissions:
309
+
310
+ ```
311
+ user_permissions = UserPermissions.new(user)
312
+ user_permissions.can?(:read, Post) # returns true
313
+ post = user.posts.first # assume we can get the list of posts form the user object
314
+ user_permissions.can?(:read, post) # returns true
315
+ ```
316
+
317
+ Ingress provides 2 convenient interfaces to apply conditional lambda on a Class or an Instance:
318
+
319
+ * if_subject_is_an_instance
320
+ * if_subject_is_a_class
321
+
322
+ These conditional lambdas always take 3 parameters: the `user`, the `subject` (this is either a Class or an Instance), and the `options` (this is additional attributes that may be needed to do the check).
323
+
324
+ They can be chained together like following:
325
+
326
+ ```
327
+ class UserPermissions < Ingress::Permissions
328
+ define_role_permissions do
329
+ can :read, Post,
330
+ if: ->(user, _post) { !user.id.nil? },
331
+ if_subject_is_an_instance: ->(user, post, _options) { user.id == post.user_id },
332
+ if_subject_is_a_class: ->(_user, klass, _options) { klass == Post }
333
+ end
334
+ end
335
+ ```
336
+
337
+ This is the result of the defined permissions:
338
+
339
+ ```
340
+ user_permissions = UserPermissions.new(user)
341
+ user_permissions.can?(:read, Post) # returns true
342
+ post = user.posts.first # assume we can get the list of posts form the user object
343
+ user_permissions.can?(:read, post) # returns true
344
+ ```
345
+
286
346
  ## Development
287
347
 
288
348
  After checking out the repo, run `script/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `script/console` for an interactive prompt that will allow you to experiment.
data/ingress.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_development_dependency "bundler", ">= 1.10", "< 3"
26
- spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "bundler", ">= 2.2", "< 3"
26
+ spec.add_development_dependency "rake", ">= 13.0.3"
27
27
  spec.add_development_dependency "rspec"
28
28
  end
@@ -6,7 +6,7 @@ module Ingress
6
6
  @allows = allows
7
7
  @action = action
8
8
  @subject = subject
9
- @conditions = [conditions].compact.flatten
9
+ @conditions = conditions
10
10
  end
11
11
 
12
12
  def allows?
@@ -16,7 +16,6 @@ module Ingress
16
16
  def match?(given_action, given_subject, user, options = {})
17
17
  return false unless action_matches?(given_action)
18
18
  return false unless subject_matches?(given_subject)
19
- return true if ignore_conditions?(given_subject)
20
19
 
21
20
  conditions_match?(user, given_subject, options)
22
21
  end
@@ -36,14 +35,6 @@ module Ingress
36
35
  "*" == subject
37
36
  end
38
37
 
39
- def ignore_conditions?(given_subject)
40
- subject_class?(given_subject) && subject_class?(@subject)
41
- end
42
-
43
- def subject_class?(subject)
44
- [Class, Module].include? subject.class
45
- end
46
-
47
38
  def conditions_match?(user, given_subject, options)
48
39
  conditions.all? do |condition|
49
40
  if condition.arity == 2
@@ -15,15 +15,17 @@ module Ingress
15
15
 
16
16
  def can(actions, subjects, options = {}, &block)
17
17
  for_each_action_and_subject(actions, subjects) do |action, subject|
18
- condition = condition_from_options(options, block)
19
- permission_repository.add_permission(role_identifier, true, action, subject, condition)
18
+ conditions = conditions_from(options, block)
19
+
20
+ permission_repository.add_permission(role_identifier, true, action, subject, conditions)
20
21
  end
21
22
  end
22
23
 
23
24
  def cannot(actions, subjects, options = {}, &block)
24
25
  for_each_action_and_subject(actions, subjects) do |action, subject|
25
- condition = condition_from_options(options, block)
26
- permission_repository.add_permission(role_identifier, false, action, subject, condition)
26
+ conditions = conditions_from(options, block)
27
+
28
+ permission_repository.add_permission(role_identifier, false, action, subject, conditions)
27
29
  end
28
30
  end
29
31
 
@@ -41,9 +43,40 @@ module Ingress
41
43
  end
42
44
  end
43
45
 
44
- def condition_from_options(options, block)
45
- if_condition = options[:if] || block
46
- if_condition.respond_to?(:call) ? if_condition : nil
46
+ def conditions_from(options, block)
47
+ generic_condition = generic_condition_from(options[:if] || block)
48
+ instance_condition = if_subject_is_an_instance_condition_from(options[:if_subject_is_an_instance])
49
+ class_condition = if_subject_is_a_class_condition_from(options[:if_subject_is_a_class])
50
+
51
+ [generic_condition, instance_condition, class_condition].compact
52
+ end
53
+
54
+ def generic_condition_from(callback)
55
+ callback if callback&.respond_to?(:call)
56
+ end
57
+
58
+ def if_subject_is_an_instance_condition_from(callback)
59
+ if callback&.respond_to?(:call)
60
+ lambda do |user, given_subject, option|
61
+ if [Class, Module].include?(given_subject.class)
62
+ true
63
+ else
64
+ callback.call(user, given_subject, option)
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ def if_subject_is_a_class_condition_from(callback)
71
+ if callback&.respond_to?(:call)
72
+ lambda do |user, given_subject, option|
73
+ if [Class, Module].include?(given_subject.class)
74
+ callback.call(user, given_subject, option)
75
+ else
76
+ true
77
+ end
78
+ end
79
+ end
47
80
  end
48
81
  end
49
82
  end
@@ -1,3 +1,3 @@
1
1
  module Ingress
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ingress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alan Skorkin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-16 00:00:00.000000000 Z
11
+ date: 2021-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '2.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '3'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '1.10'
29
+ version: '2.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '3'
@@ -34,16 +34,16 @@ dependencies:
34
34
  name: rake
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '10.0'
39
+ version: 13.0.3
40
40
  type: :development
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
44
+ - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '10.0'
46
+ version: 13.0.3
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 3.0.3
108
+ rubygems_version: 3.1.4
109
109
  signing_key:
110
110
  specification_version: 4
111
111
  summary: Simple role based authorization for Ruby applications