banken 0.0.1 → 0.1.1
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/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +0 -2
- data/README.md +381 -17
- data/Rakefile +17 -1
- data/banken.gemspec +1 -0
- data/lib/banken.rb +27 -58
- data/lib/banken/error.rb +5 -5
- data/lib/banken/loyalty_finder.rb +28 -0
- data/lib/banken/version.rb +1 -1
- data/lib/generators/banken/install/USAGE +1 -1
- data/lib/generators/banken/install/install_generator.rb +2 -2
- data/lib/generators/banken/install/templates/{application_policy.rb → application_loyalty.rb} +2 -19
- data/lib/generators/banken/loyalty/USAGE +8 -0
- data/lib/generators/banken/loyalty/loyalty_generator.rb +13 -0
- data/lib/generators/banken/loyalty/templates/loyalty.rb +4 -0
- metadata +24 -8
- data/lib/banken/helper.rb +0 -8
- data/lib/banken/policy_finder.rb +0 -41
- data/lib/generators/banken/policy/USAGE +0 -8
- data/lib/generators/banken/policy/policy_generator.rb +0 -13
- data/lib/generators/banken/policy/templates/policy.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fa23a2a65fb5297370655ef973516a3615be3d4
|
4
|
+
data.tar.gz: 5965509ce31efeb8243a1796191b4da0c416e429
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 763ee80874810e27d2d9edfa8dca6298e8f6694fa097ac558ac9857c23848b57d638b000410126e1bb427e183afb17ce4c37690a07d4c4701f4c3b9a50295d71
|
7
|
+
data.tar.gz: d8ea1e7142b0b3badd6bf538dc6a1498b921a858683e53d6b735bd5cd73bd6a02b848727d5f6fae4867fe7d69d894fa89f6458f8d2d634fa6a6c94e5083522cb
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,41 +1,405 @@
|
|
1
1
|
# Banken
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/kyuden/banken)
|
4
|
+
[](https://codeclimate.com/github/kyuden/banken)
|
5
|
+
[](https://badge.fury.io/rb/banken)
|
4
6
|
|
5
|
-
|
7
|
+
Banken provides a set of helpers which guide you in leveraging regular Ruby
|
8
|
+
classes and object oriented design patterns to build a simple, robust and
|
9
|
+
scaleable authorization system.
|
6
10
|
|
7
11
|
## Installation
|
8
12
|
|
9
|
-
|
13
|
+
``` ruby
|
14
|
+
gem "banken"
|
15
|
+
```
|
16
|
+
|
17
|
+
Include Banken in your application controller:
|
18
|
+
|
19
|
+
``` ruby
|
20
|
+
# app/controllers/application_controller.rb
|
21
|
+
class ApplicationController < ActionController::Base
|
22
|
+
include Banken
|
23
|
+
protect_from_forgery
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
Optionally, you can run the generator, which will set up an application loyalty
|
28
|
+
with some useful defaults for you:
|
29
|
+
|
30
|
+
``` sh
|
31
|
+
rails g banken:install
|
32
|
+
```
|
33
|
+
|
34
|
+
After generating your application loyalty, restart the Rails server so that Rails
|
35
|
+
can pick up any classes in the new `app/loyalties/` directory.
|
36
|
+
|
37
|
+
## Policies
|
38
|
+
|
39
|
+
Banken is focused around the notion of loyalty classes. We suggest that you put
|
40
|
+
these classes in `app/loyalties`. This is a simple example that allows updating
|
41
|
+
a post if the user is an admin, or if the post is unpublished:
|
42
|
+
|
43
|
+
``` ruby
|
44
|
+
# app/loyalties/posts_loyalty.rb
|
45
|
+
class PostsLoyalty
|
46
|
+
attr_reader :user, :post
|
47
|
+
|
48
|
+
def initialize(user, post)
|
49
|
+
@user = user
|
50
|
+
@post = post
|
51
|
+
end
|
52
|
+
|
53
|
+
def update?
|
54
|
+
user.admin? || post.unpublished?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
As you can see, this is just a plain Ruby class. Banken makes the following
|
60
|
+
assumptions about this class:
|
61
|
+
|
62
|
+
- The class has the same name as some kind of controller class, only suffixed
|
63
|
+
with the word "Loyalty".
|
64
|
+
- The first argument is a user. In your controller, Banken will call the
|
65
|
+
`current_user` method to retrieve what to send into this argument
|
66
|
+
- The second argument is optional, whose authorization you want to check.
|
67
|
+
This does not need to be an ActiveRecord or even an ActiveModel object,
|
68
|
+
it can be anything really.
|
69
|
+
- The class implements some kind of query method, in this case `update?`.
|
70
|
+
Usually, this will map to the name of a particular controller action.
|
71
|
+
|
72
|
+
That's it really.
|
73
|
+
|
74
|
+
Usually you'll want to inherit from the application loyalty created by the
|
75
|
+
generator, or set up your own base class to inherit from:
|
76
|
+
|
77
|
+
``` ruby
|
78
|
+
# app/loyalties/posts_loyalty.rb
|
79
|
+
class PostsLoyalty < ApplicationLoyalty
|
80
|
+
def update?
|
81
|
+
user.admin? || record.unpublished?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
In the generated `ApplicationLoyalty`, the optional object is called `record`.
|
87
|
+
|
88
|
+
Supposing that you are in PostsController, Banken now lets you do
|
89
|
+
this in your controller:
|
90
|
+
|
91
|
+
``` ruby
|
92
|
+
# app/controllers/posts_controller.rb
|
93
|
+
class PostsController < ApplicationController
|
94
|
+
def update
|
95
|
+
@post = Post.find(params[:id])
|
96
|
+
authorize! @post
|
97
|
+
if @post.update(post_params)
|
98
|
+
redirect_to @post
|
99
|
+
else
|
100
|
+
render :edit
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
The authorize method automatically infers from controller name that `Posts` will have a matching
|
107
|
+
`PostsLoyalty` class, and instantiates this class, handing in the current user
|
108
|
+
and the given optional object. It then infers from the action name, that it should call
|
109
|
+
`update?` on this instance of the loyalty. In this case, you can imagine that
|
110
|
+
`authorize!` would have done something like this:
|
111
|
+
|
112
|
+
``` ruby
|
113
|
+
raise "not authorized" unless PostsLoyalty.new(current_user, @post).update?
|
114
|
+
```
|
115
|
+
|
116
|
+
If you don't have an optional object for the first argument to `authorize!`, then you can pass
|
117
|
+
the class. For example:
|
118
|
+
|
119
|
+
Loyalty:
|
120
|
+
```ruby
|
121
|
+
# app/loyalties/posts_loyalty.rb
|
122
|
+
class PostsLoyalty < ApplicationLoyalty
|
123
|
+
def admin_list?
|
124
|
+
user.admin?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Controller:
|
130
|
+
```ruby
|
131
|
+
# app/controllers/posts_controller.rb
|
132
|
+
class PostsController < ApplicationController
|
133
|
+
def admin_list
|
134
|
+
authorize!
|
135
|
+
# Rest of controller action
|
136
|
+
end
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
You can easily get a hold of an instance of the loyalty through the `loyalty`
|
141
|
+
method in both the view and controller. This is especially useful for
|
142
|
+
conditionally showing links or buttons in the view:
|
143
|
+
|
144
|
+
``` erb
|
145
|
+
<% if loyalty(@post, :posts).update? %>
|
146
|
+
<%= link_to "Edit post", edit_post_path(@post) %>
|
147
|
+
<% end %>
|
148
|
+
```
|
149
|
+
|
150
|
+
## Ensuring loyalties are used
|
151
|
+
|
152
|
+
Banken adds a method called `verify_authorized` to your controllers. This
|
153
|
+
method will raise an exception if `authorize!` has not yet been called. You
|
154
|
+
should run this method in an `after_action` to ensure that you haven't
|
155
|
+
forgotten to authorize the action. For example:
|
156
|
+
|
157
|
+
``` ruby
|
158
|
+
# app/controllers/application_controller.rb
|
159
|
+
class ApplicationController < ActionController::Base
|
160
|
+
after_action :verify_authorized, except: :index
|
161
|
+
end
|
162
|
+
```
|
163
|
+
|
164
|
+
|
165
|
+
If you're using `verify_authorized` in your controllers but need to
|
166
|
+
conditionally bypass verification, you can use `skip_authorization`.
|
167
|
+
These are useful in circumstances where you don't want to disable verification for the
|
168
|
+
entire action, but have some cases where you intend to not authorize.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
# app/controllers/posts_controller.rb
|
172
|
+
class PostsController < ApplicationController
|
173
|
+
def show
|
174
|
+
record = Record.find_by(attribute: "value")
|
175
|
+
if record.present?
|
176
|
+
authorize record
|
177
|
+
else
|
178
|
+
skip_authorization
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
If you need to perform some more sophisticated logic or you want to raise a custom
|
185
|
+
exception you can use the two lower level method `banken_loyalty_authorized?` which
|
186
|
+
return `true` or `false` depending on whether `authorize!` have been called, respectively.
|
187
|
+
|
188
|
+
## Just plain old Ruby
|
189
|
+
|
190
|
+
As you can see, Banken doesn't do anything you couldn't have easily done
|
191
|
+
yourself. It's a very small library, it just provides a few neat helpers.
|
192
|
+
Together these give you the power of building a well structured, fully working
|
193
|
+
authorization system without using any special DSLs or funky syntax or
|
194
|
+
anything.
|
195
|
+
|
196
|
+
Remember that all of the loyalty is just plain Ruby classes,
|
197
|
+
which means you can use the same mechanisms you always use to DRY things up.
|
198
|
+
Encapsulate a set of permissions into a module and include them in multiple
|
199
|
+
loyalties. Use `alias_method` to make some permissions behave the same as
|
200
|
+
others. Inherit from a base set of permissions. Use metaprogramming if you
|
201
|
+
really have to.
|
202
|
+
|
203
|
+
## Generator
|
204
|
+
|
205
|
+
Use the supplied generator to generate loyalties:
|
206
|
+
|
207
|
+
``` sh
|
208
|
+
rails g banken:loyalty posts
|
209
|
+
```
|
210
|
+
|
211
|
+
## Closed systems
|
212
|
+
|
213
|
+
In many applications, only logged in users are really able to do anything. If
|
214
|
+
you're building such a system, it can be kind of cumbersome to check that the
|
215
|
+
user in a loyalty isn't `nil` for every single permission.
|
216
|
+
|
217
|
+
We suggest that you define a filter that redirects unauthenticated users to the
|
218
|
+
login page. As a secondary defence, if you've defined an ApplicationLoyalty, it
|
219
|
+
might be a good idea to raise an exception if somehow an unauthenticated user
|
220
|
+
got through. This way you can fail more gracefully.
|
221
|
+
|
222
|
+
``` ruby
|
223
|
+
# app/loyalties/application_loyalty.rb
|
224
|
+
class ApplicationLoyalty
|
225
|
+
def initialize(user, record)
|
226
|
+
raise Banken::NotAuthorizedError, "must be logged in" unless user
|
227
|
+
@user = user
|
228
|
+
@record = record
|
229
|
+
end
|
230
|
+
end
|
231
|
+
```
|
232
|
+
|
233
|
+
## Rescuing a denied Authorization in Rails
|
234
|
+
|
235
|
+
Banken raises a `Banken::NotAuthorizedError` you can
|
236
|
+
[rescue_from](http://guides.rubyonrails.org/action_controller_overview.html#rescue-from)
|
237
|
+
in your `ApplicationController`. You can customize the `user_not_authorized`
|
238
|
+
method in every controller.
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
# app/controllers/application_controller.rb
|
242
|
+
class ApplicationController < ActionController::Base
|
243
|
+
protect_from_forgery
|
244
|
+
include Banken
|
245
|
+
|
246
|
+
rescue_from Banken::NotAuthorizedError, with: :user_not_authorized
|
247
|
+
|
248
|
+
private
|
249
|
+
|
250
|
+
def user_not_authorized
|
251
|
+
flash[:alert] = "You are not authorized to perform this action."
|
252
|
+
redirect_to(request.referrer || root_path)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
## Creating custom error messages
|
258
|
+
|
259
|
+
`NotAuthorizedError`s provide information on what query (e.g. `:create?`), what
|
260
|
+
controller (e.g. `PostsController`), and what loyalty (e.g. an instance of
|
261
|
+
`PostsLoyalty`) caused the error to be raised.
|
262
|
+
|
263
|
+
One way to use these `query`, `record`, and `loyalty` properties is to connect
|
264
|
+
them with `I18n` to generate error messages. Here's how you might go about doing
|
265
|
+
that.
|
10
266
|
|
11
267
|
```ruby
|
12
|
-
|
268
|
+
# app/controllers/application_controller.rb
|
269
|
+
class ApplicationController < ActionController::Base
|
270
|
+
rescue_from Banken::NotAuthorizedError, with: :user_not_authorized
|
271
|
+
|
272
|
+
private
|
273
|
+
|
274
|
+
def user_not_authorized(exception)
|
275
|
+
loyalty_name = exception.loyalty.class.to_s.underscore
|
276
|
+
|
277
|
+
flash[:error] = t "#{loyalty_name}.#{exception.query}", scope: "banken", default: :default
|
278
|
+
redirect_to(request.referrer || root_path)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
283
|
+
```yaml
|
284
|
+
en:
|
285
|
+
banken:
|
286
|
+
default: 'You cannot perform this action.'
|
287
|
+
posts_loyalty:
|
288
|
+
update?: 'You cannot edit this post!'
|
289
|
+
create?: 'You cannot create posts!'
|
13
290
|
```
|
14
291
|
|
15
|
-
|
292
|
+
Of course, this is just an example. Banken is agnostic as to how you implement
|
293
|
+
your error messaging.
|
16
294
|
|
17
|
-
|
295
|
+
## Customize Banken user
|
18
296
|
|
19
|
-
|
297
|
+
In some cases your controller might not have access to `current_user`, or your
|
298
|
+
`current_user` is not the method that should be invoked by Banken. Simply
|
299
|
+
define a method in your controller called `banken_user`.
|
20
300
|
|
21
|
-
|
301
|
+
```ruby
|
302
|
+
def banken_user
|
303
|
+
User.find_by_other_means
|
304
|
+
end
|
305
|
+
```
|
306
|
+
|
307
|
+
## Additional context
|
22
308
|
|
23
|
-
|
309
|
+
Banken strongly encourages you to model your application in such a way that the
|
310
|
+
only context you need for authorization is a user object and a domain model that
|
311
|
+
you want to check authorization for. If you find yourself needing more context than
|
312
|
+
that, consider whether you are authorizing the right domain model, maybe another
|
313
|
+
domain model (or a wrapper around multiple domain models) can provide the context
|
314
|
+
you need.
|
24
315
|
|
25
|
-
|
316
|
+
Banken does not allow you to pass additional arguments to loyalties for precisely
|
317
|
+
this reason.
|
26
318
|
|
27
|
-
|
319
|
+
However, in very rare cases, you might need to authorize based on more context than just
|
320
|
+
the currently authenticated user. Suppose for example that authorization is dependent
|
321
|
+
on IP address in addition to the authenticated user. In that case, one option is to
|
322
|
+
create a special class which wraps up both user and IP and passes it to the loyalty.
|
28
323
|
|
29
|
-
|
324
|
+
``` ruby
|
325
|
+
class UserContext
|
326
|
+
attr_reader :user, :ip
|
30
327
|
|
31
|
-
|
328
|
+
def initialize(user, ip)
|
329
|
+
@user = user
|
330
|
+
@ip = ip
|
331
|
+
end
|
332
|
+
end
|
32
333
|
|
33
|
-
|
334
|
+
# app/controllers/application_controller.rb
|
335
|
+
class ApplicationController
|
336
|
+
include Banken
|
34
337
|
|
35
|
-
|
338
|
+
def banken_user
|
339
|
+
UserContext.new(current_user, request.ip)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
```
|
343
|
+
|
344
|
+
## Strong parameters
|
36
345
|
|
346
|
+
In Rails 4 (or Rails 3.2 with the
|
347
|
+
[strong_parameters](https://github.com/rails/strong_parameters) gem),
|
348
|
+
mass-assignment protection is handled in the controller. With Banken you can
|
349
|
+
control which attributes a user has access to update via your loyalties. You can
|
350
|
+
set up a `permitted_attributes` method in your loyalty like this:
|
37
351
|
|
38
|
-
|
352
|
+
```ruby
|
353
|
+
# app/loyalties/posts_loyalty.rb
|
354
|
+
class PostsLoyalty < ApplicationLoyalty
|
355
|
+
def permitted_attributes
|
356
|
+
if user.admin? || user.owner_of?(post)
|
357
|
+
[:title, :body, :tag_list]
|
358
|
+
else
|
359
|
+
[:tag_list]
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
```
|
364
|
+
|
365
|
+
You can now retrieve these attributes from the loyalty:
|
366
|
+
|
367
|
+
```ruby
|
368
|
+
# app/controllers/posts_controller.rb
|
369
|
+
class PostsController < ApplicationController
|
370
|
+
def update
|
371
|
+
@post = Post.find(params[:id])
|
372
|
+
if @post.update_attributes(post_params)
|
373
|
+
redirect_to @post
|
374
|
+
else
|
375
|
+
render :edit
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
private
|
380
|
+
|
381
|
+
def post_params
|
382
|
+
params.require(:post).permit(loyalty(@post).permitted_attributes)
|
383
|
+
end
|
384
|
+
end
|
385
|
+
```
|
386
|
+
|
387
|
+
However, this is a bit cumbersome, so Banken provides a convenient helper method:
|
388
|
+
|
389
|
+
```ruby
|
390
|
+
# app/controllers/posts_controller.rb
|
391
|
+
class PostsController < ApplicationController
|
392
|
+
def update
|
393
|
+
@post = Post.find(params[:id])
|
394
|
+
if @post.update_attributes(permitted_attributes(@post))
|
395
|
+
redirect_to @post
|
396
|
+
else
|
397
|
+
render :edit
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
```
|
39
402
|
|
40
|
-
|
403
|
+
# License
|
41
404
|
|
405
|
+
Licensed under the MIT license, see the separate LICENSE.txt file.
|
data/Rakefile
CHANGED
@@ -1 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
require 'yard'
|
5
|
+
|
6
|
+
desc "Run all examples"
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
|
+
#t.rspec_path = 'bin/rspec'
|
9
|
+
t.rspec_opts = %w[--color]
|
10
|
+
end
|
11
|
+
|
12
|
+
YARD::Rake::YardocTask.new do |t|
|
13
|
+
t.files = ['lib/**/*.rb']
|
14
|
+
#t.options = ['--any', '--extra', '--opts'] # optional
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => [:spec]
|
data/banken.gemspec
CHANGED
data/lib/banken.rb
CHANGED
@@ -4,67 +4,52 @@ require "active_support/core_ext/object/blank"
|
|
4
4
|
require "active_support/core_ext/module/introspection"
|
5
5
|
require "banken/version"
|
6
6
|
require "banken/error"
|
7
|
-
require "banken/
|
8
|
-
require "banken/policy_finder"
|
7
|
+
require "banken/loyalty_finder"
|
9
8
|
|
10
9
|
module Banken
|
11
10
|
extend ActiveSupport::Concern
|
12
11
|
|
13
12
|
included do
|
14
|
-
# TODO
|
15
|
-
# helper Helper if respond_to?(:helper)
|
16
13
|
if respond_to?(:helper_method)
|
17
|
-
|
18
|
-
# helper_method :banken_policy_scope
|
14
|
+
helper_method :loyalty
|
19
15
|
helper_method :banken_user
|
20
16
|
end
|
17
|
+
|
21
18
|
if respond_to?(:hide_action)
|
22
|
-
hide_action :policy_scope
|
23
19
|
hide_action :permitted_attributes
|
24
|
-
hide_action :
|
20
|
+
hide_action :loyalty
|
25
21
|
hide_action :banken_user
|
26
22
|
hide_action :skip_authorization
|
27
|
-
hide_action :skip_policy_scope
|
28
23
|
hide_action :verify_authorized
|
29
|
-
hide_action :
|
30
|
-
hide_action :policies
|
31
|
-
hide_action :policy_scopes
|
24
|
+
hide_action :loyalties
|
32
25
|
end
|
33
26
|
end
|
34
27
|
|
35
28
|
class << self
|
36
|
-
def
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def policy!(controller, user, record)
|
41
|
-
PolicyFinder.new(controller).policy!.new(user, record)
|
29
|
+
def loyalty!(controller_name, user, record=nil)
|
30
|
+
LoyaltyFinder.new(controller_name).loyalty!.new(user, record)
|
42
31
|
end
|
43
32
|
end
|
44
33
|
|
45
34
|
def authorize!(record=nil)
|
46
|
-
@
|
35
|
+
@_banken_loyalty_authorized = true
|
47
36
|
|
48
|
-
|
49
|
-
unless
|
50
|
-
raise NotAuthorizedError.new(controller: banken_controller_name,
|
37
|
+
loyalty = loyalty(record)
|
38
|
+
unless loyalty.public_send(banken_query_name)
|
39
|
+
raise NotAuthorizedError.new(controller: banken_controller_name, query: banken_query_name, loyalty: loyalty)
|
51
40
|
end
|
52
41
|
|
53
42
|
true
|
54
43
|
end
|
55
44
|
|
56
|
-
def policy_scope(scope)
|
57
|
-
@_banken_policy_scoped = true
|
58
|
-
banken_policy_scope(scope)
|
59
|
-
end
|
60
|
-
|
61
45
|
def permitted_attributes(record)
|
62
46
|
name = record.class.to_s.demodulize.underscore
|
63
|
-
params.require(name).permit(
|
47
|
+
params.require(name).permit(loyalty(record).permitted_attributes)
|
64
48
|
end
|
65
49
|
|
66
|
-
def
|
67
|
-
|
50
|
+
def loyalty(record=nil, controller_name=nil)
|
51
|
+
controller_name = banken_controller_name unless controller_name
|
52
|
+
loyalties[controller_name.to_s] ||= Banken.loyalty!(controller_name, banken_user, record)
|
68
53
|
end
|
69
54
|
|
70
55
|
def banken_user
|
@@ -72,48 +57,32 @@ module Banken
|
|
72
57
|
end
|
73
58
|
|
74
59
|
def skip_authorization
|
75
|
-
@
|
76
|
-
end
|
77
|
-
|
78
|
-
def skip_policy_scope
|
79
|
-
@_banken_policy_scoped = true
|
60
|
+
@_banken_loyalty_authorized = true
|
80
61
|
end
|
81
62
|
|
82
63
|
def verify_authorized
|
83
|
-
raise AuthorizationNotPerformedError unless
|
84
|
-
end
|
85
|
-
|
86
|
-
def verify_policy_scoped
|
87
|
-
raise PolicyScopingNotPerformedError unless banken_policy_scoped?
|
64
|
+
raise AuthorizationNotPerformedError unless banken_loyalty_authorized?
|
88
65
|
end
|
89
66
|
|
90
|
-
def
|
91
|
-
!!@
|
67
|
+
def banken_loyalty_authorized?
|
68
|
+
!!@_banken_loyalty_authorized
|
92
69
|
end
|
93
70
|
|
94
|
-
def
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
def policies
|
99
|
-
@_banken_policies ||= {}
|
100
|
-
end
|
101
|
-
|
102
|
-
def policy_scopes
|
103
|
-
@_banken_policy_scopes ||= {}
|
71
|
+
def loyalties
|
72
|
+
@_banken_loyalties ||= {}
|
104
73
|
end
|
105
74
|
|
106
75
|
private
|
107
76
|
|
108
|
-
def banken_policy_scope(scope)
|
109
|
-
policy_scopes[scope] ||= Banken.policy_scope!(banken_controller_name, banken_user, scope)
|
110
|
-
end
|
111
|
-
|
112
77
|
def banken_action_name
|
113
|
-
params[:action]
|
78
|
+
params[:action]
|
114
79
|
end
|
115
80
|
|
116
81
|
def banken_controller_name
|
117
|
-
params[:controller]
|
82
|
+
params[:controller]
|
83
|
+
end
|
84
|
+
|
85
|
+
def banken_query_name
|
86
|
+
"#{banken_action_name}?"
|
118
87
|
end
|
119
88
|
end
|
data/lib/banken/error.rb
CHANGED
@@ -2,17 +2,17 @@ module Banken
|
|
2
2
|
class Error < StandardError; end
|
3
3
|
|
4
4
|
class NotAuthorizedError < Error
|
5
|
-
attr_reader :controller, :
|
5
|
+
attr_reader :controller, :query, :loyalty
|
6
6
|
|
7
7
|
def initialize(options={})
|
8
8
|
if options.is_a? String
|
9
9
|
message = options
|
10
10
|
else
|
11
11
|
@controller = options[:controller]
|
12
|
-
@
|
13
|
-
@
|
12
|
+
@query = options[:query]
|
13
|
+
@loyalty = options[:loyalty]
|
14
14
|
|
15
|
-
message = options.fetch(:message) { "not allowed to #{
|
15
|
+
message = options.fetch(:message) { "not allowed to #{query} of #{controller} by #{loyalty.inspect}" }
|
16
16
|
end
|
17
17
|
|
18
18
|
super(message)
|
@@ -22,5 +22,5 @@ module Banken
|
|
22
22
|
class NotDefinedError < Error; end
|
23
23
|
class AuthorizationNotPerformedError < Error; end
|
24
24
|
|
25
|
-
class
|
25
|
+
class LoyaltyScopingNotPerformedError < AuthorizationNotPerformedError; end
|
26
26
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Banken
|
2
|
+
class LoyaltyFinder
|
3
|
+
SUFFIX = "Loyalty"
|
4
|
+
|
5
|
+
attr_reader :controller
|
6
|
+
|
7
|
+
def initialize(controller)
|
8
|
+
@controller = controller.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
def loyalty
|
12
|
+
loyalty_name.constantize
|
13
|
+
rescue NameError
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def loyalty!
|
18
|
+
raise NotDefinedError, "unable to find loyalty of nil" unless controller
|
19
|
+
loyalty || raise(NotDefinedError, "unable to find loyalty `#{loyalty_name}` for `#{controller}`")
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def loyalty_name
|
25
|
+
"#{controller.camelize}#{SUFFIX}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/banken/version.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
Description:
|
2
|
-
Generates an application
|
2
|
+
Generates an application loyalty as a starting point for your application.
|
@@ -3,8 +3,8 @@ module Banken
|
|
3
3
|
class InstallGenerator < ::Rails::Generators::Base
|
4
4
|
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
5
5
|
|
6
|
-
def
|
7
|
-
template '
|
6
|
+
def copy_application_loyalty
|
7
|
+
template 'application_loyalty.rb', 'app/loyalties/application_loyalty.rb'
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
data/lib/generators/banken/install/templates/{application_policy.rb → application_loyalty.rb}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class ApplicationLoyalty
|
2
2
|
attr_reader :user, :record
|
3
3
|
|
4
4
|
def initialize(user, record)
|
@@ -11,7 +11,7 @@ class ApplicationPolicy
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def show?
|
14
|
-
|
14
|
+
false
|
15
15
|
end
|
16
16
|
|
17
17
|
def create?
|
@@ -33,21 +33,4 @@ class ApplicationPolicy
|
|
33
33
|
def destroy?
|
34
34
|
false
|
35
35
|
end
|
36
|
-
|
37
|
-
def scope
|
38
|
-
Scope.new(user, record.class).resolve
|
39
|
-
end
|
40
|
-
|
41
|
-
class Scope
|
42
|
-
attr_reader :user, :scope
|
43
|
-
|
44
|
-
def initialize(user, scope)
|
45
|
-
@user = user
|
46
|
-
@scope = scope
|
47
|
-
end
|
48
|
-
|
49
|
-
def resolve
|
50
|
-
scope
|
51
|
-
end
|
52
|
-
end
|
53
36
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Banken
|
2
|
+
module Generators
|
3
|
+
class LoyaltyGenerator < ::Rails::Generators::NamedBase
|
4
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
5
|
+
|
6
|
+
def create_loyalty
|
7
|
+
template 'loyalty.rb', File.join('app/loyalties', class_path, "#{file_name}_loyalty.rb")
|
8
|
+
end
|
9
|
+
|
10
|
+
hook_for :test_framework
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: banken
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kyuden
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
description: Object oriented authorization like pundit for Rails applications.
|
112
126
|
email:
|
113
127
|
- msmsms.um@gmail.com
|
@@ -116,6 +130,8 @@ extensions: []
|
|
116
130
|
extra_rdoc_files: []
|
117
131
|
files:
|
118
132
|
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- ".travis.yml"
|
119
135
|
- CODE_OF_CONDUCT.md
|
120
136
|
- Gemfile
|
121
137
|
- LICENSE.txt
|
@@ -124,15 +140,14 @@ files:
|
|
124
140
|
- banken.gemspec
|
125
141
|
- lib/banken.rb
|
126
142
|
- lib/banken/error.rb
|
127
|
-
- lib/banken/
|
128
|
-
- lib/banken/policy_finder.rb
|
143
|
+
- lib/banken/loyalty_finder.rb
|
129
144
|
- lib/banken/version.rb
|
130
145
|
- lib/generators/banken/install/USAGE
|
131
146
|
- lib/generators/banken/install/install_generator.rb
|
132
|
-
- lib/generators/banken/install/templates/
|
133
|
-
- lib/generators/banken/
|
134
|
-
- lib/generators/banken/
|
135
|
-
- lib/generators/banken/
|
147
|
+
- lib/generators/banken/install/templates/application_loyalty.rb
|
148
|
+
- lib/generators/banken/loyalty/USAGE
|
149
|
+
- lib/generators/banken/loyalty/loyalty_generator.rb
|
150
|
+
- lib/generators/banken/loyalty/templates/loyalty.rb
|
136
151
|
homepage: https://github.com/kyuden/banken
|
137
152
|
licenses:
|
138
153
|
- MIT
|
@@ -158,3 +173,4 @@ signing_key:
|
|
158
173
|
specification_version: 4
|
159
174
|
summary: OO authorization for Rails.
|
160
175
|
test_files: []
|
176
|
+
has_rdoc:
|
data/lib/banken/helper.rb
DELETED
data/lib/banken/policy_finder.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
module Banken
|
2
|
-
class PolicyFinder
|
3
|
-
SUFFIX = "Policy"
|
4
|
-
|
5
|
-
attr_reader :controller
|
6
|
-
|
7
|
-
def initialize(controller)
|
8
|
-
@controller = controller
|
9
|
-
end
|
10
|
-
|
11
|
-
def scope
|
12
|
-
policy::Scope if policy
|
13
|
-
rescue NameError
|
14
|
-
nil
|
15
|
-
end
|
16
|
-
|
17
|
-
def policy
|
18
|
-
klass = find
|
19
|
-
klass = klass.constantize if klass.is_a?(String)
|
20
|
-
klass
|
21
|
-
rescue NameError
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def scope!
|
26
|
-
raise NotDefinedError, "unable to find policy scope of nil" unless controller
|
27
|
-
scope || raise(NotDefinedError, "unable to find scope `#{find}::Scope` for `#{controller}`")
|
28
|
-
end
|
29
|
-
|
30
|
-
def policy!
|
31
|
-
raise NotDefinedError, "unable to find policy of nil" unless controller
|
32
|
-
policy || raise(NotDefinedError, "unable to find policy `#{find}` for `#{controller}`")
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def find
|
38
|
-
"#{controller.camelize}#{SUFFIX}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module Banken
|
2
|
-
module Generators
|
3
|
-
class PolicyGenerator < ::Rails::Generators::NamedBase
|
4
|
-
source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
|
5
|
-
|
6
|
-
def create_policy
|
7
|
-
template 'policy.rb', File.join('app/policies', class_path, "#{file_name}_policy.rb")
|
8
|
-
end
|
9
|
-
|
10
|
-
hook_for :test_framework
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|