stn-simple_token_authentication 1.7.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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +270 -0
  4. data/Rakefile +61 -0
  5. data/doc/README.md +18 -0
  6. data/lib/simple_token_authentication.rb +58 -0
  7. data/lib/simple_token_authentication/acts_as_token_authenticatable.rb +49 -0
  8. data/lib/simple_token_authentication/acts_as_token_authentication_handler.rb +22 -0
  9. data/lib/simple_token_authentication/adapter.rb +7 -0
  10. data/lib/simple_token_authentication/adapters/active_record_adapter.rb +14 -0
  11. data/lib/simple_token_authentication/adapters/mongoid_adapter.rb +14 -0
  12. data/lib/simple_token_authentication/adapters/rails_adapter.rb +14 -0
  13. data/lib/simple_token_authentication/adapters/rails_api_adapter.rb +18 -0
  14. data/lib/simple_token_authentication/configuration.rb +45 -0
  15. data/lib/simple_token_authentication/entities_manager.rb +10 -0
  16. data/lib/simple_token_authentication/entity.rb +64 -0
  17. data/lib/simple_token_authentication/fallback_authentication_handler.rb +11 -0
  18. data/lib/simple_token_authentication/sign_in_handler.rb +19 -0
  19. data/lib/simple_token_authentication/token_authentication_handler.rb +149 -0
  20. data/lib/simple_token_authentication/token_comparator.rb +20 -0
  21. data/lib/simple_token_authentication/token_generator.rb +9 -0
  22. data/lib/simple_token_authentication/version.rb +3 -0
  23. data/lib/tasks/simple_token_authentication_tasks.rake +4 -0
  24. data/spec/configuration/action_controller_callbacks_options_spec.rb +53 -0
  25. data/spec/configuration/fallback_to_devise_option_spec.rb +128 -0
  26. data/spec/configuration/header_names_option_spec.rb +463 -0
  27. data/spec/configuration/sign_in_token_option_spec.rb +92 -0
  28. data/spec/lib/simple_token_authentication/acts_as_token_authenticatable_spec.rb +108 -0
  29. data/spec/lib/simple_token_authentication/acts_as_token_authentication_handler_spec.rb +127 -0
  30. data/spec/lib/simple_token_authentication/adapter_spec.rb +19 -0
  31. data/spec/lib/simple_token_authentication/adapters/active_record_adapter_spec.rb +21 -0
  32. data/spec/lib/simple_token_authentication/adapters/mongoid_adapter_spec.rb +21 -0
  33. data/spec/lib/simple_token_authentication/adapters/rails_adapter_spec.rb +21 -0
  34. data/spec/lib/simple_token_authentication/adapters/rails_api_adapter_spec.rb +43 -0
  35. data/spec/lib/simple_token_authentication/configuration_spec.rb +133 -0
  36. data/spec/lib/simple_token_authentication/entities_manager_spec.rb +67 -0
  37. data/spec/lib/simple_token_authentication/entity_spec.rb +190 -0
  38. data/spec/lib/simple_token_authentication/errors_spec.rb +8 -0
  39. data/spec/lib/simple_token_authentication/fallback_authentication_handler_spec.rb +24 -0
  40. data/spec/lib/simple_token_authentication/sign_in_handler_spec.rb +43 -0
  41. data/spec/lib/simple_token_authentication/token_authentication_handler_spec.rb +351 -0
  42. data/spec/lib/simple_token_authentication/token_comparator_spec.rb +19 -0
  43. data/spec/lib/simple_token_authentication/token_generator_spec.rb +19 -0
  44. data/spec/lib/simple_token_authentication_spec.rb +181 -0
  45. data/spec/spec_helper.rb +15 -0
  46. data/spec/support/dummy_classes_helper.rb +80 -0
  47. data/spec/support/spec_for_adapter.rb +10 -0
  48. data/spec/support/spec_for_authentication_handler_interface.rb +8 -0
  49. data/spec/support/spec_for_configuration_option_interface.rb +28 -0
  50. data/spec/support/spec_for_entities_manager_interface.rb +8 -0
  51. data/spec/support/spec_for_sign_in_handler_interface.rb +8 -0
  52. data/spec/support/spec_for_token_comparator_interface.rb +8 -0
  53. data/spec/support/spec_for_token_generator_interface.rb +8 -0
  54. data/spec/support/specs_for_token_authentication_handler_interface.rb +8 -0
  55. metadata +250 -0
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActionController', action_controller_callbacks_options: true do
4
+
5
+ after(:each) do
6
+ ensure_examples_independence
7
+ end
8
+
9
+ before(:each) do
10
+ double_user_model
11
+ define_test_subjects_for_extension_of(SimpleTokenAuthentication::ActsAsTokenAuthenticationHandler)
12
+ end
13
+
14
+ describe ':only option' do
15
+
16
+ context 'when provided to `acts_as_token_authentication_hanlder_for`' do
17
+
18
+ it 'is applied to the corresponding callback (1)', rspec_3_error: true, private: true do
19
+ some_class = @subjects.first
20
+
21
+ expect(some_class).to receive(:before_filter).with(:authenticate_user_from_token!, { only: ['some_action', :some_other_action] })
22
+ some_class.acts_as_token_authentication_handler_for User, only: ['some_action', :some_other_action]
23
+ end
24
+
25
+ it 'is applied to the corresponding callback (2)', rspec_3_error: true, private: true do
26
+ some_child_class = @subjects.last
27
+
28
+ expect(some_child_class).to receive(:before_filter).with(:authenticate_user_from_token!, { only: ['some_action', :some_other_action] })
29
+ some_child_class.acts_as_token_authentication_handler_for User, only: ['some_action', :some_other_action]
30
+ end
31
+ end
32
+ end
33
+
34
+ describe ':except option' do
35
+
36
+ context 'when provided to `acts_as_token_authentication_hanlder_for`' do
37
+
38
+ it 'is applied to the corresponding callback (1)', rspec_3_error: true, private: true do
39
+ some_class = @subjects.first
40
+
41
+ expect(some_class).to receive(:before_filter).with(:authenticate_user_from_token!, { except: ['some_action', :some_other_action] })
42
+ some_class.acts_as_token_authentication_handler_for User, except: ['some_action', :some_other_action]
43
+ end
44
+
45
+ it 'is applied to the corresponding callback (2)', rspec_3_error: true, private: true do
46
+ some_child_class = @subjects.last
47
+
48
+ expect(some_child_class).to receive(:before_filter).with(:authenticate_user_from_token!, { except: ['some_action', :some_other_action] })
49
+ some_child_class.acts_as_token_authentication_handler_for User, except: ['some_action', :some_other_action]
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Simple Token Authentication' do
4
+
5
+ describe ':fallback_to_devise option', fallback_to_devise_option: true, fallback_option: true do
6
+
7
+ describe 'determines what to do if token authentication fails' do
8
+
9
+ before(:each) do
10
+ user = double()
11
+ stub_const('User', user)
12
+ allow(user).to receive(:name).and_return('User')
13
+
14
+ # given a controller class which acts as token authentication handler
15
+ @controller_class = Class.new
16
+ allow(@controller_class).to receive(:before_filter)
17
+ @controller_class.send :extend, SimpleTokenAuthentication::ActsAsTokenAuthenticationHandler
18
+ end
19
+
20
+ context 'when true' do
21
+
22
+ it 'delegates authentication to Devise strategies', protected: true do
23
+ @controller = @controller_class.new
24
+ allow(@controller).to receive(:params)
25
+ allow(@controller).to receive(:find_record_from_identifier)
26
+
27
+ # sets :authenticate_user_from_token! (bang) in the before_filter
28
+ expect(@controller_class).to receive(:before_filter).with(:authenticate_user_from_token!, {})
29
+
30
+ # when falling back to Devise is enabled
31
+ @controller_class.acts_as_token_authentication_handler_for User, fallback_to_devise: true
32
+
33
+ # when the hook is triggered
34
+ # Devise strategies take control of authentication
35
+ expect(@controller).to receive(:authenticate_user!)
36
+ @controller.authenticate_user_from_token! # bang
37
+ end
38
+ end
39
+
40
+ context 'when false' do
41
+
42
+ it 'does nothing after token authentication fails', protected: true do
43
+ @controller = @controller_class.new
44
+ allow(@controller).to receive(:params)
45
+ allow(@controller).to receive(:find_record_from_identifier)
46
+
47
+ # sets :authenticate_user_from_token (non-bang) in the before_filter
48
+ expect(@controller_class).to receive(:before_filter).with(:authenticate_user_from_token, {})
49
+
50
+ # when falling back to Devise is enabled
51
+ @controller_class.acts_as_token_authentication_handler_for User, fallback_to_devise: false
52
+
53
+ # when the hook is triggered
54
+ # Devise strategies do not take control of authentication
55
+ expect(@controller).not_to receive(:authenticate_user!)
56
+ @controller.authenticate_user_from_token # non-bang
57
+ end
58
+ end
59
+
60
+ context 'when omitted' do
61
+
62
+ it 'delegates authentication to Devise strategies', protected: true do
63
+ @controller = @controller_class.new
64
+ allow(@controller).to receive(:params)
65
+ allow(@controller).to receive(:find_record_from_identifier)
66
+
67
+ # sets :authenticate_user_from_token! (bang) in the before_filter
68
+ expect(@controller_class).to receive(:before_filter).with(:authenticate_user_from_token!, {})
69
+
70
+ # when falling back to Devise is enabled
71
+ @controller_class.acts_as_token_authentication_handler_for User
72
+
73
+ # when the hook is triggered
74
+ # Devise strategies take control of authentication
75
+ expect(@controller).to receive(:authenticate_user!)
76
+ @controller.authenticate_user_from_token! # bang
77
+ end
78
+ end
79
+
80
+ describe 'in a per-model (token authenticatable) way' do
81
+
82
+ before(:each) do
83
+ admin = double()
84
+ stub_const('Admin', admin)
85
+ allow(admin).to receive(:name).and_return('Admin')
86
+ end
87
+
88
+ context 'when false for User and true for Admin' do
89
+
90
+ before(:each) do
91
+ @controller = @controller_class.new
92
+ allow(@controller).to receive(:params)
93
+ allow(@controller).to receive(:find_record_from_identifier)
94
+
95
+ # sets :authenticate_user_from_token (non-bang) in the before_filter
96
+ expect(@controller_class).to receive(:before_filter).with(:authenticate_user_from_token, {})
97
+ # sets :authenticate_admin_from_token! (bang) in the before_filter
98
+ expect(@controller_class).to receive(:before_filter).with(:authenticate_admin_from_token!, {})
99
+
100
+ # when falling back to Devise is enabled for Admin but not User
101
+ @controller_class.acts_as_token_authentication_handler_for User, fallback_to_devise: false
102
+ @controller_class.acts_as_token_authentication_handler_for Admin, fallback_to_devise: true
103
+ end
104
+
105
+ context 'after no user suceeds token authentication' do
106
+
107
+ it 'does nothing', protected: true do
108
+ # when the user hook is triggered
109
+ # Devise strategies do not take control of authentication
110
+ expect(@controller).not_to receive(:authenticate_user!)
111
+ @controller.authenticate_user_from_token
112
+ end
113
+ end
114
+
115
+ context 'after no admin succeeds token authentication' do
116
+
117
+ it 'does delegate authentication to Devise', protected: true do
118
+ # when the admin hook is triggered
119
+ # Devise strategies do take control of authentication
120
+ expect(@controller).to receive(:authenticate_admin!)
121
+ @controller.authenticate_admin_from_token!
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,463 @@
1
+ require 'spec_helper'
2
+
3
+ def skip_devise_case_insensitive_keys_integration!(controller)
4
+ allow(controller).to receive(:integrate_with_devise_case_insensitive_keys) do |email|
5
+ email # return the email without modification
6
+ end
7
+ end
8
+
9
+ describe 'Simple Token Authentication' do
10
+
11
+ describe ':header_names option', header_names_option: true do
12
+
13
+ describe 'determines which header fields are looked at for authentication credentials' do
14
+
15
+ before(:each) do
16
+ user = double()
17
+ stub_const('User', user)
18
+ allow(user).to receive(:name).and_return('User')
19
+
20
+ admin = double()
21
+ stub_const('Admin', admin)
22
+ allow(admin).to receive(:name).and_return('Admin')
23
+
24
+ # given one *c*orrect record (which is supposed to get signed in)
25
+ @charles_record = double()
26
+ [user, admin].each do |model|
27
+ allow(model).to receive(:where).with(email: 'charles@example.com').and_return([@charles_record])
28
+ end
29
+ allow(@charles_record).to receive(:authentication_token).and_return('ch4rlEs_toKeN')
30
+
31
+ # and one *w*rong record (which should not be signed in)
32
+ @waldo_record = double()
33
+ [user, admin].each do |model|
34
+ allow(model).to receive(:where).with(email: 'waldo@example.com').and_return([@waldo_record])
35
+ end
36
+ allow(@waldo_record).to receive(:authentication_token).and_return('w4LdO_toKeN')
37
+
38
+ # given a controller class which acts as token authentication handler
39
+ @controller_class = Class.new
40
+ allow(@controller_class).to receive(:before_filter)
41
+ @controller_class.send :extend, SimpleTokenAuthentication::ActsAsTokenAuthenticationHandler
42
+
43
+ @controller = @controller_class.new
44
+ allow(@controller).to receive(:sign_in_handler).and_return(:sign_in_handler)
45
+ skip_devise_case_insensitive_keys_integration!(@controller)
46
+ end
47
+
48
+
49
+ context 'provided the controller handles authentication for User' do
50
+
51
+ before(:each) do
52
+ # and handles authentication for a given model
53
+ @controller_class.acts_as_token_authentication_handler_for User
54
+ end
55
+
56
+ context 'and params contains no authentication credentials' do
57
+
58
+ before(:each) do
59
+ # and there are no credentials in params
60
+ allow(@controller).to receive(:params).and_return({})
61
+ end
62
+
63
+ context 'and request headers contain credentials in the custom and default fields' do
64
+
65
+ before(:each) do
66
+ # request headers are set in the nested contexts, these are minor settings
67
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
68
+ allow(@controller).to receive(:sign_in_handler).and_return(:sign_in_handler)
69
+ end
70
+
71
+ context 'when {}' do
72
+
73
+ before(:each) do
74
+ # and credentials in the default header fields lead to the wrong record
75
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
76
+ .and_return('waldo@example.com')
77
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
78
+ .and_return('waldo@example.com')
79
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
80
+ .and_return('w4LdO_toKeN')
81
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Token')
82
+ .and_return('w4LdO_toKeN')
83
+ # while credential in the custom header fields lead to the correct record
84
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
85
+ .and_return('charles@example.com')
86
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
87
+ .and_return('ch4rlEs_toKeN')
88
+
89
+ allow(SimpleTokenAuthentication).to receive(:header_names)
90
+ .and_return({})
91
+ end
92
+
93
+ it 'does look for credentials in the default header fields (\'X-User-Email\' and \'X-User-Token\')', public: true do
94
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
95
+ @controller.authenticate_user_from_token
96
+ end
97
+
98
+ it 'ignores credentials in any other fields', public: true do
99
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
100
+ @controller.authenticate_user_from_token
101
+ end
102
+ end
103
+
104
+ context 'when { user: {} }' do
105
+
106
+ before(:each) do
107
+ # and credentials in the default header fields lead to the wrong record
108
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
109
+ .and_return('waldo@example.com')
110
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
111
+ .and_return('waldo@example.com')
112
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
113
+ .and_return('w4LdO_toKeN')
114
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Token')
115
+ .and_return('w4LdO_toKeN')
116
+ # while credential in the custom header fields lead to the correct record
117
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
118
+ .and_return('charles@example.com')
119
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
120
+ .and_return('ch4rlEs_toKeN')
121
+
122
+ allow(SimpleTokenAuthentication).to receive(:header_names)
123
+ .and_return({ user: {} })
124
+ end
125
+
126
+ it 'does look for credentials in the default header fields (\'X-User-Email\' and \'X-User-Token\')', protected: true do
127
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
128
+ @controller.authenticate_user_from_token
129
+ end
130
+
131
+ it 'ignores credentials in any other fields', protected: true do
132
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
133
+ @controller.authenticate_user_from_token
134
+ end
135
+ end
136
+
137
+ context 'when { user: { email: \'X-CustomEmail\', authentication_token: \'X-Custom_Token\' } }' do
138
+
139
+ before(:each) do
140
+ # and credentials in the default header fields lead to the wrong record
141
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
142
+ .and_return('waldo@example.com')
143
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
144
+ .and_return('w4LdO_toKeN')
145
+ # while credential in the custom header fields lead to the correct record
146
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
147
+ .and_return('charles@example.com')
148
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
149
+ .and_return('ch4rlEs_toKeN')
150
+
151
+ allow(SimpleTokenAuthentication).to receive(:header_names)
152
+ .and_return({ user: { email: 'X-CustomEmail',
153
+ authentication_token: 'X-Custom_Token' } })
154
+ end
155
+
156
+ it 'does look for credentials in the custom headers fields', public: true do
157
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
158
+ @controller.authenticate_user_from_token
159
+ end
160
+
161
+ it 'ignores credentials in any other fields (including default ones)', public: true do
162
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
163
+ @controller.authenticate_user_from_token
164
+ end
165
+ end
166
+
167
+ context 'when { admin: { email: \'X-CustomEmail\', authentication_token: \'X-Custom_Token\' } }' do
168
+
169
+ before(:each) do
170
+ # and credentials in the default header fields lead to the wrong record
171
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
172
+ .and_return('waldo@example.com')
173
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
174
+ .and_return('w4LdO_toKeN')
175
+ # while credential in the custom header fields lead to the correct record
176
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
177
+ .and_return('charles@example.com')
178
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
179
+ .and_return('ch4rlEs_toKeN')
180
+
181
+ allow(SimpleTokenAuthentication).to receive(:header_names)
182
+ .and_return({ admin: { email: 'X-CustomEmail',
183
+ authentication_token: 'X-Custom_Token' } })
184
+ end
185
+
186
+ it 'does look for credentials in the default header fields for :user', public: true do
187
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
188
+ @controller.authenticate_user_from_token
189
+ end
190
+
191
+ it 'ignores credentials in the custom :admin header fields', public: true do
192
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
193
+ @controller.authenticate_user_from_token
194
+ end
195
+ end
196
+
197
+ context 'when { user: { email: \'X-CustomEmail\' }, admin: { authentication_token: \'X-Custom_Token\' } }' do
198
+
199
+ before(:each) do
200
+ # and credentials in the default header fields lead to the wrong record
201
+ allow(@controller.request.headers).to receive(:[]).with(nil)
202
+ .and_return(nil)
203
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
204
+ .and_return('waldo@example.com')
205
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
206
+ .and_return('w4LdO_toKeN')
207
+ # while credential in the custom header fields lead to the correct record
208
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
209
+ .and_return('charles@example.com')
210
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
211
+ .and_return('ch4rlEs_toKeN')
212
+
213
+ allow(SimpleTokenAuthentication).to receive(:header_names)
214
+ .and_return({ user: { email: 'X-CustomEmail' },
215
+ admin: { authentication_token: 'X-Custom_Token' } })
216
+ end
217
+
218
+ it 'does look for credentials in \'X-CustomEmail\' and \'X-User-Token\'', public: true do
219
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
220
+ @controller.authenticate_user_from_token
221
+ end
222
+
223
+ it 'ignores credentials in \'X-User-Email\' and the :admin header fields', public: true do
224
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
225
+ @controller.authenticate_user_from_token
226
+ end
227
+ end
228
+
229
+ context 'when { admin: { email: \'X-CustomEmail\' }, user: { authentication_token: \'X-Custom_Token\' } }' do
230
+
231
+ before(:each) do
232
+ # and credentials in the default header fields lead to the wrong record
233
+ allow(@controller.request.headers).to receive(:[]).with(nil)
234
+ .and_return(nil)
235
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
236
+ .and_return('waldo@example.com')
237
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
238
+ .and_return('waldo@example.com')
239
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
240
+ .and_return('w4LdO_toKeN')
241
+ # while credential in the custom header fields lead to the correct record
242
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
243
+ .and_return('charles@example.com')
244
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
245
+ .and_return('ch4rlEs_toKeN')
246
+
247
+ allow(SimpleTokenAuthentication).to receive(:header_names)
248
+ .and_return({ admin: { email: 'X-CustomEmail' },
249
+ user: { authentication_token: 'X-Custom_Token' } })
250
+ end
251
+
252
+ it 'does look for credentials in \'X-User-Email\' and \'X-Custom_Token\'', public: true do
253
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
254
+ @controller.authenticate_user_from_token
255
+ end
256
+
257
+ it 'ignores credentials in \'X-User-Token\' and the :admin header fields', public: true do
258
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
259
+ @controller.authenticate_user_from_token
260
+ end
261
+ end
262
+
263
+ context 'when { user: { email: \'X-CustomEmail\' } }' do
264
+
265
+ before(:each) do
266
+ # and credentials in the default header fields lead to the wrong record
267
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
268
+ allow(@controller.request.headers).to receive(:[]).with(nil)
269
+ .and_return(nil)
270
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
271
+ .and_return('waldo@example.com')
272
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
273
+ .and_return('waldo@example.com')
274
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Token')
275
+ .and_return('w4LdO_toKeN')
276
+ # while credential in the custom header fields lead to the correct record
277
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
278
+ .and_return('charles@example.com')
279
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
280
+ .and_return('ch4rlEs_toKeN')
281
+
282
+ allow(SimpleTokenAuthentication).to receive(:header_names)
283
+ .and_return({ user: { email: 'X-CustomEmail' } })
284
+ end
285
+
286
+ it 'does look for credentials in \'X-CustomEmail\' and \'X-User-Token\'', public: true do
287
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
288
+ @controller.authenticate_user_from_token
289
+ end
290
+
291
+ it 'ignores credentials in \'X-User-Email\' and the :admin header fields', public: true do
292
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
293
+ @controller.authenticate_user_from_token
294
+ end
295
+ end
296
+ end
297
+ end
298
+ end
299
+
300
+ context 'provided the controller handles authentication for Admin' do
301
+
302
+ before(:each) do
303
+ # and handles authentication for a given model
304
+ @controller_class.acts_as_token_authentication_handler_for Admin
305
+ end
306
+
307
+ context 'and params contains no authentication credentials' do
308
+
309
+ before(:each) do
310
+ # and there are no credentials in params
311
+ allow(@controller).to receive(:params).and_return({})
312
+ end
313
+
314
+ context 'and request headers contain credentials in the custom and default fields' do
315
+
316
+ before(:each) do
317
+ # request headers are set in the nested contexts, these are minor settings
318
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
319
+ allow(@controller).to receive(:sign_in_handler).and_return(:sign_in_handler)
320
+ end
321
+
322
+ context 'when { admin: { email: \'X-CustomEmail\', authentication_token: \'X-Custom_Token\' } }' do
323
+
324
+ before(:each) do
325
+ # and credentials in the default header fields lead to the wrong record
326
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
327
+ allow(@controller.request.headers).to receive(:[]).with(nil)
328
+ .and_return(nil)
329
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
330
+ .and_return('waldo@example.com')
331
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
332
+ .and_return('waldo@example.com')
333
+
334
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Token')
335
+ .and_return('w4LdO_toKeN')
336
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
337
+ .and_return('w4LdO_toKeN')
338
+ # while credential in the custom header fields lead to the correct record
339
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
340
+ .and_return('charles@example.com')
341
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
342
+ .and_return('ch4rlEs_toKeN')
343
+
344
+ allow(SimpleTokenAuthentication).to receive(:header_names)
345
+ .and_return({ admin: { email: 'X-CustomEmail', authentication_token: 'X-Custom_Token' } })
346
+ end
347
+
348
+ it 'does look for credentials in \'X-CustomEmail\' and \'X-Custom_Token\'', public: true do
349
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
350
+ @controller.authenticate_admin_from_token
351
+ end
352
+
353
+ it 'ignores credentials in \'X-Admin-Email\', \'X-Admin-Token\' and the :user header fields', public: true do
354
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
355
+ @controller.authenticate_admin_from_token
356
+ end
357
+ end
358
+
359
+ context 'when { admin: { email: \'X-CustomEmail\' } }' do
360
+
361
+ before(:each) do
362
+ # and credentials in the default header fields lead to the wrong record
363
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
364
+ allow(@controller.request.headers).to receive(:[]).with(nil)
365
+ .and_return(nil)
366
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Email')
367
+ .and_return('waldo@example.com')
368
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
369
+ .and_return('waldo@example.com')
370
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Token')
371
+ .and_return('w4LdO_toKeN')
372
+ # while credential in the custom header fields lead to the correct record
373
+ allow(@controller.request.headers).to receive(:[]).with('X-CustomEmail')
374
+ .and_return('charles@example.com')
375
+ allow(@controller.request.headers).to receive(:[]).with('X-Admin-Token')
376
+ .and_return('ch4rlEs_toKeN')
377
+
378
+ allow(SimpleTokenAuthentication).to receive(:header_names)
379
+ .and_return({ admin: { email: 'X-CustomEmail' } })
380
+ end
381
+
382
+ it 'does look for credentials in \'X-CustomEmail\' and \'X-Admin-Token\'', public: true do
383
+ expect(@controller).to receive(:perform_sign_in!).with(@charles_record, :sign_in_handler)
384
+ @controller.authenticate_admin_from_token
385
+ end
386
+
387
+ it 'ignores credentials in \'X-Admin-Email\' and the :user header fields', public: true do
388
+ expect(@controller).not_to receive(:perform_sign_in!).with(@waldo_record, :sign_in_handler)
389
+ @controller.authenticate_admin_from_token
390
+ end
391
+ end
392
+ end
393
+ end
394
+ end
395
+ end
396
+
397
+ it 'can be modified from an initializer file', public: true do
398
+ user = double()
399
+ stub_const('User', user)
400
+ allow(user).to receive(:name).and_return('User')
401
+
402
+ # given one *c*orrect record (which is supposed to get signed in)
403
+ @charles_record = double()
404
+ allow(user).to receive(:where).with(email: 'charles@example.com').and_return([@charles_record])
405
+ allow(@charles_record).to receive(:authentication_token).and_return('ch4rlEs_toKeN')
406
+
407
+ # and one *w*rong record (which should not be signed in)
408
+ @waldo_record = double()
409
+ allow(user).to receive(:where).with(email: 'waldo@example.com').and_return([@waldo_record])
410
+ allow(@waldo_record).to receive(:authentication_token).and_return('w4LdO_toKeN')
411
+
412
+ # given a controller class which acts as token authentication handler
413
+ @controller_class = Class.new
414
+ allow(@controller_class).to receive(:before_filter)
415
+ @controller_class.send :extend, SimpleTokenAuthentication::ActsAsTokenAuthenticationHandler
416
+
417
+ # INITIALIZATION
418
+ # this step occurs when 'simple_token_authentication' is required
419
+ #
420
+ # and handles authentication for a given model
421
+ @controller_class.acts_as_token_authentication_handler_for User
422
+
423
+ # RUNTIME
424
+ @controller = @controller_class.new
425
+ # and there are no credentials in params
426
+ allow(@controller).to receive(:params).and_return({})
427
+ # (those are minor settings)
428
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
429
+ allow(@controller).to receive(:sign_in_handler).and_return(:sign_in_handler)
430
+ allow(@controller).to receive(:perform_sign_in!)
431
+
432
+ # and credentials in the header fields which match
433
+ # the initial `header_names` option value
434
+ allow(@controller).to receive_message_chain(:request, :headers).and_return(double())
435
+ allow(@controller.request.headers).to receive(:[]).with('X-User-Email')
436
+ .and_return('waldo@example.com')
437
+ allow(@controller.request.headers).to receive(:[]).with('X-Custom_Token')
438
+ .and_return('w4LdO_toKeN')
439
+
440
+ # end credential in the header fields which match
441
+ # the updated `header_names` option value
442
+ allow(@controller.request.headers).to receive(:[]).with('X-UpdatedName-User-Email')
443
+ .and_return('charles@example.com')
444
+ allow(@controller.request.headers).to receive(:[]).with('X-UpdatedName-User-Token')
445
+ .and_return('ch4rlEs_toKeN')
446
+
447
+
448
+ # even if modified *after* the class was loaded
449
+ allow(SimpleTokenAuthentication).to receive(:header_names)
450
+ .and_return({ user: { email: 'X-UpdatedName-User-Email', authentication_token: 'X-UpdatedName-User-Token' }})
451
+
452
+ skip_devise_case_insensitive_keys_integration!(@controller)
453
+
454
+ # the option updated value is taken into account
455
+ # when token authentication is performed
456
+ expect(@controller.request.headers).to receive(:[]).with('X-UpdatedName-User-Email')
457
+ expect(@controller.request.headers).to receive(:[]).with('X-UpdatedName-User-Token')
458
+ expect(@controller.request.headers).not_to receive(:[]).with('X-User-Email')
459
+ expect(@controller.request.headers).not_to receive(:[]).with('X-User-Token')
460
+ @controller.authenticate_user_from_token
461
+ end
462
+ end
463
+ end