you_shall_not_pass 0.0.3 → 0.1.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
  SHA1:
3
- metadata.gz: c2a0082fe593f22ba8a1ccc446061ed132bb3248
4
- data.tar.gz: f9be21782946d49cd83fe2b694d29ca6a153e07c
3
+ metadata.gz: 2f7b94fd90514299c816fa9f4f55a4f50fe7fadb
4
+ data.tar.gz: 2c20e0ded03fde67292cb5fbed5a11a7ffa959b3
5
5
  SHA512:
6
- metadata.gz: 225b91dba9bc231f7ff0207523bb1f8d360506aa473e9f399de64b44a8482f9d6b50712066b1bd994a03e90e19b42c273594027430642aa63dc6804383fbd791
7
- data.tar.gz: 19679f956b3282381acbca246d940be8cabf690f1e520f22d6cb0c7258ef52d8fd9d6ace5ead2bda13740af9ef723f0bc2b741717ca08aa3c70303d807a10dfe
6
+ metadata.gz: e7e767bf6c234ab62c6ad73c94d8ce37e90fc25bdf5c2948d6126bc715351a3367164f1fe490ed28c9ccd17e884a86629077f6d81c530b884ccf205c6d6c03d8
7
+ data.tar.gz: 8512dcc4f5df0b615619ebc360387d400a56ce7db016d1598defaedef9defe7902b1ccaff82a9f62f006e22182383929c3c9e0e01512a36d914ac73bfcdf7aac
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 2.0.0
3
+ - 2.1.1
4
+ - 2.2.0
5
+ - ruby-head
data/README.md CHANGED
@@ -1,13 +1,168 @@
1
1
  # YouShallNotPass
2
+ [![Build Status](https://travis-ci.org/iachettifederico/you_shall_not_pass.png?branch=master)](https://travis-ci.org/iachettifederico/you_shall_not_pass)
3
+
4
+
5
+ Simple framework-agnostic authorization library.
6
+
7
+ ## Usage
8
+
9
+ You Shall Not Pass is a very minimalistic authorization framework. It doesn't really care about your system architecture.
10
+ You don't really need to set up your authentication schema in any particular way (in fact, you don't even really need authentication to make You Shall Not Pass work).
11
+
12
+ The first you need is to create an Authorizator. You can define one by extending `YouShallNotPass::Authorizator` and then define the authorization policies.
13
+
14
+ Let's write a first example:
15
+
16
+ ```ruby
17
+ class MyAuthorizator < YouShallNotPass::Authorizator
18
+ def time_policies
19
+ {
20
+ morning_shift: Time.now.hour <= 12,
21
+ afternoon_shift: Time.now.hour > 12 && Time.now.hour < 20,
22
+ night_shift: Time.now.hour >= 20,
23
+ }
24
+ end
25
+ end
26
+ ```
27
+
28
+ As you can see, there's no user, role, or any kind of authentication going on in this example.
29
+
30
+ Now we can ask if we have permission to `<insert action here>` depending on the shift:
31
+
32
+ ```ruby
33
+ Time.now
34
+ # => 2015-02-09 20:17:26 -0300
35
+
36
+ Time.now.hour
37
+ # => 20
38
+
39
+ auth = MyAuthorizator.new
40
+ auth.can?(:morning_shift)
41
+ # => false
42
+
43
+ auth.can?(:afternoon_shift)
44
+ # => false
45
+
46
+ auth.can?(:night_shift)
47
+ # => true
48
+ ```
49
+
50
+ In this case, the code was run at 20:17, so it corresponds to the night shift.
51
+
52
+ We can also perform an action depending on the shift. So let's get some output:
53
+
54
+ ```ruby
55
+ auth.perform_for(:morning_shift) do
56
+ puts "Morning shift"
57
+ end
58
+
59
+ auth.perform_for(:afternoon_shift) do
60
+ puts "Afternoon shift"
61
+ end
62
+
63
+ auth.perform_for(:night_shift) do
64
+ puts "Night shift"
65
+ end
66
+
67
+ # >> Night shift
68
+ ```
69
+
70
+ And as we are on the night shift, the only block that get's called is the one that performs for the night shift.
71
+
72
+ ## *_policies
73
+
74
+ You Shall Not Pass allows you to group your permissions by providing instance methods suffixed with `_policies`.
75
+
76
+ So, if we have:
77
+
78
+ ```ruby
79
+ class MyAuthorizator < YouShallNotPass::Authorizator
80
+ def time_policies
81
+ {
82
+ morning_shift: Time.now.hour <= 12,
83
+ afternoon_shift: Time.now.hour > 12 && Time.now.hour < 20,
84
+ night_shift: Time.now.hour >= 20,
85
+ }
86
+ end
87
+
88
+ def date_policies
89
+ {
90
+ jan: Time.now.month == 1,
91
+ feb: Time.now.month == 2,
92
+ }
93
+ end
94
+ end
95
+ ```
96
+
97
+ The available policy names are:
98
+
99
+ ```ruby
100
+ auth = MyAuthorizator.new
101
+ auth.policies.keys
102
+ # => [:morning_shift, :afternoon_shift, :night_shift, :jan, :feb]
103
+ ```
104
+
105
+ ## Attributes
106
+
107
+ If you have an authorization schema in place, you can make You Shall Not Pass aware of it by introducing attributes.
108
+
109
+ Let's say we have a `User` object and we want our authenticator to use it. We can extend `MyAuthorizator` to accept a `user` attribute and use it on the policies.
110
+
111
+ ```ruby
112
+ class User
113
+ def initialize(admin)
114
+ @admin = admin
115
+ end
116
+
117
+ def admin?
118
+ @admin
119
+ end
120
+ end
121
+
122
+ class MyAuthorizator < YouShallNotPass::Authorizator
123
+ attribute :user
124
+
125
+ def user_policies
126
+ {
127
+ admin: user.admin?
128
+ }
129
+ end
130
+ end
131
+ ```
132
+
133
+ Now we need to instantiate an authorizator passing the user as a (named) parameter:
134
+
135
+ ```ruby
136
+ auth1 = MyAuthorizator.new(user: User.new(true))
137
+ auth1.perform_for(:admin) do
138
+ puts "First user"
139
+ end
140
+
141
+ auth2 = MyAuthorizator.new(user: User.new(false))
142
+ auth2.perform_for(:admin) do
143
+ puts "Second user"
144
+ end
145
+
146
+ # >> First user
147
+ ```
148
+
149
+ And only the first one will print.
150
+
151
+ You can add as many attributes as you want and you will get an instance method to use it at will.
152
+
153
+ It's important to notice that the `user` in this case is just a Ruby object. You don't need to comply with any API in particular.
154
+
155
+ In a web framework, is a good idea to create the authorizator after defining the current user and then pass the current user as a parameter.
156
+
157
+ If you need to authenticate using other objects, you can keep adding attributes to the authorizator (for example pass a settings array, the environment your on - dev, prod-, etc).
2
158
 
3
- TODO: Write a gem description
4
159
 
5
160
  ## Installation
6
161
 
7
162
  Add this line to your application's Gemfile:
8
163
 
9
164
  ```ruby
10
- gem 'you_shall_not_pass'
165
+ gem 'you_shall_not_pass'
11
166
  ```
12
167
 
13
168
  And then execute:
@@ -18,9 +173,6 @@ Or install it yourself as:
18
173
 
19
174
  $ gem install you_shall_not_pass
20
175
 
21
- ## Usage
22
-
23
- TODO: Write usage instructions here
24
176
 
25
177
  ## Contributing
26
178
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
3
  require "matest/spec_tasks"
4
+
5
+ task default: :spec
@@ -8,23 +8,27 @@ module YouShallNotPass
8
8
  send attr, value
9
9
  end
10
10
  end
11
-
11
+
12
12
  def can?(permission, **args)
13
13
  Array(policies.fetch(permission)).all? do |policy|
14
14
  Callable(policy).call(**args) == true
15
15
  end
16
- rescue KeyError => e
17
- if permission =~ /_and_/
16
+ rescue KeyError => exception
17
+ break_down_can(permission, exception, **args)
18
+ end
19
+
20
+ def break_down_can(permission, exception, **args)
21
+ case permission
22
+ when /_and_/
18
23
  permission.to_s.split("_and_").all? { |policy| can?(policy.to_sym, **args)}
19
- elsif permission =~ /_or_/
24
+ when /_or_/
20
25
  permission.to_s.split("_or_").any? { |policy| can?(policy.to_sym, **args)}
21
- elsif permission =~ /\Anot_/
26
+ when /\Anot_/
22
27
  policy = permission.to_s.gsub(/\Anot_/, "")
23
28
  ! can?(policy.to_sym, **args)
24
29
  else
25
- raise e
30
+ raise exception
26
31
  end
27
-
28
32
  end
29
33
 
30
34
  def perform_for(permission, **args)
@@ -32,15 +36,35 @@ module YouShallNotPass
32
36
  end
33
37
 
34
38
  def policies
35
- @policies ||= methods.grep(/_policies\Z/).map {|name| send(name)}.each_with_object({}) do |curr, res|
39
+ @policies ||= __set_policies__
40
+ end
41
+
42
+ private
43
+
44
+ def __set_policies__
45
+ the_policies = methods.grep(/_policies\z/).map {|name| send(name)}.each_with_object({}) do |curr, res|
36
46
  res.merge!(curr)
37
47
  end
48
+
49
+ the_policies.merge!( self.class.__dsl_policies__.each_with_object({}) { |policy, h|
50
+ block = policy.last
51
+ h[policy.first] = instance_eval(&block)
52
+ })
53
+
54
+ the_policies
38
55
  end
39
56
 
40
- private
57
+ def self.__dsl_policies__
58
+ @__dsl_policies__ ||= {}
59
+ end
60
+
61
+ def self.authorize(name, &block)
62
+ __dsl_policies__[name] = block
63
+ end
41
64
 
42
65
  def self.attribute(attr)
43
66
  fattr attr
44
67
  end
68
+ private_class_method :attribute
45
69
  end
46
70
  end
@@ -1,11 +1,7 @@
1
1
  module YouShallNotPass
2
2
  class Policy
3
- include Callable
4
- attr_reader :user
5
-
6
3
  def initialize(authorizator)
7
4
  @authorizator = authorizator
8
- @user = authorizator.user
9
5
  end
10
6
 
11
7
  def call(**options)
@@ -1,3 +1,3 @@
1
1
  module YouShallNotPass
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -24,28 +24,28 @@ scope YouShallNotPass::Authorizator do
24
24
  end
25
25
  end
26
26
 
27
- class MyAuthenticator < YouShallNotPass::Authorizator
27
+ class MyAuthorizator < YouShallNotPass::Authorizator
28
28
  def policies
29
29
  {
30
- can_lambda: -> (*) { true },
31
- cant_lambda: -> (*) { false },
30
+ can_lambda: -> (*) { true },
31
+ cant_lambda: -> (*) { false },
32
32
 
33
- can_proc: proc { true },
34
- cant_proc: proc { false },
33
+ can_proc: proc { true },
34
+ cant_proc: proc { false },
35
35
 
36
- can_action: Action.new(true),
37
- cant_action: Action.new(false),
36
+ can_action: Action.new(true),
37
+ cant_action: Action.new(false),
38
38
 
39
- can_true: true,
40
- cant_false: false,
39
+ can_true: true,
40
+ cant_false: false,
41
41
 
42
- can_array: [ true, proc { true }, true ],
43
- cant_array: [ true, false, true ],
42
+ can_array: [ true, proc { true }, true ],
43
+ cant_array: [ true, false, true ],
44
44
  }
45
45
  end
46
46
  end
47
47
 
48
- let(:authorizator) { MyAuthenticator.new }
48
+ let(:authorizator) { MyAuthorizator.new }
49
49
 
50
50
  spec "allow lambda" do
51
51
  authorizator.can?(:can_lambda)
@@ -90,18 +90,18 @@ scope YouShallNotPass::Authorizator do
90
90
  end
91
91
 
92
92
  scope "arguments" do
93
- class MyAuthenticatorWithArgs < YouShallNotPass::Authorizator
93
+ class MyAuthorizatorWithArgs < YouShallNotPass::Authorizator
94
94
  def policies
95
95
  {
96
- lambda: -> (a:, b:) { a == b },
97
- proc: proc { |a:, b:| a == b },
96
+ lambda: -> (a:, b:) { a == b },
97
+ proc: proc { |a:, b:| a == b },
98
98
 
99
- splat: -> (**args) { args.all? { |k, v| k == v} },
99
+ splat: -> (**args) { args.all? { |k, v| k == v} },
100
100
  }
101
101
  end
102
102
  end
103
103
 
104
- let(:authorizator) { MyAuthenticatorWithArgs.new }
104
+ let(:authorizator) { MyAuthorizatorWithArgs.new }
105
105
 
106
106
  spec "allow lambda" do
107
107
  authorizator.can?(:lambda, a: 1, b: 1)
@@ -132,10 +132,10 @@ scope YouShallNotPass::Authorizator do
132
132
  class BasicAuthorizator < YouShallNotPass::Authorizator
133
133
  def policies
134
134
  {
135
- can: true,
136
- cant: false,
135
+ can: true,
136
+ cant: false,
137
137
 
138
- use_args: -> (**args) { args.all? { |k, v| k == v } }
138
+ use_args: -> (**args) { args.all? { |k, v| k == v } }
139
139
  }
140
140
  end
141
141
  end
@@ -168,18 +168,18 @@ scope YouShallNotPass::Authorizator do
168
168
  end
169
169
 
170
170
  scope "conditional policies" do
171
- class NumberAuthenticator < YouShallNotPass::Authorizator
171
+ class NumberAuthorizator < YouShallNotPass::Authorizator
172
172
  def policies
173
173
  {
174
- one: true,
175
- two: true,
176
- three: false,
177
- four: false,
174
+ one: true,
175
+ two: true,
176
+ three: false,
177
+ four: false,
178
178
  }
179
179
  end
180
180
  end
181
181
 
182
- let(:authorizator) { NumberAuthenticator.new }
182
+ let(:authorizator) { NumberAuthorizator.new }
183
183
 
184
184
  spec "allow _and_" do
185
185
  authorizator.can?(:one_and_two)
@@ -217,10 +217,10 @@ scope YouShallNotPass::Authorizator do
217
217
  class ConditionalAuthorizator < YouShallNotPass::Authorizator
218
218
  def policies
219
219
  {
220
- one: true,
221
- two: true,
222
- one_and_two: false,
223
- one_or_two: false
220
+ one: true,
221
+ two: true,
222
+ one_and_two: false,
223
+ one_or_two: false
224
224
  }
225
225
  end
226
226
  end
@@ -241,22 +241,22 @@ scope YouShallNotPass::Authorizator do
241
241
  class MergePolicies < YouShallNotPass::Authorizator
242
242
  def action_policies
243
243
  {
244
- create_user: true,
245
- update_user: true,
244
+ create_user: true,
245
+ update_user: true,
246
246
  }
247
247
  end
248
248
 
249
249
  def role_policies
250
250
  {
251
- admin: true,
252
- editor: true,
251
+ admin: true,
252
+ editor: true,
253
253
  }
254
254
  end
255
255
 
256
256
  def feature_policies
257
257
  {
258
- avatars: true,
259
- random_player: true,
258
+ avatars: true,
259
+ random_player: true,
260
260
  }
261
261
  end
262
262
  end
@@ -269,13 +269,13 @@ scope YouShallNotPass::Authorizator do
269
269
 
270
270
  spec "merges all the policies" do
271
271
  @expected = {
272
- create_user: true,
273
- update_user: true,
274
- admin: true,
275
- editor: true,
276
- avatars: true,
277
- random_player: true,
278
- }
272
+ create_user: true,
273
+ update_user: true,
274
+ admin: true,
275
+ editor: true,
276
+ avatars: true,
277
+ random_player: true,
278
+ }
279
279
 
280
280
  authorizator.policies == @expected
281
281
  end
@@ -288,7 +288,7 @@ scope YouShallNotPass::Authorizator do
288
288
 
289
289
  def policies
290
290
  {
291
- something: proc { user == "Me" && role == :admin }
291
+ something: proc { user == "Me" && role == :admin }
292
292
  }
293
293
  end
294
294
  end
@@ -305,4 +305,31 @@ scope YouShallNotPass::Authorizator do
305
305
  ! authorizator.can?(:something)
306
306
  end
307
307
  end
308
+
309
+ scope "dsl" do
310
+ class DslAuthorizator < YouShallNotPass::Authorizator
311
+ attribute :user
312
+ attribute :pass
313
+
314
+ authorize(:true) { true }
315
+ authorize(:false) { false }
316
+
317
+ authorize(:login) { user == pass}
318
+ end
319
+
320
+ let(:authorizator) { DslAuthorizator.new(user: "fede", pass: "fede") }
321
+
322
+ spec "authorizes true" do
323
+ authorizator.can?(:true)
324
+ end
325
+
326
+ spec "rejects false" do
327
+ authorizator.can?(:false) == false
328
+ end
329
+
330
+ spec do
331
+ authorizator.can?(:login)
332
+ end
333
+
334
+ end
308
335
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["iachetti.federico@gmail.com"]
11
11
  spec.summary = %q{Simple authorization library.}
12
12
  spec.description = %q{Embrace authorization with this simple library.}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/iachettifederico/you_shall_not_pass"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.7"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "matest", "~> 1.5"
23
+ spec.add_development_dependency "matest", "~> 1.7.1"
24
24
 
25
- spec.add_dependency "callable", "~> 0.0.3"
25
+ spec.add_dependency "callable", "~> 0.0.5"
26
26
  spec.add_dependency "fattr", "~> 2.2.2"
27
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.3
4
+ version: 0.1.0
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-02-03 00:00:00.000000000 Z
11
+ date: 2015-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.5'
47
+ version: 1.7.1
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.5'
54
+ version: 1.7.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: callable
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.0.3
61
+ version: 0.0.5
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.0.3
68
+ version: 0.0.5
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: fattr
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +88,7 @@ extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
90
  - ".gitignore"
91
+ - ".travis.yml"
91
92
  - Gemfile
92
93
  - LICENSE.txt
93
94
  - README.md
@@ -99,7 +100,7 @@ files:
99
100
  - spec/spec_helper.rb
100
101
  - spec/you_shall_not_pass/authorizator_spec.rb
101
102
  - you_shall_not_pass.gemspec
102
- homepage: ''
103
+ homepage: https://github.com/iachettifederico/you_shall_not_pass
103
104
  licenses:
104
105
  - MIT
105
106
  metadata: {}
@@ -119,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
120
  version: '0'
120
121
  requirements: []
121
122
  rubyforge_project:
122
- rubygems_version: 2.4.5
123
+ rubygems_version: 2.4.8
123
124
  signing_key:
124
125
  specification_version: 4
125
126
  summary: Simple authorization library.