authorizy 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Authorizy
4
- VERSION = '0.1.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Authorizy::BaseCop, '#access?' do
4
- subject(:cop) { described_class.new('current_user', 'params', 'session', 'controller', 'action') }
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
- subject(:config) { described_class.new }
4
+ let!(:config) { described_class.new }
5
5
 
6
6
  it 'has default value and can receive a new one' do
7
- expect(subject.aliases).to eq({})
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
- subject(:config) { described_class.new }
4
+ let!(:config) { described_class.new }
5
5
 
6
6
  it 'has default value and can receive a new one' do
7
- expect(subject.cop).to eq(Authorizy::BaseCop)
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
- subject(:config) { described_class.new }
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(subject.current_user.call(context)).to eq('user')
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 'returns nil' do
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 = -> (context) { context[:value] }
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
- subject(:config) { described_class.new }
4
+ let!(:config) { described_class.new }
5
5
 
6
6
  it 'has default value and can receive a new one' do
7
- expect(subject.dependencies).to eq({})
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  RSpec.describe Authorizy::Config do
4
4
  it 'starts with a default cop' do
5
- expect(subject.cop).to eq(Authorizy::BaseCop)
5
+ expect(described_class.new.cop).to eq(Authorizy::BaseCop)
6
6
  end
7
7
  end
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Authorizy::Config, '#redirect_url' do
4
- subject(:config) { described_class.new }
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(subject.redirect_url.call(context)).to eq('/root')
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(subject.redirect_url.call(context)).to eq('/')
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 = -> (context) { context[:value] }
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 responds to the controller name' do
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
- subject(:cop) { described_class.new('current_user', 'params', 'session', 'controller', 'action') }
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.get_action).to eq('action')
10
- expect(cop.get_controller).to eq('controller')
11
- expect(cop.get_current_user).to eq('current_user')
12
- expect(cop.get_params).to eq('params')
13
- expect(cop.get_session).to eq('session')
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 responds to the controller name' do
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 permissions is in session as string' do
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) { { 'action' => 'create', 'controller' => 'controller' } }
7
- let!(:session) { { 'permissions' => [{ 'action' => 'create', 'controller' => 'controller' }] } }
7
+ let!(:params) { { action: 'any', controller: 'any' } }
8
+ let!(:session) { {} }
8
9
 
9
- it 'uses the session value skipping the user fetch' do
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 not in session' do
15
- subject(:authorizy) { described_class.new(current_user, params, session) }
16
-
17
- let!(:current_user) { User.new(authorizy: { permissions: [{ action: 'create', controller: 'match' }] }) }
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 'fetches the permission from user' do
22
- expect(authorizy.access?).to be(true)
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
- subject(:authorizy) { described_class.new(current_user, params, session) }
28
-
27
+ let!(:cop) { OpenStruct.new(access?: false) }
29
28
  let!(:current_user) { User.new }
30
- let!(:params) { { 'action' => 'create', 'controller' => 'match' } }
29
+ let!(:params) { { controller: 'match', action: 'create' } }
31
30
  let!(:session) { {} }
32
31
 
33
- it { expect(authorizy.access?).to be(false) }
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
- subject(:authorizy) { described_class.new(current_user, params, session) }
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) { { 'action' => 'create', 'controller' => 'missing' } }
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(authorizy.access?).to be(false)
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) { { 'action' => 'create', 'controller' => 'match' } }
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
- it 'continues trying via session and so user permissions' do
75
- allow(cop).to receive(:public_send).with('match').and_return(false)
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
- expect(authorizy.access?).to be(false)
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
- it 'skips session and user permission return true to the access' do
83
- allow(cop).to receive(:public_send).with('match').and_return(true)
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
- expect(authorizy.access?).to be(true)
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
- context 'when controller is given' do
91
- subject(:authorizy) { described_class.new(current_user, params, session, controller: 'controller') }
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
- let!(:current_user) { User.new }
94
- let!(:params) { { 'action' => 'action', 'controller' => 'ignored' } }
95
- let!(:session) { { 'permissions' => [{ 'action' => 'action', 'controller' => 'controller' }] } }
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
- it 'uses the given controller over the one on params' do
98
- expect(authorizy.access?).to be(true)
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
- context 'when action is given' do
103
- subject(:authorizy) { described_class.new(current_user, params, session, action: 'action') }
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
- let!(:current_user) { User.new }
106
- let!(:params) { { 'action' => 'ignored', 'controller' => 'controller' } }
107
- let!(:session) { { 'permissions' => [{ 'action' => 'action', 'controller' => 'controller' }] } }
132
+ def admin__controller; end
133
+ end.new(current_user, params, session)
134
+ end
108
135
 
109
- it 'uses the given action over the one on params' do
110
- expect(authorizy.access?).to be(true)
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
- subject(:authorizy) { described_class.new(current_user, params, session) }
116
-
161
+ let!(:cop) { instance_double('Authorizy::BaseCop', access?: false) }
117
162
  let!(:current_user) { User.new }
118
- let!(:params) { { 'action' => 'action', 'controller' => 'controller' } }
119
- let!(:session) { { 'permissions' => [{ 'action' => 'miss', 'controller' => 'controller' }] } }
163
+ let!(:params) { { controller: 'controller', action: 'action' } }
164
+ let!(:session) { { permissions: [%w[controller miss]] } }
120
165
 
121
- it 'cannot access' do
122
- expect(authorizy.access?).to be(false)
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
- subject(:authorizy) { described_class.new(current_user, params, session) }
128
-
172
+ let!(:cop) { instance_double('Authorizy::BaseCop', access?: false) }
129
173
  let!(:current_user) { User.new }
130
- let!(:params) { { 'action' => 'action', 'controller' => 'controller' } }
131
- let!(:session) { { 'permissions' => [{ 'action' => 'create', 'controller' => 'miss' }] } }
174
+ let!(:params) { { controller: 'controller', action: 'action' } }
175
+ let!(:session) { { permissions: [%w[miss action]] } }
132
176
 
133
- it 'cannot access' do
134
- expect(authorizy.access?).to be(false)
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