authority 2.7.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.markdown +4 -0
- data/CONTRIBUTING.markdown +27 -0
- data/README.markdown +21 -1
- data/gemfiles/4.0.gemfile +2 -2
- data/lib/authority.rb +1 -0
- data/lib/authority/controller.rb +26 -3
- data/lib/authority/version.rb +1 -1
- data/spec/authority/controller_spec.rb +65 -4
- data/spec/authority_spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9206ed88d49590c996639a19863a6d31dfd96717
|
4
|
+
data.tar.gz: e17aef04639c0fab82bcb7b221167f5b066eb12d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6fb759f6188d224fe7a7a7a029a605bbe595f8ad344c9e3705d9e7d0e460b86ee5d0fb20e4d529cf22f3685f1f0c477e309301acdbde5456d9dcad5f4a32584
|
7
|
+
data.tar.gz: e762ecc99ebd2632b01a45b88ffacc19196af9eb90acb72b6063b5cef08122ae74e7d17b3921098f13cede871a6f01e2dec174aeb9e608dc0c080d37a88b6297
|
data/.travis.yml
CHANGED
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
Authority does its best to use [semantic versioning](http://semver.org).
|
4
4
|
|
5
|
+
## v2.8.0
|
6
|
+
|
7
|
+
New controller method `ensure_authorization_performed`, thanks to [Igor Davydov](https://github.com/div).
|
8
|
+
|
5
9
|
## 2.7.0
|
6
10
|
|
7
11
|
Allows setting authorizer by class (`authorizer = FooAuthorizer`) as well as by name (`authorizer_name = 'FooAuthorizer'`), thanks to [mguymon](https://github.com/mguymon)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
## I love you
|
4
|
+
|
5
|
+
Thanks so much for wanting to contribute to Authority! You are wonderful and I love you.
|
6
|
+
|
7
|
+
## New feature? Probably not.
|
8
|
+
|
9
|
+
Authority's default answer to new features is "no".
|
10
|
+
|
11
|
+
Every feature increases the complexity of Authority. It will need documentation, tests, and maintenance. Its interactions with other features will forever need to be considered. More code means more chances for bugs.
|
12
|
+
|
13
|
+
Every feature makes Authority harder to understand for users and maintainers.
|
14
|
+
|
15
|
+
A feature **must clearly benefit most users** to justify these costs.
|
16
|
+
|
17
|
+
It's hard to reject pull requests. It feels like rejecting the requester personally. But the silent participants in the conversation must be considered, too: all the other users and maintainers. Every user of Authority has entrusted us to put code into their system. **We owe it to them not to add needless complexity**.
|
18
|
+
|
19
|
+
If your feature seems worth the tradeoff, great! But be aware that the bar is high.
|
20
|
+
|
21
|
+
## Bugfixes welcome
|
22
|
+
|
23
|
+
Bugfixes, updating deprecated method calls, etc are always welcome.
|
24
|
+
|
25
|
+
## Tests and readability
|
26
|
+
|
27
|
+
No untested code will be accepted. No confusing code will be accepted. (Yes, that's subjective.) Make it as readable as you possibly can.
|
data/README.markdown
CHANGED
@@ -6,8 +6,10 @@ Authority will work fine with a standalone app or a single sign-on system. You c
|
|
6
6
|
|
7
7
|
If you're using it with Rails controllers, it requires that you already have some kind of user object in your application, accessible via a method like `current_user` (configurable).
|
8
8
|
|
9
|
+
[![Gem Version](https://badge.fury.io/rb/authority.png)](https://rubygems.org/gems/searchlight)
|
9
10
|
[![Build Status](https://secure.travis-ci.org/nathanl/authority.png?branch=master)](http://travis-ci.org/nathanl/authority)
|
10
11
|
[![Code Climate](https://codeclimate.com/github/nathanl/authority.png)](https://codeclimate.com/github/nathanl/authority)
|
12
|
+
[![Dependency Status](https://gemnasium.com/nathanl/authority.png)](https://gemnasium.com/nathanl/authority)
|
11
13
|
|
12
14
|
## Contents
|
13
15
|
|
@@ -380,7 +382,7 @@ class LlamasController < ApplicationController
|
|
380
382
|
end
|
381
383
|
```
|
382
384
|
|
383
|
-
|
385
|
+
If you have a controller that dynamically determines the class it's working with, you can pass the name of a controller instance method to `authorize_actions_for` instead of a class, and the class will be looked up when a request is made.
|
384
386
|
|
385
387
|
```ruby
|
386
388
|
class LlamasController < ApplicationController
|
@@ -388,11 +390,29 @@ class LlamasController < ApplicationController
|
|
388
390
|
authorize_actions_for :llama_class
|
389
391
|
|
390
392
|
def llama_class
|
393
|
+
# In a real application, you would choose your llama class
|
394
|
+
# much more carefully
|
391
395
|
[StandardLlama, LludicrousLlama].sample
|
392
396
|
end
|
393
397
|
end
|
394
398
|
```
|
395
399
|
|
400
|
+
Finally, you can enforce that every controller action runs an authorization check using the class method `ensure_authorization_performed`, which sets up an `after_filter` to raise an exception if it wasn't. Any `only` or `except` arguments will be passed to `after_filter`. You can also use `if` or `unless` to specify the name of a controller method which determines whether it's necessary.
|
401
|
+
|
402
|
+
Since this runs in an `after_filter`, it obviously doesn't prevent the action, it just alerts you that no authorization was performed. Therefore, it's most useful in development. An example usage might be:
|
403
|
+
|
404
|
+
```ruby
|
405
|
+
class ApplicationController < ActionController::Base
|
406
|
+
ensure_authorization_performed :except => [:index, :search], :if => :auditing_security?, :unless => :devise_controller?
|
407
|
+
|
408
|
+
def auditing_security?
|
409
|
+
Rails.env != 'production'
|
410
|
+
end
|
411
|
+
end
|
412
|
+
```
|
413
|
+
|
414
|
+
If you want a skippable filter, you can roll your own using the instance method, also called `ensure_authorization_performed`.
|
415
|
+
|
396
416
|
<a name="views">
|
397
417
|
### Views
|
398
418
|
|
data/gemfiles/4.0.gemfile
CHANGED
data/lib/authority.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
require 'active_support/core_ext/class/attribute'
|
3
3
|
require 'active_support/core_ext/hash/keys'
|
4
|
+
require 'active_support/core_ext/hash/slice'
|
4
5
|
require 'active_support/core_ext/string/inflections'
|
5
6
|
require 'active_support/rescuable'
|
6
7
|
require 'forwardable'
|
data/lib/authority/controller.rb
CHANGED
@@ -7,7 +7,7 @@ module Authority
|
|
7
7
|
|
8
8
|
def self.security_violation_callback
|
9
9
|
Proc.new do |exception|
|
10
|
-
# Through the magic of
|
10
|
+
# Through the magic of `instance_exec` `ActionController::Base#rescue_from`
|
11
11
|
# can call this proc and make `self` the actual controller instance
|
12
12
|
self.send(Authority.configuration.security_violation_handler, exception)
|
13
13
|
end
|
@@ -18,6 +18,19 @@ module Authority
|
|
18
18
|
class_attribute :authority_resource, :instance_reader => false
|
19
19
|
end
|
20
20
|
|
21
|
+
attr_writer :authorization_performed
|
22
|
+
|
23
|
+
def authorization_performed?
|
24
|
+
!!@authorization_performed
|
25
|
+
end
|
26
|
+
|
27
|
+
def ensure_authorization_performed(options = {})
|
28
|
+
return if authorization_performed?
|
29
|
+
return if options[:if] && !send(options[:if])
|
30
|
+
return if options[:unless] && send(options[:unless])
|
31
|
+
raise AuthorizationNotPerformed, "No authorization was performed for #{self.class.to_s}##{self.action_name}"
|
32
|
+
end
|
33
|
+
|
21
34
|
module ClassMethods
|
22
35
|
|
23
36
|
# Sets up before_filter to ensure user is allowed to perform a given controller action
|
@@ -49,6 +62,13 @@ module Authority
|
|
49
62
|
authority_actions(action_map)
|
50
63
|
end
|
51
64
|
|
65
|
+
# Convenience wrapper for instance method
|
66
|
+
def ensure_authorization_performed(options = {})
|
67
|
+
after_filter(options.slice(:only, :except)) do |controller_instance|
|
68
|
+
controller_instance.ensure_authorization_performed(options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
52
72
|
# The controller action to authority action map used for determining
|
53
73
|
# which Rails actions map to which authority actions (ex: index to read)
|
54
74
|
#
|
@@ -74,7 +94,9 @@ module Authority
|
|
74
94
|
if authority_action.nil?
|
75
95
|
raise MissingAction.new("No authority action defined for #{action_name}")
|
76
96
|
end
|
97
|
+
|
77
98
|
Authority.enforce(authority_action, authority_resource, authority_user, *options)
|
99
|
+
self.authorization_performed = true
|
78
100
|
end
|
79
101
|
|
80
102
|
# Renders a static file to minimize the chances of further errors.
|
@@ -112,7 +134,8 @@ module Authority
|
|
112
134
|
send(Authority.configuration.user_method)
|
113
135
|
end
|
114
136
|
|
115
|
-
class MissingAction
|
116
|
-
class MissingResource
|
137
|
+
class MissingAction < StandardError ; end
|
138
|
+
class MissingResource < StandardError ; end
|
139
|
+
class AuthorizationNotPerformed < StandardError ; end
|
117
140
|
end
|
118
141
|
end
|
data/lib/authority/version.rb
CHANGED
@@ -49,15 +49,15 @@ describe Authority::Controller do
|
|
49
49
|
controller_instance = controller_class.new
|
50
50
|
# If a callback is passed to a controller's `rescue_from` method as the value for
|
51
51
|
# the `with` option (like `SomeController.rescue_from FooException, :with => some_callback`),
|
52
|
-
# Rails will use
|
52
|
+
# Rails will use `instance_exec` to ensure that when the proc refers to
|
53
53
|
# `self`, it will be the controller, not the proc itself.
|
54
54
|
# I need this callback's `self` to be the controller for the purposes of
|
55
55
|
# this test, so I'm stealing that behavior.
|
56
|
-
callback = Authority::Controller.security_violation_callback.bind(controller_instance)
|
57
56
|
|
58
57
|
Authority.configuration.security_violation_handler = :fire_ze_missiles
|
59
58
|
controller_instance.should_receive(:fire_ze_missiles).with(fake_exception)
|
60
|
-
|
59
|
+
controller_instance.instance_exec(fake_exception, &Authority::Controller.security_violation_callback)
|
60
|
+
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -155,6 +155,61 @@ describe Authority::Controller do
|
|
155
155
|
|
156
156
|
end
|
157
157
|
|
158
|
+
describe "ensure_authorization_performed" do
|
159
|
+
|
160
|
+
let(:controller_instance) { controller_class.new }
|
161
|
+
|
162
|
+
before(:each) do
|
163
|
+
controller_instance.stub(:class).and_return("FooController")
|
164
|
+
controller_instance.stub(:action_name).and_return(:bar)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "sets up an after_filter, passing the options it was given" do
|
168
|
+
filter_options = {:only => [:show, :edit, :update]}
|
169
|
+
controller_class.should_receive(:after_filter).with(filter_options)
|
170
|
+
controller_class.ensure_authorization_performed(filter_options)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "triggers AuthorizationNotPerformed in after filter" do
|
174
|
+
controller_class.stub(:after_filter).and_yield(controller_instance)
|
175
|
+
lambda {
|
176
|
+
controller_class.ensure_authorization_performed
|
177
|
+
}.should raise_error(Authority::Controller::AuthorizationNotPerformed)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "AuthorizationNotPerformed error has meaningful message" do
|
181
|
+
controller_class.stub(:after_filter).and_yield(controller_instance)
|
182
|
+
lambda {
|
183
|
+
controller_class.ensure_authorization_performed
|
184
|
+
}.should raise_error("No authorization was performed for FooController#bar")
|
185
|
+
end
|
186
|
+
|
187
|
+
it "does not trigger AuthorizationNotPerformed when :if is false" do
|
188
|
+
controller_instance.stub(:authorize?) { false }
|
189
|
+
controller_class.stub(:after_filter).with({}).and_yield(controller_instance)
|
190
|
+
lambda {
|
191
|
+
controller_class.ensure_authorization_performed(:if => :authorize?)
|
192
|
+
}.should_not raise_error()
|
193
|
+
end
|
194
|
+
|
195
|
+
it "does not trigger AuthorizationNotPerformed when :unless is true" do
|
196
|
+
controller_instance.stub(:skip_authorization?) { true }
|
197
|
+
controller_class.stub(:after_filter).with({}).and_yield(controller_instance)
|
198
|
+
lambda {
|
199
|
+
controller_class.ensure_authorization_performed(:unless => :skip_authorization?)
|
200
|
+
}.should_not raise_error()
|
201
|
+
end
|
202
|
+
|
203
|
+
it "does not raise error when #authorization_performed is true" do
|
204
|
+
controller_instance.authorization_performed = true
|
205
|
+
controller_class.stub(:after_filter).with({}).and_yield(controller_instance)
|
206
|
+
lambda {
|
207
|
+
controller_class.ensure_authorization_performed
|
208
|
+
}.should_not raise_error()
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
158
213
|
end
|
159
214
|
|
160
215
|
describe "instance methods" do
|
@@ -244,6 +299,12 @@ describe Authority::Controller do
|
|
244
299
|
controller_instance.send(:authorize_action_for, resource_class, options)
|
245
300
|
end
|
246
301
|
|
302
|
+
it "sets correct authorization flag" do
|
303
|
+
Authority.stub(:enforce)
|
304
|
+
controller_instance.send(:authorize_action_for, resource_class)
|
305
|
+
controller_instance.authorization_performed?.should be_true
|
306
|
+
end
|
307
|
+
|
247
308
|
end
|
248
309
|
|
249
310
|
describe "authority_user" do
|
@@ -257,7 +318,7 @@ describe Authority::Controller do
|
|
257
318
|
|
258
319
|
describe "authority_forbidden action" do
|
259
320
|
|
260
|
-
let(:mock_error) {
|
321
|
+
let(:mock_error) { double(:message => 'oh noes! an error!') }
|
261
322
|
|
262
323
|
it "logs an error" do
|
263
324
|
Authority.logger.should_receive(:warn)
|
data/spec/authority_spec.rb
CHANGED
@@ -66,7 +66,7 @@ describe Authority do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it "doesn't raise a SecurityViolation if the action is authorized" do
|
69
|
-
expect { Authority.enforce(:read, resource_class, user) }.not_to raise_error(
|
69
|
+
expect { Authority.enforce(:read, resource_class, user) }.not_to raise_error()
|
70
70
|
end
|
71
71
|
|
72
72
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authority
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Long
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-09-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- .rspec
|
54
54
|
- .travis.yml
|
55
55
|
- CHANGELOG.markdown
|
56
|
+
- CONTRIBUTING.markdown
|
56
57
|
- Gemfile
|
57
58
|
- LICENSE
|
58
59
|
- README.markdown
|