you_shall_not_pass 0.0.1 → 0.0.2
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/lib/you_shall_not_pass.rb +1 -1
- data/lib/you_shall_not_pass/authorizator.rb +22 -53
- data/lib/you_shall_not_pass/version.rb +1 -1
- data/spec/you_shall_not_pass/authorizator_spec.rb +294 -2
- data/you_shall_not_pass.gemspec +3 -0
- metadata +30 -3
- data/lib/you_shall_not_pass/callable.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aebfe45a21e352593dba3c1d5cc1baae6e1f9b66
|
4
|
+
data.tar.gz: 8c6f55da43443b50d645136e4350013195c32e32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36fa32a3062e4b639f3e0c753335b4258e14d7c08e60ab00b26d824da38b40d00916ce6a2cd080a81ddcc94bf99cb619c51ae0a3b07bcb6e6253382103390b74
|
7
|
+
data.tar.gz: c90158efd3dd6010b86fb9177f3093f2f7d5865b8aff219bc121a1815a5bd3f4db0b1b4487f217354835f1e5ba361f2f119121f14fa2bb996b64a8cf58efd61a
|
data/lib/you_shall_not_pass.rb
CHANGED
@@ -1,39 +1,31 @@
|
|
1
|
-
require "
|
1
|
+
require "callable"
|
2
|
+
require "fattr"
|
3
|
+
|
2
4
|
module YouShallNotPass
|
3
5
|
class Authorizator
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(user)
|
9
|
-
@user = user
|
6
|
+
def initialize(**attrs)
|
7
|
+
attrs.each do |attr, value|
|
8
|
+
send attr, value
|
9
|
+
end
|
10
10
|
end
|
11
|
-
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
Callable(policy).call(**options)
|
11
|
+
|
12
|
+
def can?(permission, **args)
|
13
|
+
Array(policies.fetch(permission)).all? do |policy|
|
14
|
+
Callable(policy).call(**args) == true
|
16
15
|
end
|
17
|
-
|
18
|
-
if
|
19
|
-
|
16
|
+
rescue KeyError => e
|
17
|
+
if permission =~ /_and_/
|
18
|
+
permission.to_s.split("_and_").all? { |policy| can?(policy.to_sym, **args)}
|
19
|
+
elsif permission =~ /_or_/
|
20
|
+
permission.to_s.split("_or_").any? { |policy| can?(policy.to_sym, **args)}
|
20
21
|
else
|
21
|
-
|
22
|
+
raise e
|
22
23
|
end
|
23
|
-
end
|
24
|
-
alias :can? :can_all?
|
25
24
|
|
26
|
-
|
27
|
-
available_policies = Array(policies[action.to_sym])
|
28
|
-
can = available_policies.any? && available_policies.any? do |policy|
|
29
|
-
Callable(policy).call(**options)
|
30
|
-
end
|
25
|
+
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
else
|
35
|
-
can
|
36
|
-
end
|
27
|
+
def perform_for(permission, **args)
|
28
|
+
yield if can?(permission, **args)
|
37
29
|
end
|
38
30
|
|
39
31
|
def policies
|
@@ -44,31 +36,8 @@ module YouShallNotPass
|
|
44
36
|
|
45
37
|
private
|
46
38
|
|
47
|
-
def
|
48
|
-
|
49
|
-
entries = Dir.new(policies_dir).entries
|
50
|
-
policy_files = entries.grep(/_policy.rb/)
|
51
|
-
.map { |p|
|
52
|
-
p["_policy.rb"] = ""
|
53
|
-
policy_class = "#{p.camelize}Policy".constantize
|
54
|
-
[p.to_sym, policy_class.new(self)]
|
55
|
-
}.to_h
|
56
|
-
else
|
57
|
-
Hash.new
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.set_policies_dir(dir)
|
62
|
-
@policies_dir = dir
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.policies_dir
|
66
|
-
@policies_dir
|
67
|
-
end
|
68
|
-
|
69
|
-
def policies_dir
|
70
|
-
self.class.policies_dir
|
39
|
+
def self.attribute(attr)
|
40
|
+
fattr attr
|
71
41
|
end
|
72
42
|
end
|
73
|
-
|
74
43
|
end
|
@@ -2,7 +2,299 @@ require "spec_helper"
|
|
2
2
|
require "you_shall_not_pass/authorizator"
|
3
3
|
|
4
4
|
scope YouShallNotPass::Authorizator do
|
5
|
-
|
6
|
-
|
5
|
+
scope "#can?" do
|
6
|
+
scope "no policies" do
|
7
|
+
spec "no policies defined" do
|
8
|
+
@ex = capture_exception(KeyError) do
|
9
|
+
YouShallNotPass::Authorizator.new.can?(:whatever)
|
10
|
+
end
|
11
|
+
|
12
|
+
@ex.class == KeyError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
scope "lambdas, procs and other callables" do
|
17
|
+
class Action
|
18
|
+
def initialize(val)
|
19
|
+
@val = val
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(*)
|
23
|
+
@val
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class MyAuthenticator < YouShallNotPass::Authorizator
|
28
|
+
def policies
|
29
|
+
{
|
30
|
+
can_lambda: -> (*) { true },
|
31
|
+
cant_lambda: -> (*) { false },
|
32
|
+
|
33
|
+
can_proc: proc { true },
|
34
|
+
cant_proc: proc { false },
|
35
|
+
|
36
|
+
can_action: Action.new(true),
|
37
|
+
cant_action: Action.new(false),
|
38
|
+
|
39
|
+
can_true: true,
|
40
|
+
cant_false: false,
|
41
|
+
|
42
|
+
can_array: [ true, proc { true }, true ],
|
43
|
+
cant_array: [ true, false, true ],
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:authorizator) { MyAuthenticator.new }
|
49
|
+
|
50
|
+
spec "allow lambda" do
|
51
|
+
authorizator.can?(:can_lambda)
|
52
|
+
end
|
53
|
+
|
54
|
+
spec "reject lambda" do
|
55
|
+
! authorizator.can?(:cant_lambda)
|
56
|
+
end
|
57
|
+
|
58
|
+
spec "allow proc" do
|
59
|
+
authorizator.can?(:can_proc)
|
60
|
+
end
|
61
|
+
|
62
|
+
spec "reject proc" do
|
63
|
+
! authorizator.can?(:cant_proc)
|
64
|
+
end
|
65
|
+
|
66
|
+
spec "allow action" do
|
67
|
+
authorizator.can?(:can_action)
|
68
|
+
end
|
69
|
+
|
70
|
+
spec "reject action" do
|
71
|
+
! authorizator.can?(:cant_action)
|
72
|
+
end
|
73
|
+
|
74
|
+
spec "allow true" do
|
75
|
+
authorizator.can?(:can_true)
|
76
|
+
end
|
77
|
+
|
78
|
+
spec "reject false" do
|
79
|
+
! authorizator.can?(:cant_false)
|
80
|
+
end
|
81
|
+
|
82
|
+
spec "allow array" do
|
83
|
+
authorizator.can?(:can_array)
|
84
|
+
end
|
85
|
+
|
86
|
+
spec "reject array" do
|
87
|
+
! authorizator.can?(:cant_array)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
scope "arguments" do
|
93
|
+
class MyAuthenticatorWithArgs < YouShallNotPass::Authorizator
|
94
|
+
def policies
|
95
|
+
{
|
96
|
+
lambda: -> (a:, b:) { a == b },
|
97
|
+
proc: proc { |a:, b:| a == b },
|
98
|
+
|
99
|
+
splat: -> (**args) { args.all? { |k, v| k == v} },
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:authorizator) { MyAuthenticatorWithArgs.new }
|
105
|
+
|
106
|
+
spec "allow lambda" do
|
107
|
+
authorizator.can?(:lambda, a: 1, b: 1)
|
108
|
+
end
|
109
|
+
|
110
|
+
spec "reject lambda" do
|
111
|
+
! authorizator.can?(:lambda, a: 1, b: 2)
|
112
|
+
end
|
113
|
+
|
114
|
+
spec "allow proc" do
|
115
|
+
authorizator.can?(:proc, a: 1, b: 1)
|
116
|
+
end
|
117
|
+
|
118
|
+
spec "reject proc" do
|
119
|
+
! authorizator.can?(:proc, a: 1, b: 2)
|
120
|
+
end
|
121
|
+
|
122
|
+
spec "allow splat" do
|
123
|
+
authorizator.can?(:splat, a: :a , b: :b , c: :c )
|
124
|
+
end
|
125
|
+
|
126
|
+
spec "reject splat" do
|
127
|
+
! authorizator.can?(:splat, a: :a, b: :b, c: :a)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
scope "#perform_for" do
|
132
|
+
class BasicAuthorizator < YouShallNotPass::Authorizator
|
133
|
+
def policies
|
134
|
+
{
|
135
|
+
can: true,
|
136
|
+
cant: false,
|
137
|
+
|
138
|
+
use_args: -> (**args) { args.all? { |k, v| k == v } }
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
let(:authorizator) { BasicAuthorizator.new }
|
144
|
+
|
145
|
+
spec "executes the block if it is allowed" do
|
146
|
+
authorizator.perform_for(:can) do
|
147
|
+
@i_can = true
|
148
|
+
end
|
149
|
+
|
150
|
+
!! defined? @i_can
|
151
|
+
end
|
152
|
+
|
153
|
+
spec "doesn't execute the block if it isn't allowed" do
|
154
|
+
authorizator.perform_for(:cant) do
|
155
|
+
@i_can = true
|
156
|
+
end
|
157
|
+
|
158
|
+
! defined? @i_can
|
159
|
+
end
|
160
|
+
|
161
|
+
spec "passes the arguments" do
|
162
|
+
authorizator.perform_for(:use_args, a: :a, b: :b) do
|
163
|
+
@i_can = true
|
164
|
+
end
|
165
|
+
|
166
|
+
!! defined? @i_can
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
scope "conditional policies" do
|
171
|
+
class NumberAuthenticator < YouShallNotPass::Authorizator
|
172
|
+
def policies
|
173
|
+
{
|
174
|
+
one: true,
|
175
|
+
two: true,
|
176
|
+
three: false,
|
177
|
+
four: false,
|
178
|
+
}
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
let(:authorizator) { NumberAuthenticator.new }
|
183
|
+
|
184
|
+
spec "allow _and_" do
|
185
|
+
authorizator.can?(:one_and_two)
|
186
|
+
end
|
187
|
+
|
188
|
+
spec "reject _and_" do
|
189
|
+
! authorizator.can?(:one_and_three)
|
190
|
+
end
|
191
|
+
|
192
|
+
spec "allow _or_" do
|
193
|
+
authorizator.can?(:one_or_two)
|
194
|
+
end
|
195
|
+
|
196
|
+
spec "reject _or_" do
|
197
|
+
! authorizator.can?(:three_or_four)
|
198
|
+
end
|
199
|
+
|
200
|
+
spec "allow _and_or_" do
|
201
|
+
authorizator.can?(:one_and_two_or_three)
|
202
|
+
end
|
203
|
+
|
204
|
+
spec "reject _and_or_" do
|
205
|
+
! authorizator.can?(:one_and_three_or_four)
|
206
|
+
end
|
207
|
+
|
208
|
+
scope "regular policies vs conditional policies" do
|
209
|
+
class ConditionalAuthorizator < YouShallNotPass::Authorizator
|
210
|
+
def policies
|
211
|
+
{
|
212
|
+
one: true,
|
213
|
+
two: true,
|
214
|
+
one_and_two: false,
|
215
|
+
one_or_two: false
|
216
|
+
}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
let(:authorizator) { ConditionalAuthorizator.new }
|
221
|
+
|
222
|
+
spec "_and_" do
|
223
|
+
! authorizator.can?(:one_and_two)
|
224
|
+
end
|
225
|
+
|
226
|
+
spec "_or_" do
|
227
|
+
! authorizator.can?(:one_or_two)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
scope "#polices" do
|
233
|
+
class MergePolicies < YouShallNotPass::Authorizator
|
234
|
+
def action_policies
|
235
|
+
{
|
236
|
+
create_user: true,
|
237
|
+
update_user: true,
|
238
|
+
}
|
239
|
+
end
|
240
|
+
|
241
|
+
def role_policies
|
242
|
+
{
|
243
|
+
admin: true,
|
244
|
+
editor: true,
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
def feature_policies
|
249
|
+
{
|
250
|
+
avatars: true,
|
251
|
+
random_player: true,
|
252
|
+
}
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
spec do
|
257
|
+
YouShallNotPass::Authorizator.new.policies == {}
|
258
|
+
end
|
259
|
+
|
260
|
+
let(:authorizator) { MergePolicies.new }
|
261
|
+
|
262
|
+
spec "merges all the policies" do
|
263
|
+
@expected = {
|
264
|
+
create_user: true,
|
265
|
+
update_user: true,
|
266
|
+
admin: true,
|
267
|
+
editor: true,
|
268
|
+
avatars: true,
|
269
|
+
random_player: true,
|
270
|
+
}
|
271
|
+
|
272
|
+
authorizator.policies == @expected
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
scope ".attribute" do
|
277
|
+
class UserAuthorizator < YouShallNotPass::Authorizator
|
278
|
+
attribute :user
|
279
|
+
attribute :role
|
280
|
+
|
281
|
+
def policies
|
282
|
+
{
|
283
|
+
something: proc { user == "Me" && role == :admin }
|
284
|
+
}
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
spec "can initialize with attributes" do
|
289
|
+
authorizator = UserAuthorizator.new(user: "Me", role: :admin)
|
290
|
+
|
291
|
+
authorizator.can?(:something)
|
292
|
+
end
|
293
|
+
|
294
|
+
spec "can initialize with attributes" do
|
295
|
+
authorizator = UserAuthorizator.new(user: "Me", role: :user)
|
296
|
+
|
297
|
+
! authorizator.can?(:something)
|
298
|
+
end
|
7
299
|
end
|
8
300
|
end
|
data/you_shall_not_pass.gemspec
CHANGED
@@ -21,4 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
23
|
spec.add_development_dependency "matest", "~> 1.5"
|
24
|
+
|
25
|
+
spec.add_dependency "callable", "~> 0.0.3"
|
26
|
+
spec.add_dependency "fattr", "~> 2.2.2"
|
24
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: you_shall_not_pass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Federico Iachetti
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: callable
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: fattr
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.2.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.2.2
|
55
83
|
description: Embrace authorization with this simple library.
|
56
84
|
email:
|
57
85
|
- iachetti.federico@gmail.com
|
@@ -66,7 +94,6 @@ files:
|
|
66
94
|
- Rakefile
|
67
95
|
- lib/you_shall_not_pass.rb
|
68
96
|
- lib/you_shall_not_pass/authorizator.rb
|
69
|
-
- lib/you_shall_not_pass/callable.rb
|
70
97
|
- lib/you_shall_not_pass/policy.rb
|
71
98
|
- lib/you_shall_not_pass/version.rb
|
72
99
|
- spec/spec_helper.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module YouShallNotPass
|
2
|
-
|
3
|
-
module Callable
|
4
|
-
def Callable( callable_or_not )
|
5
|
-
callable_or_not.respond_to?(:call) ? callable_or_not : proc { |*args| callable_or_not }
|
6
|
-
end
|
7
|
-
|
8
|
-
def callable
|
9
|
-
Callable( self )
|
10
|
-
end
|
11
|
-
|
12
|
-
def callable?
|
13
|
-
self.respond_to? :call
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|