omniauth-rightsignature 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ require 'helper'
2
+
3
+ describe OmniAuth::Form do
4
+ describe '.build' do
5
+ it 'yields the instance when called with a block and argument' do
6
+ OmniAuth::Form.build { |f| expect(f).to be_kind_of(OmniAuth::Form) }
7
+ end
8
+
9
+ it 'evaluates in the instance when called with a block and no argument' do
10
+ OmniAuth::Form.build { |f| expect(f.class).to eq(OmniAuth::Form) }
11
+ end
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'sets the form action to the passed :url option' do
16
+ expect(OmniAuth::Form.new(:url => '/awesome').to_html).to be_include("action='/awesome'")
17
+ end
18
+
19
+ it 'sets an H1 tag from the passed :title option' do
20
+ expect(OmniAuth::Form.new(:title => 'Something Cool').to_html).to be_include('<h1>Something Cool</h1>')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,73 @@
1
+ require 'helper'
2
+
3
+ describe OmniAuth::Strategies::Developer do
4
+ let(:app) do
5
+ Rack::Builder.new do |b|
6
+ b.use Rack::Session::Cookie, :secret => 'abc123'
7
+ b.use OmniAuth::Strategies::Developer
8
+ b.run lambda { |_env| [200, {}, ['Not Found']] }
9
+ end.to_app
10
+ end
11
+
12
+ context 'request phase' do
13
+ before(:each) { get '/auth/developer' }
14
+
15
+ it 'displays a form' do
16
+ expect(last_response.status).to eq(200)
17
+ expect(last_response.body).to be_include('<form')
18
+ end
19
+
20
+ it 'has the callback as the action for the form' do
21
+ expect(last_response.body).to be_include("action='/auth/developer/callback'")
22
+ end
23
+
24
+ it 'has a text field for each of the fields' do
25
+ expect(last_response.body.scan('<input').size).to eq(2)
26
+ end
27
+ end
28
+
29
+ context 'callback phase' do
30
+ let(:auth_hash) { last_request.env['omniauth.auth'] }
31
+
32
+ context 'with default options' do
33
+ before do
34
+ post '/auth/developer/callback', :name => 'Example User', :email => 'user@example.com'
35
+ end
36
+
37
+ it 'sets the name in the auth hash' do
38
+ expect(auth_hash.info.name).to eq('Example User')
39
+ end
40
+
41
+ it 'sets the email in the auth hash' do
42
+ expect(auth_hash.info.email).to eq('user@example.com')
43
+ end
44
+
45
+ it 'sets the uid to the email' do
46
+ expect(auth_hash.uid).to eq('user@example.com')
47
+ end
48
+ end
49
+
50
+ context 'with custom options' do
51
+ let(:app) do
52
+ Rack::Builder.new do |b|
53
+ b.use Rack::Session::Cookie, :secret => 'abc123'
54
+ b.use OmniAuth::Strategies::Developer, :fields => [:first_name, :last_name], :uid_field => :last_name
55
+ b.run lambda { |_env| [200, {}, ['Not Found']] }
56
+ end.to_app
57
+ end
58
+
59
+ before do
60
+ @options = {:uid_field => :last_name, :fields => [:first_name, :last_name]}
61
+ post '/auth/developer/callback', :first_name => 'Example', :last_name => 'User'
62
+ end
63
+
64
+ it 'sets info fields properly' do
65
+ expect(auth_hash.info.name).to eq('Example User')
66
+ end
67
+
68
+ it 'sets the uid properly' do
69
+ expect(auth_hash.uid).to eq('User')
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,765 @@
1
+ require 'helper'
2
+
3
+ def make_env(path = '/auth/test', props = {})
4
+ {
5
+ 'REQUEST_METHOD' => 'GET',
6
+ 'PATH_INFO' => path,
7
+ 'rack.session' => {},
8
+ 'rack.input' => StringIO.new('test=true'),
9
+ }.merge(props)
10
+ end
11
+
12
+ describe OmniAuth::Strategy do
13
+ let(:app) do
14
+ lambda { |_env| [404, {}, ['Awesome']] }
15
+ end
16
+
17
+ let(:fresh_strategy) do
18
+ c = Class.new
19
+ c.send(:include, OmniAuth::Strategy)
20
+ end
21
+
22
+ describe '.default_options' do
23
+ it 'is inherited from a parent class' do
24
+ superklass = Class.new
25
+ superklass.send :include, OmniAuth::Strategy
26
+ superklass.configure do |c|
27
+ c.foo = 'bar'
28
+ end
29
+
30
+ klass = Class.new(superklass)
31
+ expect(klass.default_options.foo).to eq('bar')
32
+ end
33
+ end
34
+
35
+ describe '.configure' do
36
+ subject do
37
+ c = Class.new
38
+ c.send(:include, OmniAuth::Strategy)
39
+ end
40
+
41
+ context 'when block is passed' do
42
+ it 'allows for default options setting' do
43
+ subject.configure do |c|
44
+ c.wakka = 'doo'
45
+ end
46
+ expect(subject.default_options['wakka']).to eq('doo')
47
+ end
48
+
49
+ it "works when block doesn't evaluate to true" do
50
+ environment_variable = nil
51
+ subject.configure do |c|
52
+ c.abc = '123'
53
+ c.hgi = environment_variable
54
+ end
55
+ expect(subject.default_options['abc']).to eq('123')
56
+ end
57
+ end
58
+
59
+ it 'takes a hash and deep merge it' do
60
+ subject.configure :abc => {:def => 123}
61
+ subject.configure :abc => {:hgi => 456}
62
+ expect(subject.default_options['abc']).to eq('def' => 123, 'hgi' => 456)
63
+ end
64
+ end
65
+
66
+ describe '#skip_info?' do
67
+ it 'is true if options.skip_info is true' do
68
+ expect(ExampleStrategy.new(app, :skip_info => true)).to be_skip_info
69
+ end
70
+
71
+ it 'is false if options.skip_info is false' do
72
+ expect(ExampleStrategy.new(app, :skip_info => false)).not_to be_skip_info
73
+ end
74
+
75
+ it 'is false by default' do
76
+ expect(ExampleStrategy.new(app)).not_to be_skip_info
77
+ end
78
+
79
+ it 'is true if options.skip_info is a callable that evaluates to truthy' do
80
+ instance = ExampleStrategy.new(app, :skip_info => lambda { |uid| uid })
81
+ expect(instance).to receive(:uid).and_return(true)
82
+ expect(instance).to be_skip_info
83
+ end
84
+ end
85
+
86
+ describe '.option' do
87
+ subject do
88
+ c = Class.new
89
+ c.send(:include, OmniAuth::Strategy)
90
+ end
91
+ it 'sets a default value' do
92
+ subject.option :abc, 123
93
+ expect(subject.default_options.abc).to eq(123)
94
+ end
95
+
96
+ it 'sets the default value to nil if none is provided' do
97
+ subject.option :abc
98
+ expect(subject.default_options.abc).to be_nil
99
+ end
100
+ end
101
+
102
+ describe '.args' do
103
+ subject do
104
+ c = Class.new
105
+ c.send(:include, OmniAuth::Strategy)
106
+ end
107
+
108
+ it 'sets args to the specified argument if there is one' do
109
+ subject.args [:abc, :def]
110
+ expect(subject.args).to eq([:abc, :def])
111
+ end
112
+
113
+ it 'is inheritable' do
114
+ subject.args [:abc, :def]
115
+ c = Class.new(subject)
116
+ expect(c.args).to eq([:abc, :def])
117
+ end
118
+
119
+ it 'accepts corresponding options as default arg values' do
120
+ subject.args [:a, :b]
121
+ subject.option :a, '1'
122
+ subject.option :b, '2'
123
+
124
+ expect(subject.new(nil).options.a).to eq '1'
125
+ expect(subject.new(nil).options.b).to eq '2'
126
+ expect(subject.new(nil, '3', '4').options.b).to eq '4'
127
+ expect(subject.new(nil, nil, '4').options.a).to eq nil
128
+ end
129
+ end
130
+
131
+ context 'fetcher procs' do
132
+ subject { fresh_strategy }
133
+ %w(uid info credentials extra).each do |fetcher|
134
+ describe ".#{fetcher}" do
135
+ it 'sets and retrieve a proc' do
136
+ proc = lambda { 'Hello' }
137
+ subject.send(fetcher, &proc)
138
+ expect(subject.send(fetcher)).to eq(proc)
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ context 'fetcher stacks' do
145
+ subject { fresh_strategy }
146
+ %w(uid info credentials extra).each do |fetcher|
147
+ describe ".#{fetcher}_stack" do
148
+ it 'is an array of called ancestral procs' do
149
+ fetchy = proc { 'Hello' }
150
+ subject.send(fetcher, &fetchy)
151
+ expect(subject.send("#{fetcher}_stack", subject.new(app))).to eq(['Hello'])
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ %w(request_phase).each do |abstract_method|
158
+ context "#{abstract_method}" do
159
+ it 'raises a NotImplementedError' do
160
+ strat = Class.new
161
+ strat.send :include, OmniAuth::Strategy
162
+ expect { strat.new(app).send(abstract_method) }.to raise_error(NotImplementedError)
163
+ end
164
+ end
165
+ end
166
+
167
+ describe '#auth_hash' do
168
+ subject do
169
+ klass = Class.new
170
+ klass.send :include, OmniAuth::Strategy
171
+ klass.option :name, 'auth_hasher'
172
+ klass
173
+ end
174
+ let(:instance) { subject.new(app) }
175
+
176
+ it 'calls through to uid and info' do
177
+ expect(instance).to receive(:uid)
178
+ expect(instance).to receive(:info)
179
+ instance.auth_hash
180
+ end
181
+
182
+ it 'returns an AuthHash' do
183
+ allow(instance).to receive(:uid).and_return('123')
184
+ allow(instance).to receive(:info).and_return(:name => 'Hal Awesome')
185
+ hash = instance.auth_hash
186
+ expect(hash).to be_kind_of(OmniAuth::AuthHash)
187
+ expect(hash.uid).to eq('123')
188
+ expect(hash.info.name).to eq('Hal Awesome')
189
+ end
190
+ end
191
+
192
+ describe '#initialize' do
193
+ context 'options extraction' do
194
+ it 'is the last argument if the last argument is a Hash' do
195
+ expect(ExampleStrategy.new(app, :abc => 123).options[:abc]).to eq(123)
196
+ end
197
+
198
+ it 'is the default options if any are provided' do
199
+ allow(ExampleStrategy).to receive(:default_options).and_return(OmniAuth::Strategy::Options.new(:abc => 123))
200
+ expect(ExampleStrategy.new(app).options.abc).to eq(123)
201
+ end
202
+ end
203
+
204
+ context 'custom args' do
205
+ subject do
206
+ c = Class.new
207
+ c.send(:include, OmniAuth::Strategy)
208
+ end
209
+
210
+ it 'sets options based on the arguments if they are supplied' do
211
+ subject.args [:abc, :def]
212
+ s = subject.new app, 123, 456
213
+ expect(s.options[:abc]).to eq(123)
214
+ expect(s.options[:def]).to eq(456)
215
+ end
216
+ end
217
+ end
218
+
219
+ describe '#call' do
220
+ it 'duplicates and calls' do
221
+ klass = Class.new
222
+ klass.send :include, OmniAuth::Strategy
223
+ instance = klass.new(app)
224
+ expect(instance).to receive(:dup).and_return(instance)
225
+ instance.call('rack.session' => {})
226
+ end
227
+ end
228
+
229
+ describe '#inspect' do
230
+ it 'returns the class name' do
231
+ expect(ExampleStrategy.new(app).inspect).to eq('#<ExampleStrategy>')
232
+ end
233
+ end
234
+
235
+ describe '#redirect' do
236
+ it 'uses javascript if :iframe is true' do
237
+ response = ExampleStrategy.new(app, :iframe => true).redirect('http://abc.com')
238
+ expect(response.last.body.first).to be_include('top.location.href')
239
+ end
240
+ end
241
+
242
+ describe '#callback_phase' do
243
+ subject do
244
+ c = Class.new
245
+ c.send(:include, OmniAuth::Strategy)
246
+ c.new(app)
247
+ end
248
+
249
+ it 'sets the auth hash' do
250
+ env = make_env
251
+ allow(subject).to receive(:env).and_return(env)
252
+ allow(subject).to receive(:auth_hash).and_return('AUTH HASH')
253
+ subject.callback_phase
254
+ expect(env['omniauth.auth']).to eq('AUTH HASH')
255
+ end
256
+ end
257
+
258
+ describe '#full_host' do
259
+ let(:strategy) { ExampleStrategy.new(app, {}) }
260
+ it 'remains calm when there is a pipe in the URL' do
261
+ strategy.call!(make_env('/whatever', 'rack.url_scheme' => 'http', 'SERVER_NAME' => 'facebook.lame', 'QUERY_STRING' => 'code=asofibasf|asoidnasd', 'SCRIPT_NAME' => '', 'SERVER_PORT' => 80))
262
+ expect { strategy.full_host }.not_to raise_error
263
+ end
264
+ end
265
+
266
+ describe '#uid' do
267
+ subject { fresh_strategy }
268
+ it "is the current class's uid if one exists" do
269
+ subject.uid { 'Hi' }
270
+ expect(subject.new(app).uid).to eq('Hi')
271
+ end
272
+
273
+ it 'inherits if it can' do
274
+ subject.uid { 'Hi' }
275
+ c = Class.new(subject)
276
+ expect(c.new(app).uid).to eq('Hi')
277
+ end
278
+ end
279
+
280
+ %w(info credentials extra).each do |fetcher|
281
+ subject { fresh_strategy }
282
+ it "is the current class's proc call if one exists" do
283
+ subject.send(fetcher) { {:abc => 123} }
284
+ expect(subject.new(app).send(fetcher)).to eq(:abc => 123)
285
+ end
286
+
287
+ it 'inherits by merging with preference for the latest class' do
288
+ subject.send(fetcher) { {:abc => 123, :def => 456} }
289
+ c = Class.new(subject)
290
+ c.send(fetcher) { {:abc => 789} }
291
+ expect(c.new(app).send(fetcher)).to eq(:abc => 789, :def => 456)
292
+ end
293
+ end
294
+
295
+ describe '#call' do
296
+ before(:all) do
297
+ @options = nil
298
+ end
299
+
300
+ let(:strategy) { ExampleStrategy.new(app, @options || {}) }
301
+
302
+ context 'omniauth.origin' do
303
+ it 'is set on the request phase' do
304
+ expect { strategy.call(make_env('/auth/test', 'HTTP_REFERER' => 'http://example.com/origin')) }.to raise_error('Request Phase')
305
+ expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('http://example.com/origin')
306
+ end
307
+
308
+ it 'is turned into an env variable on the callback phase' do
309
+ expect { strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'})) }.to raise_error('Callback Phase')
310
+ expect(strategy.last_env['omniauth.origin']).to eq('http://example.com/origin')
311
+ end
312
+
313
+ it 'sets from the params if provided' do
314
+ expect { strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'origin=/foo')) }.to raise_error('Request Phase')
315
+ expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('/foo')
316
+ end
317
+
318
+ it 'is set on the failure env' do
319
+ expect(OmniAuth.config).to receive(:on_failure).and_return(lambda { |env| env })
320
+ @options = {:failure => :forced_fail}
321
+ strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => '/awesome'}))
322
+ end
323
+
324
+ context 'with script_name' do
325
+ it 'is set on the request phase, containing full path' do
326
+ env = {'HTTP_REFERER' => 'http://example.com/sub_uri/origin', 'SCRIPT_NAME' => '/sub_uri'}
327
+ expect { strategy.call(make_env('/auth/test', env)) }.to raise_error('Request Phase')
328
+ expect(strategy.last_env['rack.session']['omniauth.origin']).to eq('http://example.com/sub_uri/origin')
329
+ end
330
+
331
+ it 'is turned into an env variable on the callback phase, containing full path' do
332
+ env = {
333
+ 'rack.session' => {'omniauth.origin' => 'http://example.com/sub_uri/origin'},
334
+ 'SCRIPT_NAME' => '/sub_uri',
335
+ }
336
+
337
+ expect { strategy.call(make_env('/auth/test/callback', env)) }.to raise_error('Callback Phase')
338
+ expect(strategy.last_env['omniauth.origin']).to eq('http://example.com/sub_uri/origin')
339
+ end
340
+ end
341
+ end
342
+
343
+ context 'default paths' do
344
+ it 'uses the default request path' do
345
+ expect { strategy.call(make_env) }.to raise_error('Request Phase')
346
+ end
347
+
348
+ it 'is case insensitive on request path' do
349
+ expect { strategy.call(make_env('/AUTH/Test')) }.to raise_error('Request Phase')
350
+ end
351
+
352
+ it 'is case insensitive on callback path' do
353
+ expect { strategy.call(make_env('/AUTH/TeSt/CaLlBAck')) }.to raise_error('Callback Phase')
354
+ end
355
+
356
+ it 'uses the default callback path' do
357
+ expect { strategy.call(make_env('/auth/test/callback')) }.to raise_error('Callback Phase')
358
+ end
359
+
360
+ it 'strips trailing spaces on request' do
361
+ expect { strategy.call(make_env('/auth/test/')) }.to raise_error('Request Phase')
362
+ end
363
+
364
+ it 'strips trailing spaces on callback' do
365
+ expect { strategy.call(make_env('/auth/test/callback/')) }.to raise_error('Callback Phase')
366
+ end
367
+
368
+ context 'callback_url' do
369
+ it 'uses the default callback_path' do
370
+ expect(strategy).to receive(:full_host).and_return('http://example.com')
371
+
372
+ expect { strategy.call(make_env) }.to raise_error('Request Phase')
373
+
374
+ expect(strategy.callback_url).to eq('http://example.com/auth/test/callback')
375
+ end
376
+
377
+ it 'preserves the query parameters' do
378
+ allow(strategy).to receive(:full_host).and_return('http://example.com')
379
+ begin
380
+ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'id=5'))
381
+ rescue RuntimeError
382
+ end
383
+ expect(strategy.callback_url).to eq('http://example.com/auth/test/callback?id=5')
384
+ end
385
+
386
+ it 'consider script name' do
387
+ allow(strategy).to receive(:full_host).and_return('http://example.com')
388
+ begin
389
+ strategy.call(make_env('/auth/test', 'SCRIPT_NAME' => '/sub_uri'))
390
+ rescue RuntimeError
391
+ end
392
+ expect(strategy.callback_url).to eq('http://example.com/sub_uri/auth/test/callback')
393
+ end
394
+ end
395
+ end
396
+
397
+ context ':form option' do
398
+ it 'calls through to the supplied form option if one exists' do
399
+ strategy.options.form = lambda { |_env| 'Called me!' }
400
+ expect(strategy.call(make_env('/auth/test'))).to eq('Called me!')
401
+ end
402
+
403
+ it 'calls through to the app if :form => true is set as an option' do
404
+ strategy.options.form = true
405
+ expect(strategy.call(make_env('/auth/test'))).to eq(app.call(make_env('/auth/test')))
406
+ end
407
+ end
408
+
409
+ context 'dynamic paths' do
410
+ it 'runs the request phase if the custom request path evaluator is truthy' do
411
+ @options = {:request_path => lambda { |_env| true }}
412
+ expect { strategy.call(make_env('/asoufibasfi')) }.to raise_error('Request Phase')
413
+ end
414
+
415
+ it 'runs the callback phase if the custom callback path evaluator is truthy' do
416
+ @options = {:callback_path => lambda { |_env| true }}
417
+ expect { strategy.call(make_env('/asoufiasod')) }.to raise_error('Callback Phase')
418
+ end
419
+
420
+ it 'provides a custom callback path if request_path evals to a string' do
421
+ strategy_instance = fresh_strategy.new(nil, :request_path => lambda { |_env| '/auth/boo/callback/22' })
422
+ expect(strategy_instance.callback_path).to eq('/auth/boo/callback/22')
423
+ end
424
+
425
+ it 'correctly reports the callback path when the custom callback path evaluator is truthy' do
426
+ strategy_instance = ExampleStrategy.new(app, :callback_path => lambda { |env| env['PATH_INFO'] == '/auth/bish/bosh/callback' })
427
+
428
+ expect { strategy_instance.call(make_env('/auth/bish/bosh/callback')) }.to raise_error('Callback Phase')
429
+ expect(strategy_instance.callback_path).to eq('/auth/bish/bosh/callback')
430
+ end
431
+ end
432
+
433
+ context 'custom paths' do
434
+ it 'uses a custom request_path if one is provided' do
435
+ @options = {:request_path => '/awesome'}
436
+ expect { strategy.call(make_env('/awesome')) }.to raise_error('Request Phase')
437
+ end
438
+
439
+ it 'uses a custom callback_path if one is provided' do
440
+ @options = {:callback_path => '/radical'}
441
+ expect { strategy.call(make_env('/radical')) }.to raise_error('Callback Phase')
442
+ end
443
+
444
+ context 'callback_url' do
445
+ it 'uses a custom callback_path if one is provided' do
446
+ @options = {:callback_path => '/radical'}
447
+ expect(strategy).to receive(:full_host).and_return('http://example.com')
448
+
449
+ expect { strategy.call(make_env('/radical')) }.to raise_error('Callback Phase')
450
+
451
+ expect(strategy.callback_url).to eq('http://example.com/radical')
452
+ end
453
+
454
+ it 'preserves the query parameters' do
455
+ @options = {:callback_path => '/radical'}
456
+ allow(strategy).to receive(:full_host).and_return('http://example.com')
457
+ begin
458
+ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'id=5'))
459
+ rescue RuntimeError
460
+ end
461
+ expect(strategy.callback_url).to eq('http://example.com/radical?id=5')
462
+ end
463
+ end
464
+ end
465
+
466
+ context 'custom prefix' do
467
+ before do
468
+ @options = {:path_prefix => '/wowzers'}
469
+ end
470
+
471
+ it 'uses a custom prefix for request' do
472
+ expect { strategy.call(make_env('/wowzers/test')) }.to raise_error('Request Phase')
473
+ end
474
+
475
+ it 'uses a custom prefix for callback' do
476
+ expect { strategy.call(make_env('/wowzers/test/callback')) }.to raise_error('Callback Phase')
477
+ end
478
+
479
+ context 'callback_url' do
480
+ it 'uses a custom prefix' do
481
+ expect(strategy).to receive(:full_host).and_return('http://example.com')
482
+
483
+ expect { strategy.call(make_env('/wowzers/test')) }.to raise_error('Request Phase')
484
+
485
+ expect(strategy.callback_url).to eq('http://example.com/wowzers/test/callback')
486
+ end
487
+
488
+ it 'preserves the query parameters' do
489
+ allow(strategy).to receive(:full_host).and_return('http://example.com')
490
+ begin
491
+ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'id=5'))
492
+ rescue RuntimeError
493
+ end
494
+ expect(strategy.callback_url).to eq('http://example.com/wowzers/test/callback?id=5')
495
+ end
496
+ end
497
+ end
498
+
499
+ context 'request method restriction' do
500
+ before do
501
+ OmniAuth.config.allowed_request_methods = [:post]
502
+ end
503
+
504
+ it 'does not allow a request method of the wrong type' do
505
+ expect { strategy.call(make_env) }.not_to raise_error
506
+ end
507
+
508
+ it 'allows a request method of the correct type' do
509
+ expect { strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'POST')) }.to raise_error('Request Phase')
510
+ end
511
+
512
+ after do
513
+ OmniAuth.config.allowed_request_methods = [:get, :post]
514
+ end
515
+ end
516
+
517
+ context 'receiving an OPTIONS request' do
518
+ shared_examples_for 'an OPTIONS request' do
519
+ it 'responds with 200' do
520
+ expect(response[0]).to eq(200)
521
+ end
522
+
523
+ it 'sets the Allow header properly' do
524
+ expect(response[1]['Allow']).to eq('GET, POST')
525
+ end
526
+ end
527
+
528
+ context 'to the request path' do
529
+ let(:response) { strategy.call(make_env('/auth/test', 'REQUEST_METHOD' => 'OPTIONS')) }
530
+ it_behaves_like 'an OPTIONS request'
531
+ end
532
+
533
+ context 'to the request path' do
534
+ let(:response) { strategy.call(make_env('/auth/test/callback', 'REQUEST_METHOD' => 'OPTIONS')) }
535
+ it_behaves_like 'an OPTIONS request'
536
+ end
537
+
538
+ context 'to some other path' do
539
+ it 'does not short-circuit the request' do
540
+ env = make_env('/other', 'REQUEST_METHOD' => 'OPTIONS')
541
+ expect(strategy.call(env)).to eq(app.call(env))
542
+ end
543
+ end
544
+ end
545
+
546
+ context 'test mode' do
547
+ let(:app) do
548
+ # In test mode, the underlying app shouldn't be called on request phase.
549
+ lambda { |_env| [404, {'Content-Type' => 'text/html'}, []] }
550
+ end
551
+
552
+ before do
553
+ OmniAuth.config.test_mode = true
554
+ end
555
+
556
+ it 'short circuits the request phase entirely' do
557
+ response = strategy.call(make_env)
558
+ expect(response[0]).to eq(302)
559
+ expect(response[1]['Location']).to eq('/auth/test/callback')
560
+ end
561
+
562
+ it 'is case insensitive on request path' do
563
+ expect(strategy.call(make_env('/AUTH/Test'))[0]).to eq(302)
564
+ end
565
+
566
+ it 'respects SCRIPT_NAME (a.k.a. BaseURI)' do
567
+ response = strategy.call(make_env('/auth/test', 'SCRIPT_NAME' => '/sub_uri'))
568
+ expect(response[1]['Location']).to eq('/sub_uri/auth/test/callback')
569
+ end
570
+
571
+ it 'redirects on failure' do
572
+ response = OmniAuth.config.on_failure.call(make_env('/auth/test', 'omniauth.error.type' => 'error'))
573
+ expect(response[0]).to eq(302)
574
+ expect(response[1]['Location']).to eq('/auth/failure?message=error')
575
+ end
576
+
577
+ it 'respects SCRIPT_NAME (a.k.a. BaseURI) on failure' do
578
+ response = OmniAuth.config.on_failure.call(make_env('/auth/test', 'SCRIPT_NAME' => '/sub_uri', 'omniauth.error.type' => 'error'))
579
+ expect(response[0]).to eq(302)
580
+ expect(response[1]['Location']).to eq('/sub_uri/auth/failure?message=error')
581
+ end
582
+
583
+ it 'is case insensitive on callback path' do
584
+ expect(strategy.call(make_env('/AUTH/TeSt/CaLlBAck')).first).to eq(strategy.call(make_env('/auth/test/callback')).first)
585
+ end
586
+
587
+ it 'maintains host and port' do
588
+ response = strategy.call(make_env('/auth/test', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.org', 'SERVER_PORT' => 3000))
589
+ expect(response[1]['Location']).to eq('http://example.org:3000/auth/test/callback')
590
+ end
591
+
592
+ it 'maintains query string parameters' do
593
+ response = strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'cheese=stilton'))
594
+ expect(response[1]['Location']).to eq('/auth/test/callback?cheese=stilton')
595
+ end
596
+
597
+ it 'does not short circuit requests outside of authentication' do
598
+ expect(strategy.call(make_env('/'))).to eq(app.call(make_env('/')))
599
+ end
600
+
601
+ it 'responds with the default hash if none is set' do
602
+ OmniAuth.config.mock_auth[:test] = nil
603
+
604
+ strategy.call make_env('/auth/test/callback')
605
+ expect(strategy.env['omniauth.auth']['uid']).to eq('1234')
606
+ end
607
+
608
+ it 'responds with a provider-specific hash if one is set' do
609
+ OmniAuth.config.mock_auth[:test] = {
610
+ 'uid' => 'abc',
611
+ }
612
+
613
+ strategy.call make_env('/auth/test/callback')
614
+ expect(strategy.env['omniauth.auth']['uid']).to eq('abc')
615
+ end
616
+
617
+ it 'simulates login failure if mocked data is set as a symbol' do
618
+ OmniAuth.config.mock_auth[:test] = :invalid_credentials
619
+
620
+ strategy.call make_env('/auth/test/callback')
621
+ expect(strategy.env['omniauth.error.type']).to eq(:invalid_credentials)
622
+ end
623
+
624
+ it 'sets omniauth.origin on the request phase' do
625
+ strategy.call(make_env('/auth/test', 'HTTP_REFERER' => 'http://example.com/origin'))
626
+ expect(strategy.env['rack.session']['omniauth.origin']).to eq('http://example.com/origin')
627
+ end
628
+
629
+ it 'sets omniauth.origin from the params if provided' do
630
+ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'origin=/foo'))
631
+ expect(strategy.env['rack.session']['omniauth.origin']).to eq('/foo')
632
+ end
633
+
634
+ it 'turns omniauth.origin into an env variable on the callback phase' do
635
+ OmniAuth.config.mock_auth[:test] = {}
636
+
637
+ strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'}))
638
+ expect(strategy.env['omniauth.origin']).to eq('http://example.com/origin')
639
+ end
640
+
641
+ it 'executes callback hook on the callback phase' do
642
+ OmniAuth.config.mock_auth[:test] = {}
643
+ OmniAuth.config.before_callback_phase do |env|
644
+ env['foobar'] = 'baz'
645
+ end
646
+ strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.origin' => 'http://example.com/origin'}))
647
+ expect(strategy.env['foobar']).to eq('baz')
648
+ end
649
+
650
+ it 'sets omniauth.params on the request phase' do
651
+ OmniAuth.config.mock_auth[:test] = {}
652
+
653
+ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'foo=bar'))
654
+ expect(strategy.env['rack.session']['omniauth.params']).to eq('foo' => 'bar')
655
+ end
656
+
657
+ it 'executes request hook on the request phase' do
658
+ OmniAuth.config.mock_auth[:test] = {}
659
+ OmniAuth.config.before_request_phase do |env|
660
+ env['foobar'] = 'baz'
661
+ end
662
+ strategy.call(make_env('/auth/test', 'QUERY_STRING' => 'foo=bar'))
663
+ expect(strategy.env['foobar']).to eq('baz')
664
+ end
665
+
666
+ it 'turns omniauth.params into an env variable on the callback phase' do
667
+ OmniAuth.config.mock_auth[:test] = {}
668
+
669
+ strategy.call(make_env('/auth/test/callback', 'rack.session' => {'omniauth.params' => {'foo' => 'bar'}}))
670
+ expect(strategy.env['omniauth.params']).to eq('foo' => 'bar')
671
+ end
672
+
673
+ after do
674
+ OmniAuth.config.test_mode = false
675
+ end
676
+ end
677
+
678
+ context 'custom full_host' do
679
+ before do
680
+ OmniAuth.config.test_mode = true
681
+ end
682
+
683
+ it 'is the string when a string is there' do
684
+ OmniAuth.config.full_host = 'my.host.com'
685
+ expect(strategy.full_host).to eq('my.host.com')
686
+ end
687
+
688
+ it 'runs the proc with the env when it is a proc' do
689
+ OmniAuth.config.full_host = proc { |env| env['HOST'] }
690
+ strategy.call(make_env('/auth/test', 'HOST' => 'my.host.net'))
691
+ expect(strategy.full_host).to eq('my.host.net')
692
+ end
693
+
694
+ it "is based on the request if it's not a string nor a proc" do
695
+ OmniAuth.config.full_host = nil
696
+ strategy.call(make_env('/whatever', 'rack.url_scheme' => 'http', 'SERVER_NAME' => 'my.host.net', 'SERVER_PORT' => 80))
697
+ expect(strategy.full_host).to eq('http://my.host.net')
698
+ end
699
+
700
+ it 'honors HTTP_X_FORWARDED_PROTO if present' do
701
+ OmniAuth.config.full_host = nil
702
+ strategy.call(make_env('/whatever', 'HTTP_X_FORWARDED_PROTO' => 'https', 'rack.url_scheme' => 'http', 'SERVER_NAME' => 'my.host.net', 'SERVER_PORT' => 443))
703
+ expect(strategy.full_host).to eq('https://my.host.net')
704
+ end
705
+
706
+ after do
707
+ OmniAuth.config.full_host = nil
708
+ OmniAuth.config.test_mode = false
709
+ end
710
+ end
711
+ end
712
+
713
+ context 'setup phase' do
714
+ before do
715
+ OmniAuth.config.test_mode = true
716
+ end
717
+
718
+ context 'when options[:setup] = true' do
719
+ let(:strategy) do
720
+ ExampleStrategy.new(app, :setup => true)
721
+ end
722
+
723
+ let(:app) do
724
+ lambda do |env|
725
+ env['omniauth.strategy'].options[:awesome] = 'sauce' if env['PATH_INFO'] == '/auth/test/setup'
726
+ [404, {}, 'Awesome']
727
+ end
728
+ end
729
+
730
+ it 'calls through to /auth/:provider/setup' do
731
+ strategy.call(make_env('/auth/test'))
732
+ expect(strategy.options[:awesome]).to eq('sauce')
733
+ end
734
+
735
+ it 'does not call through on a non-omniauth endpoint' do
736
+ strategy.call(make_env('/somewhere/else'))
737
+ expect(strategy.options[:awesome]).not_to eq('sauce')
738
+ end
739
+ end
740
+
741
+ context 'when options[:setup] is an app' do
742
+ let(:setup_proc) do
743
+ proc do |env|
744
+ env['omniauth.strategy'].options[:awesome] = 'sauce'
745
+ end
746
+ end
747
+
748
+ let(:strategy) { ExampleStrategy.new(app, :setup => setup_proc) }
749
+
750
+ it 'does not call the app on a non-omniauth endpoint' do
751
+ strategy.call(make_env('/somehwere/else'))
752
+ expect(strategy.options[:awesome]).not_to eq('sauce')
753
+ end
754
+
755
+ it 'calls the rack app' do
756
+ strategy.call(make_env('/auth/test'))
757
+ expect(strategy.options[:awesome]).to eq('sauce')
758
+ end
759
+ end
760
+
761
+ after do
762
+ OmniAuth.config.test_mode = false
763
+ end
764
+ end
765
+ end