isomorfeus-policy 1.0.0.zeta25 → 2.0.0.rc4
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/LICENSE +21 -21
- data/README.md +181 -182
- data/lib/isomorfeus/policy/config.rb +36 -36
- data/lib/isomorfeus/policy/version.rb +5 -5
- data/lib/isomorfeus-policy.rb +22 -21
- data/lib/isomorfeus_policy/anonymous.rb +11 -11
- data/lib/isomorfeus_policy/lucid_authorization/base.rb +5 -5
- data/lib/isomorfeus_policy/lucid_authorization/mixin.rb +42 -42
- data/lib/isomorfeus_policy/lucid_policy/base.rb +10 -11
- data/lib/isomorfeus_policy/lucid_policy/exception.rb +4 -4
- data/lib/isomorfeus_policy/lucid_policy/helper.rb +18 -18
- data/lib/isomorfeus_policy/lucid_policy/mixin.rb +191 -195
- data/lib/lucid_props.rb +95 -95
- metadata +31 -31
@@ -1,42 +1,42 @@
|
|
1
|
-
module LucidAuthorization
|
2
|
-
module Mixin
|
3
|
-
def record_authorization_reason
|
4
|
-
@_isomorfeus_record_authorization_reason = true
|
5
|
-
end
|
6
|
-
|
7
|
-
def stop_to_record_authorization_reason
|
8
|
-
@_isomorfeus_record_authorization_reason = false
|
9
|
-
@_isomorfeus_authorization_reason = nil
|
10
|
-
end
|
11
|
-
|
12
|
-
def authorization_reason
|
13
|
-
@_isomorfeus_authorization_reason
|
14
|
-
end
|
15
|
-
|
16
|
-
def authorized?(target_class, target_method = nil, props = nil)
|
17
|
-
begin
|
18
|
-
class_name = self.class.name
|
19
|
-
class_name = class_name.split('>::').last if class_name.start_with?('#<')
|
20
|
-
policy_class = Isomorfeus.cached_policy_class("#{class_name}Policy")
|
21
|
-
rescue ::NameError
|
22
|
-
policy_class = nil
|
23
|
-
end
|
24
|
-
return false unless policy_class
|
25
|
-
policy_instance = policy_class.new(self, @_isomorfeus_record_authorization_reason)
|
26
|
-
result = policy_instance.authorized?(target_class, target_method, props)
|
27
|
-
@_isomorfeus_authorization_reason = policy_instance.reason
|
28
|
-
result
|
29
|
-
end
|
30
|
-
|
31
|
-
def authorized!(target_class, target_method = nil, props = nil)
|
32
|
-
class_name = self.class.name
|
33
|
-
class_name = class_name.split('>::').last if class_name.start_with?('#<')
|
34
|
-
policy_class = Isomorfeus.cached_policy_class("#{class_name}Policy")
|
35
|
-
Isomorfeus.raise_error(error_class: LucidPolicy::Exception, message: "#{self}: policy class #{class_name}Policy not found!") unless policy_class
|
36
|
-
policy_instance = policy_class.new(self, @_isomorfeus_record_authorization_reason)
|
37
|
-
result = policy_instance.authorized!(target_class, target_method, props)
|
38
|
-
@_isomorfeus_authorization_reason = policy_instance.reason
|
39
|
-
result
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
1
|
+
module LucidAuthorization
|
2
|
+
module Mixin
|
3
|
+
def record_authorization_reason
|
4
|
+
@_isomorfeus_record_authorization_reason = true
|
5
|
+
end
|
6
|
+
|
7
|
+
def stop_to_record_authorization_reason
|
8
|
+
@_isomorfeus_record_authorization_reason = false
|
9
|
+
@_isomorfeus_authorization_reason = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorization_reason
|
13
|
+
@_isomorfeus_authorization_reason
|
14
|
+
end
|
15
|
+
|
16
|
+
def authorized?(target_class, target_method = nil, props = nil)
|
17
|
+
begin
|
18
|
+
class_name = self.class.name
|
19
|
+
class_name = class_name.split('>::').last if class_name.start_with?('#<')
|
20
|
+
policy_class = Isomorfeus.cached_policy_class("#{class_name}Policy")
|
21
|
+
rescue ::NameError
|
22
|
+
policy_class = nil
|
23
|
+
end
|
24
|
+
return false unless policy_class
|
25
|
+
policy_instance = policy_class.new(self, @_isomorfeus_record_authorization_reason)
|
26
|
+
result = policy_instance.authorized?(target_class, target_method, props)
|
27
|
+
@_isomorfeus_authorization_reason = policy_instance.reason
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def authorized!(target_class, target_method = nil, props = nil)
|
32
|
+
class_name = self.class.name
|
33
|
+
class_name = class_name.split('>::').last if class_name.start_with?('#<')
|
34
|
+
policy_class = Isomorfeus.cached_policy_class("#{class_name}Policy")
|
35
|
+
Isomorfeus.raise_error(error_class: LucidPolicy::Exception, message: "#{self}: policy class #{class_name}Policy not found!") unless policy_class
|
36
|
+
policy_instance = policy_class.new(self, @_isomorfeus_record_authorization_reason)
|
37
|
+
result = policy_instance.authorized!(target_class, target_method, props)
|
38
|
+
@_isomorfeus_authorization_reason = policy_instance.reason
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
module LucidPolicy
|
2
|
-
class Base
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
1
|
+
module LucidPolicy
|
2
|
+
class Base
|
3
|
+
def self.inherited(base)
|
4
|
+
base.include LucidPolicy::Mixin
|
5
|
+
if RUBY_ENGINE != 'opal'
|
6
|
+
Isomorfeus.add_valid_policy_class(base)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module LucidPolicy
|
2
|
-
class Exception < ::Exception
|
3
|
-
end
|
4
|
-
end
|
1
|
+
module LucidPolicy
|
2
|
+
class Exception < ::Exception
|
3
|
+
end
|
4
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
module LucidPolicy
|
2
|
-
class Helper < BasicObject
|
3
|
-
attr_reader :result
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@result = :deny
|
7
|
-
end
|
8
|
-
|
9
|
-
def allow
|
10
|
-
@result = :allow
|
11
|
-
nil
|
12
|
-
end
|
13
|
-
|
14
|
-
def deny
|
15
|
-
nil
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
module LucidPolicy
|
2
|
+
class Helper < BasicObject
|
3
|
+
attr_reader :result
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@result = :deny
|
7
|
+
end
|
8
|
+
|
9
|
+
def allow
|
10
|
+
@result = :allow
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def deny
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,195 +1,191 @@
|
|
1
|
-
module LucidPolicy
|
2
|
-
module Mixin
|
3
|
-
def self.included(base)
|
4
|
-
base.instance_exec do
|
5
|
-
if RUBY_ENGINE != 'opal'
|
6
|
-
Isomorfeus.add_valid_policy_class(base) unless base == LucidPolicy::Base
|
7
|
-
end
|
8
|
-
|
9
|
-
def authorization_rules
|
10
|
-
@authorization_rules ||= { rules: {}.dup, policies: {}.dup, others: :deny }.dup
|
11
|
-
end
|
12
|
-
|
13
|
-
def all
|
14
|
-
:others
|
15
|
-
end
|
16
|
-
|
17
|
-
def allow(*classes_and_methods_and_options)
|
18
|
-
_allow_or_deny(:allow, *classes_and_methods_and_options)
|
19
|
-
end
|
20
|
-
|
21
|
-
def deny(*classes_and_methods_and_options)
|
22
|
-
_allow_or_deny(:deny, *classes_and_methods_and_options)
|
23
|
-
end
|
24
|
-
|
25
|
-
def others
|
26
|
-
:others
|
27
|
-
end
|
28
|
-
|
29
|
-
def rule(*classes_and_methods, &block)
|
30
|
-
_allow_or_deny(:rule, *classes_and_methods, &block)
|
31
|
-
end
|
32
|
-
|
33
|
-
def combine_with(policy_class, **options)
|
34
|
-
authorization_rules[:policies] = { policy_class => options }
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
rules[:rules][target_class][:
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@
|
90
|
-
@
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
rule
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
r
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
r
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
1
|
+
module LucidPolicy
|
2
|
+
module Mixin
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_exec do
|
5
|
+
if RUBY_ENGINE != 'opal'
|
6
|
+
Isomorfeus.add_valid_policy_class(base) unless base == LucidPolicy::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
def authorization_rules
|
10
|
+
@authorization_rules ||= { rules: {}.dup, policies: {}.dup, others: :deny }.dup
|
11
|
+
end
|
12
|
+
|
13
|
+
def all
|
14
|
+
:others
|
15
|
+
end
|
16
|
+
|
17
|
+
def allow(*classes_and_methods_and_options)
|
18
|
+
_allow_or_deny(:allow, *classes_and_methods_and_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def deny(*classes_and_methods_and_options)
|
22
|
+
_allow_or_deny(:deny, *classes_and_methods_and_options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def others
|
26
|
+
:others
|
27
|
+
end
|
28
|
+
|
29
|
+
def rule(*classes_and_methods, &block)
|
30
|
+
_allow_or_deny(:rule, *classes_and_methods, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def combine_with(policy_class, **options)
|
34
|
+
authorization_rules[:policies] = { policy_class => options }
|
35
|
+
end
|
36
|
+
|
37
|
+
def _allow_or_deny(thing, *classes_methods_options, &block)
|
38
|
+
rules = authorization_rules
|
39
|
+
|
40
|
+
if %i[allow deny].include?(thing) && classes_methods_options.first == :others
|
41
|
+
rules[:others] = thing
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
target_classes = []
|
46
|
+
target_methods = []
|
47
|
+
target_options = {}
|
48
|
+
|
49
|
+
classes_methods_options.each do |class_method_option|
|
50
|
+
if class_method_option.class == Hash
|
51
|
+
target_options = class_method_option
|
52
|
+
else
|
53
|
+
class_or_method_s = class_method_option.to_s
|
54
|
+
if class_method_option.class == Symbol && class_or_method_s[0].downcase == class_or_method_s[0]
|
55
|
+
target_methods << class_method_option
|
56
|
+
else
|
57
|
+
class_method_option = class_or_method_s unless class_method_option.class == String
|
58
|
+
target_classes << class_method_option
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
thing_or_block = block_given? ? block : thing
|
64
|
+
|
65
|
+
target_classes.each do |target_class|
|
66
|
+
target_class = target_class.split('>::').last if target_class.start_with?('#<')
|
67
|
+
rules[:rules][target_class] = {} unless rules[:rules].key?(target_class)
|
68
|
+
|
69
|
+
if target_methods.empty?
|
70
|
+
rules[:rules][target_class][:rule] = thing_or_block
|
71
|
+
rules[:rules][target_class][:options] = target_options unless target_options.empty?
|
72
|
+
else
|
73
|
+
rules[:rules][target_class][:rule] = :deny unless rules[:rules][target_class].key?(:rule)
|
74
|
+
rules[:rules][target_class][:methods] = {} unless rules[:rules][target_class].key?(:methods)
|
75
|
+
target_methods.each do |target_method|
|
76
|
+
rules[:rules][target_class][:methods][target_method] = { rule: thing_or_block }
|
77
|
+
rules[:rules][target_class][:methods][target_method][:options] = target_options unless target_options.empty?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
attr_reader :reason
|
85
|
+
|
86
|
+
def initialize(object, record_reason = nil)
|
87
|
+
@object = object
|
88
|
+
@reason = nil
|
89
|
+
@record_reason = record_reason
|
90
|
+
if @record_reason
|
91
|
+
@class_name = self.class.name
|
92
|
+
@class_name = @class_name.split('>::').last if @class_name.start_with?('#<')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def authorized?(target_class, target_method = nil, props = nil)
|
97
|
+
Isomorfeus.raise_error(error_class: LucidPolicy::Exception, message: "#{self}: At least the class or class name must be given!") unless target_class
|
98
|
+
|
99
|
+
target_class = target_class.to_s unless target_class.class == String
|
100
|
+
target_class = target_class.split('>::').last if target_class.start_with?('#<')
|
101
|
+
|
102
|
+
rules = self.class.authorization_rules
|
103
|
+
|
104
|
+
result = if rules[:rules].key?(target_class)
|
105
|
+
if target_method && rules[:rules][target_class].key?(:methods) && rules[:rules][target_class][:methods].key?(target_method)
|
106
|
+
options = rules[:rules][target_class][:methods][target_method][:options]
|
107
|
+
rule = rules[:rules][target_class][:methods][target_method][:rule]
|
108
|
+
@reason = { policy_class: @class_name, class_name: target_class, method: target_method, rule: rule } if @record_reason
|
109
|
+
else
|
110
|
+
options = rules[:rules][target_class][:options]
|
111
|
+
rule = rules[:rules][target_class][:rule]
|
112
|
+
@reason = { policy_class: @class_name, class_name: target_class, rule: rule } if @record_reason
|
113
|
+
end
|
114
|
+
|
115
|
+
if rule.class == Symbol || rule.class == String
|
116
|
+
if options
|
117
|
+
condition, method_result = _get_condition_and_result(options)
|
118
|
+
if @record_reason
|
119
|
+
@reason[:condition] = condition
|
120
|
+
@reason[:condition_result] = method_result
|
121
|
+
end
|
122
|
+
rule if (condition == :if && method_result == true) || (condition == :if_not && method_result == false)
|
123
|
+
else
|
124
|
+
rule
|
125
|
+
end
|
126
|
+
else
|
127
|
+
props = LucidProps.new(props) unless props.class == LucidProps
|
128
|
+
policy_helper = LucidPolicy::Helper.new
|
129
|
+
policy_helper.instance_exec(@object, target_class, target_method, props, &rule)
|
130
|
+
r = policy_helper.result
|
131
|
+
@reason[:rule_result] = r if @record_reason
|
132
|
+
r
|
133
|
+
end
|
134
|
+
else
|
135
|
+
r = rules[:others]
|
136
|
+
@reason = { policy_class: @class_name, class_name: target_class, others: r } if @record_reason
|
137
|
+
r
|
138
|
+
end
|
139
|
+
|
140
|
+
return true if result == :allow
|
141
|
+
|
142
|
+
rules[:policies].each do |policy_class, options|
|
143
|
+
combined_policy_result = nil
|
144
|
+
if options.empty?
|
145
|
+
policy_instance = policy_class.new(@object, @record_reason)
|
146
|
+
combined_policy_result = policy_instance.authorized?(target_class, target_method, props)
|
147
|
+
@reason = @reason = { policy_class: @class_name, combined: policy_instance.reason } if @record_reason
|
148
|
+
else
|
149
|
+
condition, method_result = _get_condition_and_result(options)
|
150
|
+
if (condition == :if && method_result == true) || (condition == :if_not && method_result == false)
|
151
|
+
policy_instance = policy_class.new(@object, @record_reason)
|
152
|
+
combined_policy_result = policy_instance.authorized?(target_class, target_method, props)
|
153
|
+
@reason = { policy_class: @class_name, combined: policy_instance.reason, condition: condition, condition_result: method_result } if @record_reason
|
154
|
+
end
|
155
|
+
end
|
156
|
+
return true if combined_policy_result == true
|
157
|
+
end
|
158
|
+
|
159
|
+
result == :allow ? true : false
|
160
|
+
end
|
161
|
+
|
162
|
+
def authorized!(target_class, target_method = nil, props = nil)
|
163
|
+
result = authorized?(target_class, target_method, props)
|
164
|
+
reason_message = reason ? ", reason: #{reason}" : ''
|
165
|
+
return true if result
|
166
|
+
Isomorfeus.raise_error(error_class: LucidPolicy::Exception, message: "#{@object}: not authorized to call #{target_class}#{}#{target_method} #{props} #{reason_message}!")
|
167
|
+
end
|
168
|
+
|
169
|
+
def _get_condition_and_result(options)
|
170
|
+
condition = nil
|
171
|
+
method_name_or_block = if options.key?(:if)
|
172
|
+
condition = :if
|
173
|
+
options[:if]
|
174
|
+
elsif options.key?(:if_not)
|
175
|
+
condition = :if_not
|
176
|
+
options[:if_not]
|
177
|
+
elsif options.key?(:unless)
|
178
|
+
condition = :if_not
|
179
|
+
options[:unless]
|
180
|
+
end
|
181
|
+
method_result = if method_name_or_block && method_name_or_block.class == Symbol
|
182
|
+
@object.__send__(method_name_or_block)
|
183
|
+
else
|
184
|
+
props = LucidProps.new(props) unless props.class == LucidProps
|
185
|
+
method_name_or_block.call(@object, props)
|
186
|
+
end
|
187
|
+
[condition, method_result]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|