authorizy 0.1.0 → 0.3.0
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/CHANGELOG.md +41 -0
- data/README.md +119 -27
- data/lib/authorizy/base_cop.rb +3 -3
- data/lib/authorizy/config.rb +4 -3
- data/lib/authorizy/core.rb +34 -21
- data/lib/authorizy/expander.rb +15 -16
- data/lib/authorizy/extension.rb +11 -4
- data/lib/authorizy/rspec.rb +44 -0
- data/lib/authorizy/version.rb +1 -1
- data/spec/authorizy/base_cop/access_question_spec.rb +2 -1
- data/spec/authorizy/config/aliases_spec.rb +2 -2
- data/spec/authorizy/config/cop_spec.rb +2 -2
- data/spec/authorizy/config/current_user_spec.rb +4 -6
- data/spec/authorizy/config/dependencies_spec.rb +2 -2
- data/spec/authorizy/config/field_spec.rb +29 -0
- data/spec/authorizy/config/initialize_spec.rb +1 -1
- data/spec/authorizy/config/redirect_url_spec.rb +4 -4
- data/spec/authorizy/cop/controller_spec.rb +1 -2
- data/spec/authorizy/cop/model_spec.rb +7 -6
- data/spec/authorizy/cop/namespaced_controller_spec.rb +1 -2
- data/spec/authorizy/core/access_spec.rb +119 -75
- data/spec/authorizy/expander/expand_spec.rb +41 -46
- data/spec/authorizy/extension/authorizy_question_spec.rb +14 -10
- data/spec/authorizy/extension/authorizy_spec.rb +15 -3
- data/spec/authorizy/rspec_spec.rb +11 -0
- data/spec/common_helper.rb +2 -0
- data/spec/spec_helper.rb +3 -3
- data/spec/support/coverage.rb +5 -1
- data/spec/support/models/authorizy_cop.rb +5 -5
- data/spec/support/schema.rb +1 -1
- metadata +73 -26
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/expectations'
|
4
|
+
|
5
|
+
RSpec::Matchers.define :be_authorized do |controller, action, params: {}, session: {}|
|
6
|
+
match do |user|
|
7
|
+
parameters = params.merge(controller: controller, action: action)
|
8
|
+
|
9
|
+
access?(user, parameters, session)
|
10
|
+
end
|
11
|
+
|
12
|
+
match_when_negated do |user|
|
13
|
+
parameters = params.merge(controller: controller, action: action)
|
14
|
+
|
15
|
+
!access?(user, parameters, session)
|
16
|
+
end
|
17
|
+
|
18
|
+
failure_message do |user|
|
19
|
+
maybe_params_or_session("expected #{user.class}##{user.id} to be authorized in #{data}", params, session)
|
20
|
+
end
|
21
|
+
|
22
|
+
failure_message_when_negated do |user|
|
23
|
+
maybe_params_or_session("expected #{user.class}##{user.id} not to be authorized in #{data}", params, session)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def access?(user, params, session)
|
29
|
+
cop = Authorizy.config.cop.new(user, params, session)
|
30
|
+
|
31
|
+
Authorizy::Core.new(user, params, session, cop: cop).access?
|
32
|
+
end
|
33
|
+
|
34
|
+
def maybe_params_or_session(message, params, session)
|
35
|
+
message += ", params: #{params}" if params.present?
|
36
|
+
message += ", session: #{session}" if session.present?
|
37
|
+
|
38
|
+
message
|
39
|
+
end
|
40
|
+
|
41
|
+
def data
|
42
|
+
%(controller: "#{expected[0]}", action: "#{expected[1]}")
|
43
|
+
end
|
44
|
+
end
|
data/lib/authorizy/version.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::BaseCop, '#access?' do
|
4
|
-
|
4
|
+
let!(:params) { { 'controller' => 'controller', 'action' => 'action' } }
|
5
|
+
let(:cop) { described_class.new('current_user', params, 'session') }
|
5
6
|
|
6
7
|
it 'returns false as default' do
|
7
8
|
expect(cop.access?).to be(false)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::Config, '#aliases' do
|
4
|
-
|
4
|
+
let!(:config) { described_class.new }
|
5
5
|
|
6
6
|
it 'has default value and can receive a new one' do
|
7
|
-
expect(
|
7
|
+
expect(config.aliases).to eq({})
|
8
8
|
|
9
9
|
config.aliases = 'value'
|
10
10
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::Config, '#cop' do
|
4
|
-
|
4
|
+
let!(:config) { described_class.new }
|
5
5
|
|
6
6
|
it 'has default value and can receive a new one' do
|
7
|
-
expect(
|
7
|
+
expect(config.cop).to eq(Authorizy::BaseCop)
|
8
8
|
|
9
9
|
config.cop = 'value'
|
10
10
|
|
@@ -1,29 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::Config, '#current_user' do
|
4
|
-
|
4
|
+
let!(:config) { described_class.new }
|
5
5
|
|
6
6
|
context 'when uses default value' do
|
7
7
|
context 'when context responds to current_user' do
|
8
8
|
let!(:context) { OpenStruct.new(current_user: 'user') }
|
9
9
|
|
10
10
|
it 'is called' do
|
11
|
-
expect(
|
11
|
+
expect(config.current_user.call(context)).to eq('user')
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
context 'when context does not respond to current_user' do
|
16
16
|
let!(:context) { 'context' }
|
17
17
|
|
18
|
-
it
|
19
|
-
expect(subject.current_user.call(context)).to be(nil)
|
20
|
-
end
|
18
|
+
it { expect(config.current_user.call(context)).to be(nil) }
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
22
|
context 'when uses custom value' do
|
25
23
|
it 'executes what you want' do
|
26
|
-
config.current_user = ->
|
24
|
+
config.current_user = ->(context) { context[:value] }
|
27
25
|
|
28
26
|
expect(config.current_user.call({ value: 'value' })).to eq('value')
|
29
27
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::Config, '#dependencies' do
|
4
|
-
|
4
|
+
let!(:config) { described_class.new }
|
5
5
|
|
6
6
|
it 'has default value and can receive a new one' do
|
7
|
-
expect(
|
7
|
+
expect(config.dependencies).to eq({})
|
8
8
|
|
9
9
|
config.dependencies = 'value'
|
10
10
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Authorizy::Config, '#field' do
|
4
|
+
let!(:config) { described_class.new }
|
5
|
+
|
6
|
+
context 'when uses default value' do
|
7
|
+
context 'when current_user responds to authorizy' do
|
8
|
+
let!(:current_user) { OpenStruct.new(authorizy: { permissions: [%i[users index]] }) }
|
9
|
+
|
10
|
+
it 'is called' do
|
11
|
+
expect(config.field.call(current_user)).to eq(permissions: [%i[users index]])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when current_user does not respond to field' do
|
16
|
+
let!(:current_user) { nil }
|
17
|
+
|
18
|
+
it { expect(config.field.call(current_user)).to eq({}) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when uses custom value' do
|
23
|
+
it 'executes what you want' do
|
24
|
+
config.field = ->(current_user) { current_user[:value] }
|
25
|
+
|
26
|
+
expect(config.field.call({ value: 'value' })).to eq('value')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::Config, '#redirect_url' do
|
4
|
-
|
4
|
+
let!(:config) { described_class.new }
|
5
5
|
|
6
6
|
context 'when uses default value' do
|
7
7
|
context 'when context responds to root_url' do
|
8
8
|
let!(:context) { OpenStruct.new(root_url: '/root') }
|
9
9
|
|
10
10
|
it 'is called' do
|
11
|
-
expect(
|
11
|
+
expect(config.redirect_url.call(context)).to eq('/root')
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -16,14 +16,14 @@ RSpec.describe Authorizy::Config, '#redirect_url' do
|
|
16
16
|
let!(:context) { 'context' }
|
17
17
|
|
18
18
|
it 'returns just a slash' do
|
19
|
-
expect(
|
19
|
+
expect(config.redirect_url.call(context)).to eq('/')
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'when uses custom value' do
|
25
25
|
it 'executes what you want' do
|
26
|
-
config.redirect_url = ->
|
26
|
+
config.redirect_url = ->(context) { context[:value] }
|
27
27
|
|
28
28
|
expect(config.redirect_url.call({ value: 'value' })).to eq('value')
|
29
29
|
end
|
@@ -5,7 +5,6 @@ require 'support/models/empty_cop'
|
|
5
5
|
require 'support/controllers/dummy_controller'
|
6
6
|
|
7
7
|
RSpec.describe DummyController, '#authorizy', type: :controller do
|
8
|
-
let!(:parameters) { ActionController::Parameters.new(key: 'value', controller: 'dummy', action: 'action') }
|
9
8
|
let!(:user) { User.new }
|
10
9
|
|
11
10
|
context 'when cop responds to the controller name' do
|
@@ -30,7 +29,7 @@ RSpec.describe DummyController, '#authorizy', type: :controller do
|
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
33
|
-
context 'when cop
|
32
|
+
context 'when cop does not respond to the controller name' do
|
34
33
|
it 'denies the access' do
|
35
34
|
config_mock(cop: EmptyCop, current_user: user) do
|
36
35
|
get :action
|
@@ -3,13 +3,14 @@
|
|
3
3
|
require 'support/models/authorizy_cop'
|
4
4
|
|
5
5
|
RSpec.describe AuthorizyCop do
|
6
|
-
|
6
|
+
let!(:params) { { controller: 'controller', action: 'action' } }
|
7
|
+
let(:cop) { described_class.new('current_user', params, 'session') }
|
7
8
|
|
8
9
|
it 'adds private attributes readers' do
|
9
|
-
expect(cop.
|
10
|
-
expect(cop.
|
11
|
-
expect(cop.
|
12
|
-
expect(cop.
|
13
|
-
expect(cop.
|
10
|
+
expect(cop.fetch_action).to eq('action')
|
11
|
+
expect(cop.fetch_controller).to eq('controller')
|
12
|
+
expect(cop.fetch_current_user).to eq('current_user')
|
13
|
+
expect(cop.fetch_params).to eq(controller: 'controller', action: 'action')
|
14
|
+
expect(cop.fetch_session).to eq('session')
|
14
15
|
end
|
15
16
|
end
|
@@ -5,7 +5,6 @@ require 'support/models/empty_cop'
|
|
5
5
|
require 'support/controllers/admin/dummy_controller'
|
6
6
|
|
7
7
|
RSpec.describe Admin::DummyController, '#authorizy', type: :controller do
|
8
|
-
let!(:parameters) { ActionController::Parameters.new(key: 'value', controller: 'admin/users', action: 'action') }
|
9
8
|
let!(:user) { User.new }
|
10
9
|
|
11
10
|
context 'when cop responds to the controller name' do
|
@@ -30,7 +29,7 @@ RSpec.describe Admin::DummyController, '#authorizy', type: :controller do
|
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
33
|
-
context 'when cop
|
32
|
+
context 'when cop does not respond to the controller name' do
|
34
33
|
it 'denies the access' do
|
35
34
|
config_mock(cop: EmptyCop, current_user: user) do
|
36
35
|
get :action
|
@@ -1,137 +1,181 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Authorizy::Core, '#access?' do
|
4
|
-
context 'when
|
4
|
+
context 'when cop#access? returns true' do
|
5
|
+
let!(:cop) { OpenStruct.new(access?: true) }
|
5
6
|
let!(:current_user) { User.new }
|
6
|
-
let!(:params) { {
|
7
|
-
let!(:session) { {
|
7
|
+
let!(:params) { { action: 'any', controller: 'any' } }
|
8
|
+
let!(:session) { {} }
|
8
9
|
|
9
|
-
it '
|
10
|
-
expect(described_class.new(current_user, params, session).access?).to be(true)
|
10
|
+
it 'is authorized based in the cop response' do
|
11
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(true)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
|
-
context 'when permissions is
|
15
|
-
|
16
|
-
|
17
|
-
let!(:
|
18
|
-
let!(:params) { { 'action' => 'create', 'controller' => 'match' } }
|
15
|
+
context 'when permissions is in the current user' do
|
16
|
+
let!(:cop) { OpenStruct.new(access?: false) }
|
17
|
+
let!(:current_user) { User.new(authorizy: { permissions: [%w[controller create]] }) }
|
18
|
+
let!(:params) { { controller: 'controller', action: 'create' } }
|
19
19
|
let!(:session) { {} }
|
20
20
|
|
21
|
-
it '
|
22
|
-
expect(
|
21
|
+
it 'is authorized based on the user permissions' do
|
22
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(true)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
context 'when session has no permission nor the user' do
|
27
|
-
|
28
|
-
|
27
|
+
let!(:cop) { OpenStruct.new(access?: false) }
|
29
28
|
let!(:current_user) { User.new }
|
30
|
-
let!(:params) { {
|
29
|
+
let!(:params) { { controller: 'match', action: 'create' } }
|
31
30
|
let!(:session) { {} }
|
32
31
|
|
33
|
-
it
|
32
|
+
it 'does not authorize' do
|
33
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
|
36
37
|
context 'when cop does not respond to controller' do
|
37
|
-
|
38
|
-
|
39
|
-
let!(:cop) { instance_double('Authorizy.config.cop') }
|
38
|
+
let!(:cop) { instance_double('Authorizy::BaseCop', access?: false) }
|
40
39
|
let!(:current_user) { User.new }
|
41
|
-
let!(:params) { {
|
40
|
+
let!(:params) { { action: 'create', controller: 'missing' } }
|
42
41
|
let!(:session) { {} }
|
43
42
|
|
44
|
-
before do
|
45
|
-
allow(Authorizy.config.cop).to receive(:new)
|
46
|
-
.with(current_user, params, session, 'missing', 'create')
|
47
|
-
.and_return(cop)
|
48
|
-
|
49
|
-
allow(cop).to receive(:respond_to?).with('missing').and_return(false)
|
50
|
-
end
|
51
|
-
|
52
43
|
it 'does not authorize via cop' do
|
53
|
-
expect(
|
44
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
54
45
|
end
|
55
46
|
end
|
56
47
|
|
57
48
|
context 'when cop responds to controller' do
|
58
|
-
subject(:authorizy) { described_class.new(current_user, params, session) }
|
59
|
-
|
60
|
-
let!(:cop) { instance_double('Authorizy.config.cop') }
|
61
49
|
let!(:current_user) { User.new }
|
62
|
-
let!(:params) { {
|
50
|
+
let!(:params) { { controller: 'admin/controller', action: 'create' } }
|
63
51
|
let!(:session) { {} }
|
64
52
|
|
65
|
-
before do
|
66
|
-
allow(Authorizy.config.cop).to receive(:new)
|
67
|
-
.with(current_user, params, session, 'match', 'create')
|
68
|
-
.and_return(cop)
|
69
|
-
|
70
|
-
allow(cop).to receive(:respond_to?).with('match').and_return(true)
|
71
|
-
end
|
72
|
-
|
73
53
|
context 'when cop does not release the access' do
|
74
|
-
|
75
|
-
|
54
|
+
let!(:cop) do
|
55
|
+
Class.new(Authorizy::BaseCop) do
|
56
|
+
def access?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
def admin__controller
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end.new(current_user, params, session)
|
64
|
+
end
|
76
65
|
|
77
|
-
|
66
|
+
it 'is not authorized by cop' do
|
67
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
78
68
|
end
|
79
69
|
end
|
80
70
|
|
81
71
|
context 'when cop releases the access' do
|
82
|
-
|
83
|
-
|
72
|
+
let!(:cop) do
|
73
|
+
Class.new(Authorizy::BaseCop) do
|
74
|
+
def access?
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
def admin__controller
|
79
|
+
true
|
80
|
+
end
|
81
|
+
end.new(current_user, params, session)
|
82
|
+
end
|
84
83
|
|
85
|
-
|
84
|
+
it 'is authorized by the cop' do
|
85
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(true)
|
86
86
|
end
|
87
87
|
end
|
88
|
-
end
|
89
88
|
|
90
|
-
|
91
|
-
|
89
|
+
context 'when cop return nil' do
|
90
|
+
let!(:cop) do
|
91
|
+
Class.new(Authorizy::BaseCop) do
|
92
|
+
def access?
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
def admin__controller
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
end.new(current_user, params, session)
|
100
|
+
end
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
|
102
|
+
it 'is converted to false' do
|
103
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when cop return empty' do
|
108
|
+
let!(:cop) do
|
109
|
+
Class.new(Authorizy::BaseCop) do
|
110
|
+
def access?
|
111
|
+
false
|
112
|
+
end
|
113
|
+
|
114
|
+
def admin__controller
|
115
|
+
''
|
116
|
+
end
|
117
|
+
end.new(current_user, params, session)
|
118
|
+
end
|
96
119
|
|
97
|
-
|
98
|
-
|
120
|
+
it 'is converted to false' do
|
121
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
122
|
+
end
|
99
123
|
end
|
100
|
-
end
|
101
124
|
|
102
|
-
|
103
|
-
|
125
|
+
context 'when cop return nothing' do
|
126
|
+
let!(:cop) do
|
127
|
+
Class.new(Authorizy::BaseCop) do
|
128
|
+
def access?
|
129
|
+
false
|
130
|
+
end
|
104
131
|
|
105
|
-
|
106
|
-
|
107
|
-
|
132
|
+
def admin__controller; end
|
133
|
+
end.new(current_user, params, session)
|
134
|
+
end
|
108
135
|
|
109
|
-
|
110
|
-
|
136
|
+
it 'is converted to false' do
|
137
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when cop return true as string' do
|
142
|
+
let!(:cop) do
|
143
|
+
Class.new(Authorizy::BaseCop) do
|
144
|
+
def access?
|
145
|
+
false
|
146
|
+
end
|
147
|
+
|
148
|
+
def admin__controller
|
149
|
+
'true'
|
150
|
+
end
|
151
|
+
end.new(current_user, params, session)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'is converted to false' do
|
155
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
156
|
+
end
|
111
157
|
end
|
112
158
|
end
|
113
159
|
|
114
160
|
context 'when user has the controller permission but not action' do
|
115
|
-
|
116
|
-
|
161
|
+
let!(:cop) { instance_double('Authorizy::BaseCop', access?: false) }
|
117
162
|
let!(:current_user) { User.new }
|
118
|
-
let!(:params) { {
|
119
|
-
let!(:session) { {
|
163
|
+
let!(:params) { { controller: 'controller', action: 'action' } }
|
164
|
+
let!(:session) { { permissions: [%w[controller miss]] } }
|
120
165
|
|
121
|
-
it '
|
122
|
-
expect(
|
166
|
+
it 'is not authorized' do
|
167
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
123
168
|
end
|
124
169
|
end
|
125
170
|
|
126
171
|
context 'when user has the action permission but not controller' do
|
127
|
-
|
128
|
-
|
172
|
+
let!(:cop) { instance_double('Authorizy::BaseCop', access?: false) }
|
129
173
|
let!(:current_user) { User.new }
|
130
|
-
let!(:params) { {
|
131
|
-
let!(:session) { {
|
174
|
+
let!(:params) { { controller: 'controller', action: 'action' } }
|
175
|
+
let!(:session) { { permissions: [%w[miss action]] } }
|
132
176
|
|
133
|
-
it '
|
134
|
-
expect(
|
177
|
+
it 'is not authorized' do
|
178
|
+
expect(described_class.new(current_user, params, session, cop: cop).access?).to be(false)
|
135
179
|
end
|
136
180
|
end
|
137
181
|
end
|