authority 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +6 -0
- data/Gemfile +1 -1
- data/README.markdown +27 -11
- data/TODO.markdown +5 -6
- data/lib/authority.rb +12 -21
- data/lib/authority/abilities.rb +3 -1
- data/lib/authority/controller.rb +31 -22
- data/lib/authority/security_violation.rb +15 -0
- data/lib/authority/user_abilities.rb +4 -0
- data/lib/authority/version.rb +1 -1
- data/spec/authority/abilities_spec.rb +76 -61
- data/spec/authority/authorizer_spec.rb +43 -39
- data/spec/authority/configuration_spec.rb +11 -11
- data/spec/authority/controller_spec.rb +151 -86
- data/spec/authority/integration_spec.rb +34 -29
- data/spec/authority/user_abilities_spec.rb +30 -20
- data/spec/authority_spec.rb +37 -41
- data/spec/spec_helper.rb +1 -0
- data/spec/support/{example_model.rb → example_classes.rb} +5 -1
- metadata +6 -7
- data/spec/support/example_controllers.rb +0 -22
- data/spec/support/user.rb +0 -3
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'support/
|
3
|
-
require 'support/user'
|
2
|
+
require 'support/example_classes'
|
4
3
|
|
5
4
|
describe "integration from user through model to authorizer" do
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
6
|
+
let(:user) { ExampleUser.new }
|
7
|
+
let(:resource_class) { ExampleResource }
|
8
|
+
let(:resource_instance) { resource_class.new }
|
11
9
|
|
12
10
|
describe "class methods" do
|
13
11
|
|
@@ -16,20 +14,24 @@ describe "integration from user through model to authorizer" do
|
|
16
14
|
adjective = Authority.abilities[verb]
|
17
15
|
adjective_method = "#{adjective}_by?"
|
18
16
|
|
19
|
-
describe "
|
17
|
+
describe "#{adjective_method}" do
|
18
|
+
|
19
|
+
describe "if given an options hash" do
|
20
|
+
|
21
|
+
it "delegates `#{adjective_method}` to its authorizer class, passing the options" do
|
22
|
+
resource_class.authorizer.should_receive(adjective_method).with(user, :lacking => 'nothing')
|
23
|
+
user.send(verb_method, resource_class, :lacking => 'nothing')
|
24
|
+
end
|
20
25
|
|
21
|
-
it "should delegate `#{adjective_method}` to its authorizer class, passing the options" do
|
22
|
-
ExampleModel.authorizer.should_receive(adjective_method).with(@user, :lacking => 'nothing')
|
23
|
-
@user.send(verb_method, ExampleModel, :lacking => 'nothing')
|
24
26
|
end
|
25
27
|
|
26
|
-
|
28
|
+
describe "if not given an options hash" do
|
27
29
|
|
28
|
-
|
30
|
+
it "delegates `#{adjective_method}` to its authorizer class, passing no options" do
|
31
|
+
resource_class.authorizer.should_receive(adjective_method).with(user)
|
32
|
+
user.send(verb_method, resource_instance)
|
33
|
+
end
|
29
34
|
|
30
|
-
it "should delegate `#{adjective_method}` to its authorizer class, passing no options" do
|
31
|
-
ExampleModel.authorizer.should_receive(adjective_method).with(@user)
|
32
|
-
@user.send(verb_method, @example_model)
|
33
35
|
end
|
34
36
|
|
35
37
|
end
|
@@ -40,11 +42,10 @@ describe "integration from user through model to authorizer" do
|
|
40
42
|
|
41
43
|
describe "instance methods" do
|
42
44
|
|
45
|
+
let!(:authorizer_instance) { resource_class.authorizer.new(resource_instance) }
|
46
|
+
|
43
47
|
before :each do
|
44
|
-
|
45
|
-
@example_model = ExampleModel.new
|
46
|
-
@authorizer = ExampleModel.authorizer.new(@example_model)
|
47
|
-
ExampleModel.authorizer.stub(:new).and_return(@authorizer)
|
48
|
+
resource_class.authorizer.stub(:new).and_return(authorizer_instance)
|
48
49
|
end
|
49
50
|
|
50
51
|
Authority.verbs.each do |verb|
|
@@ -52,20 +53,24 @@ describe "integration from user through model to authorizer" do
|
|
52
53
|
adjective = Authority.abilities[verb]
|
53
54
|
adjective_method = "#{adjective}_by?"
|
54
55
|
|
55
|
-
describe "
|
56
|
+
describe "#{adjective_method}" do
|
57
|
+
|
58
|
+
describe "if given an options hash" do
|
59
|
+
|
60
|
+
it "delegates `#{adjective_method}` to a new authorizer instance, passing the options" do
|
61
|
+
authorizer_instance.should_receive(adjective_method).with(user, :consistency => 'mushy')
|
62
|
+
user.send(verb_method, resource_instance, :consistency => 'mushy')
|
63
|
+
end
|
56
64
|
|
57
|
-
it "should delegate `#{adjective_method}` to a new authorizer instance, passing the options" do
|
58
|
-
@authorizer.should_receive(adjective_method).with(@user, :consistency => 'mushy')
|
59
|
-
@user.send(verb_method, @example_model, :consistency => 'mushy')
|
60
65
|
end
|
61
66
|
|
62
|
-
|
67
|
+
describe "if not given an options hash" do
|
68
|
+
|
69
|
+
it "delegates `#{adjective_method}` to a new authorizer instance, passing no options" do
|
70
|
+
authorizer_instance.should_receive(adjective_method).with(user)
|
71
|
+
user.send(verb_method, resource_instance)
|
72
|
+
end
|
63
73
|
|
64
|
-
describe "if not given an options hash" do
|
65
|
-
|
66
|
-
it "should delegate `#{adjective_method}` to a new authorizer instance, passing no options" do
|
67
|
-
@authorizer.should_receive(adjective_method).with(@user)
|
68
|
-
@user.send(verb_method, @example_model)
|
69
74
|
end
|
70
75
|
|
71
76
|
end
|
@@ -1,39 +1,49 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'support/
|
3
|
-
require 'support/user'
|
2
|
+
require 'support/example_classes'
|
4
3
|
|
5
4
|
describe Authority::UserAbilities do
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
@user = User.new
|
10
|
-
end
|
6
|
+
let(:resource_instance) { ExampleResource.new }
|
7
|
+
let(:user) { ExampleUser.new }
|
11
8
|
|
12
|
-
|
13
|
-
method_name = "can_#{verb}?"
|
9
|
+
describe "using `can_{verb}?` methods to check permissions on a resource" do
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
Authority.verbs.each do |verb|
|
12
|
+
method_name = "can_#{verb}?"
|
13
|
+
|
14
|
+
it "defines the `#{method_name}` method" do
|
15
|
+
expect(user).to respond_to(method_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "if given options" do
|
18
19
|
|
19
|
-
|
20
|
+
it "delegates the authorization check to the resource, passing the options" do
|
21
|
+
resource_instance.should_receive("#{Authority.abilities[verb]}_by?").with(user, :size => 'wee')
|
22
|
+
user.send(method_name, resource_instance, :size => 'wee')
|
23
|
+
end
|
20
24
|
|
21
|
-
it "should delegate the authorization check to the resource, passing the options" do
|
22
|
-
@example_model.should_receive("#{Authority.abilities[verb]}_by?").with(@user, :size => 'wee')
|
23
|
-
@user.send(method_name, @example_model, :size => 'wee')
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
+
describe "if not given options" do
|
27
28
|
|
28
|
-
|
29
|
+
it "delegates the authorization check to the resource, passing no options" do
|
30
|
+
resource_instance.should_receive("#{Authority.abilities[verb]}_by?").with(user)
|
31
|
+
user.send(method_name, resource_instance)
|
32
|
+
end
|
29
33
|
|
30
|
-
it "should delegate the authorization check to the resource, passing no options" do
|
31
|
-
@example_model.should_receive("#{Authority.abilities[verb]}_by?").with(@user)
|
32
|
-
@user.send(method_name, @example_model)
|
33
34
|
end
|
34
35
|
|
35
36
|
end
|
36
37
|
|
37
38
|
end
|
38
39
|
|
40
|
+
describe "using `can?` for non-resource-specific checks" do
|
41
|
+
|
42
|
+
it "checks with ApplicationAuthorizer" do
|
43
|
+
ApplicationAuthorizer.should_receive(:can_mimic_lemurs?).with(user)
|
44
|
+
user.can?(:mimic_lemurs)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
39
49
|
end
|
data/spec/authority_spec.rb
CHANGED
@@ -1,38 +1,37 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'support/
|
3
|
-
require 'support/user'
|
2
|
+
require 'support/example_classes'
|
4
3
|
|
5
4
|
describe Authority do
|
6
5
|
|
7
|
-
it "
|
8
|
-
Authority.abilities.
|
6
|
+
it "has a default list of abilities" do
|
7
|
+
expect(Authority.abilities).to be_a(Hash)
|
9
8
|
end
|
10
9
|
|
11
|
-
it "
|
10
|
+
it "does not allow modification of the Authority.abilities hash directly" do
|
12
11
|
expect { Authority.abilities[:exchange] = 'fungible' }.to raise_error(
|
13
12
|
StandardError, /modify frozen/
|
14
13
|
) # can't modify frozen hash - exact error type and message depends on Ruby version
|
15
14
|
end
|
16
15
|
|
17
|
-
it "
|
18
|
-
Authority.verbs.map(&:to_s).sort.
|
16
|
+
it "has a convenience accessor for the ability verbs" do
|
17
|
+
expect(Authority.verbs.map(&:to_s).sort).to eq(%w[create delete read update])
|
19
18
|
end
|
20
19
|
|
21
|
-
it "
|
22
|
-
Authority.adjectives.sort.
|
20
|
+
it "has a convenience accessor for the ability adjectives" do
|
21
|
+
expect(Authority.adjectives.sort).to eq(%w[creatable deletable readable updatable])
|
23
22
|
end
|
24
23
|
|
25
24
|
describe "configuring Authority" do
|
26
25
|
|
27
|
-
it "
|
28
|
-
Authority.
|
26
|
+
it "has a configuration accessor" do
|
27
|
+
expect(Authority).to respond_to(:configuration)
|
29
28
|
end
|
30
29
|
|
31
|
-
it "
|
32
|
-
Authority.
|
30
|
+
it "has a `configure` method" do
|
31
|
+
expect(Authority).to respond_to(:configure)
|
33
32
|
end
|
34
33
|
|
35
|
-
it "
|
34
|
+
it "requires the remainder of library internals after configuration" do
|
36
35
|
Authority.should_receive(:require_authority_internals!)
|
37
36
|
Authority.configure
|
38
37
|
end
|
@@ -40,62 +39,59 @@ describe Authority do
|
|
40
39
|
|
41
40
|
describe "enforcement" do
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
42
|
+
let(:user) { ExampleUser.new }
|
43
|
+
let(:resource_class) { ExampleResource }
|
46
44
|
|
47
45
|
describe "if given options" do
|
48
46
|
|
49
|
-
it "
|
47
|
+
it "checks the user's authorization, passing along the options" do
|
50
48
|
options = { :for => 'context' }
|
51
|
-
|
52
|
-
Authority.enforce(:delete,
|
49
|
+
user.should_receive(:can_delete?).with(resource_class, options).and_return(true)
|
50
|
+
Authority.enforce(:delete, resource_class, user, options)
|
53
51
|
end
|
54
52
|
|
55
53
|
end
|
56
54
|
|
57
55
|
describe "if not given options" do
|
58
56
|
|
59
|
-
it "
|
60
|
-
|
61
|
-
Authority.enforce(:delete,
|
57
|
+
it "checks the user's authorization, passing no options" do
|
58
|
+
user.should_receive(:can_delete?).with(resource_class).and_return(true)
|
59
|
+
Authority.enforce(:delete, resource_class, user)
|
62
60
|
end
|
63
61
|
|
64
62
|
end
|
65
63
|
|
66
|
-
it "
|
67
|
-
expect { Authority.enforce(:update,
|
64
|
+
it "raises a SecurityViolation if the action is unauthorized" do
|
65
|
+
expect { Authority.enforce(:update, resource_class, user) }.to raise_error(Authority::SecurityViolation)
|
68
66
|
end
|
69
67
|
|
70
|
-
it "
|
71
|
-
expect { Authority.enforce(:read,
|
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(Authority::SecurityViolation)
|
72
70
|
end
|
73
71
|
|
74
72
|
end
|
75
73
|
|
76
74
|
describe Authority::SecurityViolation do
|
77
75
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
@security_violation = Authority::SecurityViolation.new(@user, @action, @resource)
|
83
|
-
end
|
76
|
+
let(:user) { :"Cap'n Ned" }
|
77
|
+
let(:action) { :keelhaul }
|
78
|
+
let(:resource) { :houseplant }
|
79
|
+
let(:security_violation) { Authority::SecurityViolation.new(user, action, resource) }
|
84
80
|
|
85
|
-
it "
|
86
|
-
|
81
|
+
it "has a reader for the user" do
|
82
|
+
expect(security_violation.user).to eq(user)
|
87
83
|
end
|
88
84
|
|
89
|
-
it "
|
90
|
-
|
85
|
+
it "has a reader for the action" do
|
86
|
+
expect(security_violation.action).to eq(action)
|
91
87
|
end
|
92
88
|
|
93
|
-
it "
|
94
|
-
|
89
|
+
it "has a reader for the resource" do
|
90
|
+
expect(security_violation.resource).to eq(resource)
|
95
91
|
end
|
96
92
|
|
97
|
-
it "
|
98
|
-
|
93
|
+
it "uses them all in its message" do
|
94
|
+
expect(security_violation.message).to eq("#{user} is not authorized to #{action} this resource: #{resource}")
|
99
95
|
end
|
100
96
|
|
101
97
|
end
|
data/spec/spec_helper.rb
CHANGED
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.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-12-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &69990830 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
version: 3.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *69990830
|
26
26
|
description: Authority helps you authorize actions in your Rails app. It's ORM-neutral
|
27
27
|
and has very little fancy syntax; just group your models under one or more Authorizer
|
28
28
|
classes and write plain Ruby methods on them.
|
@@ -53,6 +53,7 @@ files:
|
|
53
53
|
- lib/authority/configuration.rb
|
54
54
|
- lib/authority/controller.rb
|
55
55
|
- lib/authority/railtie.rb
|
56
|
+
- lib/authority/security_violation.rb
|
56
57
|
- lib/authority/user_abilities.rb
|
57
58
|
- lib/authority/version.rb
|
58
59
|
- lib/generators/authority/install_generator.rb
|
@@ -67,10 +68,8 @@ files:
|
|
67
68
|
- spec/authority/user_abilities_spec.rb
|
68
69
|
- spec/authority_spec.rb
|
69
70
|
- spec/spec_helper.rb
|
70
|
-
- spec/support/
|
71
|
-
- spec/support/example_model.rb
|
71
|
+
- spec/support/example_classes.rb
|
72
72
|
- spec/support/mock_rails.rb
|
73
|
-
- spec/support/user.rb
|
74
73
|
homepage: https://github.com/nathanl/authority
|
75
74
|
licenses: []
|
76
75
|
post_install_message:
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module MockController
|
2
|
-
def rescue_from(*args) ; end
|
3
|
-
def before_filter(*args) ; end
|
4
|
-
end
|
5
|
-
|
6
|
-
# this controller will have `authority_actions_for` called on it
|
7
|
-
class ExampleController
|
8
|
-
extend MockController
|
9
|
-
include Authority::Controller
|
10
|
-
end
|
11
|
-
|
12
|
-
class DummyController < ExampleController
|
13
|
-
end
|
14
|
-
|
15
|
-
class InstanceController < ExampleController
|
16
|
-
end
|
17
|
-
|
18
|
-
# this controller will not have `authority_actions_for` called on it but will
|
19
|
-
# have `authority_action_for` called on it
|
20
|
-
class SampleController
|
21
|
-
extend MockController
|
22
|
-
end
|
data/spec/support/user.rb
DELETED