omniauth-globus 0.8.3
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 +7 -0
- data/.gitignore +50 -0
- data/.rubocop.yml +209 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +98 -0
- data/LICENSE +21 -0
- data/README.md +3 -0
- data/lib/omniauth/globus/version.rb +7 -0
- data/lib/omniauth/globus.rb +3 -0
- data/lib/omniauth/strategies/globus.rb +154 -0
- data/lib/omniauth-globus.rb +1 -0
- data/omniauth-globus.gemspec +35 -0
- data/spec/fixtures/access_token.json +9 -0
- data/spec/fixtures/request_info.json +213 -0
- data/spec/omniauth/strategies/globus_spec.rb +514 -0
- data/spec/rubocop_spec.rb +9 -0
- data/spec/spec_helper.rb +25 -0
- metadata +213 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'omniauth-globus'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
|
|
8
|
+
describe OmniAuth::Strategies::Globus do
|
|
9
|
+
let(:request) { double('Request', params: {}, cookies: {}, env: {}) }
|
|
10
|
+
let(:app) do
|
|
11
|
+
lambda do
|
|
12
|
+
[200, {}, ['Hello.']]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
subject do
|
|
17
|
+
OmniAuth::Strategies::Globus.new(app, 'appid', 'secret', @options || {}).tap do |strategy|
|
|
18
|
+
allow(strategy).to receive(:request) do
|
|
19
|
+
request
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
before do
|
|
25
|
+
OmniAuth.config.test_mode = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
after do
|
|
29
|
+
OmniAuth.config.test_mode = false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe '#client_options' do
|
|
33
|
+
it 'has correct site' do
|
|
34
|
+
expect(subject.client.site).to eq('https://auth.globus.org')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'has correct authorize_url' do
|
|
38
|
+
expect(subject.client.options[:authorize_url]).to eq('https://auth.globus.org/v2/oauth2/authorize')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'has correct token_url' do
|
|
42
|
+
expect(subject.client.options[:token_url]).to eq('https://auth.globus.org/v2/oauth2/token')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe 'overrides' do
|
|
46
|
+
context 'as strings' do
|
|
47
|
+
it 'should allow overriding the site' do
|
|
48
|
+
@options = { client_options: { 'site' => 'https://example.com' } }
|
|
49
|
+
expect(subject.client.site).to eq('https://example.com')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'should allow overriding the authorization_endpoint' do
|
|
53
|
+
@options = { client_options: { 'authorization_endpoint' => 'https://example.com' } }
|
|
54
|
+
expect(subject.client.options[:authorization_endpoint]).to eq('https://example.com')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'should allow overriding the token_endpoint' do
|
|
58
|
+
@options = { client_options: { 'token_endpoint' => 'https://example.com' } }
|
|
59
|
+
expect(subject.client.options[:token_endpoint]).to eq('https://example.com')
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'as symbols' do
|
|
64
|
+
it 'should allow overriding the site' do
|
|
65
|
+
@options = { client_options: { site: 'https://example.com' } }
|
|
66
|
+
expect(subject.client.site).to eq('https://example.com')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'should allow overriding the authorization_endpoint' do
|
|
70
|
+
@options = { client_options: { authorization_endpoint: 'https://example.com' } }
|
|
71
|
+
expect(subject.client.options[:authorization_endpoint]).to eq('https://example.com')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'should allow overriding the token_endpoint' do
|
|
75
|
+
@options = { client_options: { token_endpoint: 'https://example.com' } }
|
|
76
|
+
expect(subject.client.options[:token_endpoint]).to eq('https://example.com')
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#authorize_options' do
|
|
83
|
+
%i[access_type login_hint prompt scope state device_id device_name].each do |k|
|
|
84
|
+
it "should support #{k}" do
|
|
85
|
+
@options = { k => 'http://someval' }
|
|
86
|
+
expect(subject.authorize_params[k.to_s]).to eq('http://someval')
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe 'redirect_uri' do
|
|
91
|
+
it 'should default to nil' do
|
|
92
|
+
@options = {}
|
|
93
|
+
expect(subject.authorize_params['redirect_uri']).to eq(nil)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'should set the redirect_uri parameter if present' do
|
|
97
|
+
@options = { redirect_uri: 'https://example.com' }
|
|
98
|
+
expect(subject.authorize_params['redirect_uri']).to eq('https://example.com')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe 'access_type' do
|
|
103
|
+
it 'should default to "offline"' do
|
|
104
|
+
@options = {}
|
|
105
|
+
expect(subject.authorize_params['access_type']).to eq('offline')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'should set the access_type parameter if present' do
|
|
109
|
+
@options = { access_type: 'online' }
|
|
110
|
+
expect(subject.authorize_params['access_type']).to eq('online')
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe 'login_hint' do
|
|
115
|
+
it 'should default to nil' do
|
|
116
|
+
expect(subject.authorize_params['login_hint']).to eq(nil)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'should set the login_hint parameter if present' do
|
|
120
|
+
@options = { login_hint: 'john@example.com' }
|
|
121
|
+
expect(subject.authorize_params['login_hint']).to eq('john@example.com')
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe 'prompt' do
|
|
126
|
+
it 'should default to nil' do
|
|
127
|
+
expect(subject.authorize_params['prompt']).to eq(nil)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'should set the prompt parameter if present' do
|
|
131
|
+
@options = { prompt: 'consent select_account' }
|
|
132
|
+
expect(subject.authorize_params['prompt']).to eq('consent select_account')
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
describe 'request_visible_actions' do
|
|
137
|
+
it 'should default to nil' do
|
|
138
|
+
expect(subject.authorize_params['request_visible_actions']).to eq(nil)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it 'should set the request_visible_actions parameter if present' do
|
|
142
|
+
@options = { request_visible_actions: 'something' }
|
|
143
|
+
expect(subject.authorize_params['request_visible_actions']).to eq('something')
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
describe 'include_granted_scopes' do
|
|
148
|
+
it 'should default to nil' do
|
|
149
|
+
expect(subject.authorize_params['include_granted_scopes']).to eq(nil)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'should set the include_granted_scopes parameter if present' do
|
|
153
|
+
@options = { include_granted_scopes: 'true' }
|
|
154
|
+
expect(subject.authorize_params['include_granted_scopes']).to eq('true')
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe 'scope' do
|
|
159
|
+
it 'should leave base scopes as is' do
|
|
160
|
+
@options = { scope: 'profile' }
|
|
161
|
+
expect(subject.authorize_params['scope']).to eq('profile')
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it 'should join scopes' do
|
|
165
|
+
@options = { scope: 'profile,email' }
|
|
166
|
+
expect(subject.authorize_params['scope']).to eq('profile email')
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'should deal with whitespace when joining scopes' do
|
|
170
|
+
@options = { scope: 'profile, email' }
|
|
171
|
+
expect(subject.authorize_params['scope']).to eq('profile email')
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'should set default scope to openid, profile, email' do
|
|
175
|
+
expect(subject.authorize_params['scope']).to eq("openid profile email")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'should support space delimited scopes' do
|
|
179
|
+
@options = { scope: 'profile email' }
|
|
180
|
+
expect(subject.authorize_params['scope']).to eq('profile email')
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'should support extremely badly formed scopes' do
|
|
184
|
+
@options = { scope: 'profile email,foo,steve yeah' }
|
|
185
|
+
expect(subject.authorize_params['scope']).to eq('profile email foo steve yeah')
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
describe 'state' do
|
|
190
|
+
it 'should set the state parameter' do
|
|
191
|
+
@options = { state: 'some_state' }
|
|
192
|
+
expect(subject.authorize_params['state']).to eq('some_state')
|
|
193
|
+
expect(subject.authorize_params[:state]).to eq('some_state')
|
|
194
|
+
expect(subject.session['omniauth.state']).to eq('some_state')
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it 'should set the omniauth.state dynamically' do
|
|
198
|
+
allow(subject).to receive(:request) { double('Request', params: { 'state' => 'some_state' }, env: {}) }
|
|
199
|
+
expect(subject.authorize_params['state']).to eq('some_state')
|
|
200
|
+
expect(subject.authorize_params[:state]).to eq('some_state')
|
|
201
|
+
expect(subject.session['omniauth.state']).to eq('some_state')
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
describe 'overrides' do
|
|
206
|
+
it 'should include top-level options that are marked as :authorize_options' do
|
|
207
|
+
@options = { authorize_options: %i[scope foo request_visible_actions], scope: 'http://bar', foo: 'baz', request_visible_actions: 'something' }
|
|
208
|
+
expect(subject.authorize_params['scope']).to eq('http://bar')
|
|
209
|
+
expect(subject.authorize_params['foo']).to eq('baz')
|
|
210
|
+
expect(subject.authorize_params['request_visible_actions']).to eq('something')
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
describe 'request overrides' do
|
|
214
|
+
%i[access_type login_hint prompt scope state].each do |k|
|
|
215
|
+
context "authorize option #{k}" do
|
|
216
|
+
let(:request) { double('Request', params: { k.to_s => 'http://example.com' }, cookies: {}, env: {}) }
|
|
217
|
+
|
|
218
|
+
it "should set the #{k} authorize option dynamically in the request" do
|
|
219
|
+
@options = { k: '' }
|
|
220
|
+
expect(subject.authorize_params[k.to_s]).to eq('http://example.com')
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe 'custom authorize_options' do
|
|
226
|
+
let(:request) { double('Request', params: { 'foo' => 'something' }, cookies: {}, env: {}) }
|
|
227
|
+
|
|
228
|
+
it 'should support request overrides from custom authorize_options' do
|
|
229
|
+
@options = { authorize_options: [:foo], foo: '' }
|
|
230
|
+
expect(subject.authorize_params['foo']).to eq('something')
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
describe '#authorize_params' do
|
|
238
|
+
it 'should include any authorize params passed in the :authorize_params option' do
|
|
239
|
+
@options = { authorize_params: { request_visible_actions: 'something', foo: 'bar', baz: 'zip' }, bad: 'not_included' }
|
|
240
|
+
expect(subject.authorize_params['request_visible_actions']).to eq('something')
|
|
241
|
+
expect(subject.authorize_params['foo']).to eq('bar')
|
|
242
|
+
expect(subject.authorize_params['baz']).to eq('zip')
|
|
243
|
+
expect(subject.authorize_params['bad']).to eq(nil)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
describe '#token_params' do
|
|
248
|
+
it 'should include any token params passed in the :token_params option' do
|
|
249
|
+
@options = { token_params: { foo: 'bar', baz: 'zip' } }
|
|
250
|
+
expect(subject.token_params['foo']).to eq('bar')
|
|
251
|
+
expect(subject.token_params['baz']).to eq('zip')
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
describe '#token_options' do
|
|
256
|
+
it 'should include top-level options that are marked as :token_options' do
|
|
257
|
+
@options = { token_options: %i[scope foo], scope: 'bar', foo: 'baz', bad: 'not_included' }
|
|
258
|
+
expect(subject.token_params['scope']).to eq('bar')
|
|
259
|
+
expect(subject.token_params['foo']).to eq('baz')
|
|
260
|
+
expect(subject.token_params['bad']).to eq(nil)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
describe '#callback_path' do
|
|
265
|
+
it 'has the correct default callback path' do
|
|
266
|
+
expect(subject.callback_path).to eq("/auth/globus/callback")
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it 'should set the callback_path parameter if present' do
|
|
270
|
+
@options = { callback_path: '/auth/foo/callback' }
|
|
271
|
+
expect(subject.callback_path).to eq('/auth/foo/callback')
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
describe '#info' do
|
|
276
|
+
let(:client) do
|
|
277
|
+
OAuth2::Client.new('abc', 'def') do |builder|
|
|
278
|
+
builder.request :url_encoded
|
|
279
|
+
builder.adapter :test do |stub|
|
|
280
|
+
stub.get("/v2/oauth2/userinfo") { [200, { "content-type" => "application/json" }, response_hash.to_json] }
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
|
|
285
|
+
before { allow(subject).to receive(:access_token).and_return(access_token) }
|
|
286
|
+
|
|
287
|
+
context 'with email' do
|
|
288
|
+
let(:response_hash) do
|
|
289
|
+
{ email: 'something@domain.invalid' }
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it 'should return email' do
|
|
293
|
+
expect(subject.info[:email]).to eq('something@domain.invalid')
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
describe '#extra' do
|
|
299
|
+
let(:client) do
|
|
300
|
+
OAuth2::Client.new('abc', 'def') do |builder|
|
|
301
|
+
builder.request :url_encoded
|
|
302
|
+
builder.adapter :test do |stub|
|
|
303
|
+
stub.get('/v2/oauth2/userinfo') { [200, { 'content-type' => 'application/json' }, '{"sub": "12345"}'] }
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
let(:access_token) { OAuth2::AccessToken.from_hash(client, {}) }
|
|
308
|
+
|
|
309
|
+
before { allow(subject).to receive(:access_token).and_return(access_token) }
|
|
310
|
+
|
|
311
|
+
describe 'id_token' do
|
|
312
|
+
shared_examples 'id_token issued by valid issuer' do |issuer| # rubocop:disable Metrics/BlockLength
|
|
313
|
+
context 'when the id_token is passed into the access token' do
|
|
314
|
+
let(:token_info) do
|
|
315
|
+
{
|
|
316
|
+
identity_provider_display_name: "ORCID",
|
|
317
|
+
sub: "abc",
|
|
318
|
+
preferred_username: "0000-0003-1419-2405@orcid.org",
|
|
319
|
+
identity_provider: "def",
|
|
320
|
+
organization: "DataCite",
|
|
321
|
+
email: "mfenner@datacite.org",
|
|
322
|
+
name: "Martin Fenner",
|
|
323
|
+
exp: Time.now.to_i + 3600,
|
|
324
|
+
iss: "https://auth.globus.org"
|
|
325
|
+
}
|
|
326
|
+
end
|
|
327
|
+
let(:id_token) { JWT.encode(token_info, 'secret') }
|
|
328
|
+
let(:access_token) { OAuth2::AccessToken.from_hash(client, 'id_token' => id_token) }
|
|
329
|
+
|
|
330
|
+
it 'should include id_token when set on the access_token' do
|
|
331
|
+
expect(subject.extra).to include(id_token: id_token)
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
it_behaves_like 'id_token issued by valid issuer', 'https://auth.globus.org'
|
|
337
|
+
|
|
338
|
+
context 'when the id_token is issued by an invalid issuer' do
|
|
339
|
+
let(:token_info) do
|
|
340
|
+
{
|
|
341
|
+
identity_provider_display_name: "ORCID",
|
|
342
|
+
sub: "abc",
|
|
343
|
+
preferred_username: "0000-0003-1419-2405@orcid.org",
|
|
344
|
+
identity_provider: "def",
|
|
345
|
+
organization: "DataCite",
|
|
346
|
+
email: "mfenner@datacite.org",
|
|
347
|
+
name: "Martin Fenner",
|
|
348
|
+
exp: Time.now.to_i + 3600,
|
|
349
|
+
iss: "https://fake.globus.org"
|
|
350
|
+
}
|
|
351
|
+
end
|
|
352
|
+
let(:id_token) { JWT.encode(token_info, 'secret') }
|
|
353
|
+
let(:access_token) { OAuth2::AccessToken.from_hash(client, 'id_token' => id_token) }
|
|
354
|
+
|
|
355
|
+
it 'raises JWT::InvalidIssuerError' do
|
|
356
|
+
expect { subject.extra }.to raise_error(JWT::InvalidIssuerError)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
context 'when the id_token is missing' do
|
|
361
|
+
it 'should not include id_token' do
|
|
362
|
+
expect(subject.extra).not_to have_key(:id_token)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
it 'should not include id_info' do
|
|
366
|
+
expect(subject.extra).not_to have_key(:id_info)
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
describe 'raw_info' do
|
|
372
|
+
context 'when skip_info is true' do
|
|
373
|
+
before { subject.options[:skip_info] = true }
|
|
374
|
+
|
|
375
|
+
it 'should not include raw_info' do
|
|
376
|
+
expect(subject.extra).not_to have_key(:raw_info)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
context 'when skip_info is false' do
|
|
381
|
+
before { subject.options[:skip_info] = false }
|
|
382
|
+
|
|
383
|
+
it 'should include raw_info' do
|
|
384
|
+
expect(subject.extra[:raw_info]).to eq('sub' => '12345')
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
describe 'build_access_token' do
|
|
391
|
+
it 'should use a hybrid authorization request_uri if this is an AJAX request with a code parameter' do
|
|
392
|
+
allow(request).to receive(:xhr?).and_return(true)
|
|
393
|
+
allow(request).to receive(:params).and_return('code' => 'valid_code')
|
|
394
|
+
|
|
395
|
+
client = double(:client)
|
|
396
|
+
auth_code = double(:auth_code)
|
|
397
|
+
allow(client).to receive(:auth_code).and_return(auth_code)
|
|
398
|
+
expect(subject).to receive(:client).and_return(client)
|
|
399
|
+
expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'postmessage' }, {})
|
|
400
|
+
|
|
401
|
+
expect(subject).not_to receive(:orig_build_access_token)
|
|
402
|
+
subject.build_access_token
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
it 'should use a hybrid authorization request_uri if this is an AJAX request (mobile) with a code parameter' do
|
|
406
|
+
allow(request).to receive(:xhr?).and_return(true)
|
|
407
|
+
allow(request).to receive(:params).and_return('code' => 'valid_code', 'redirect_uri' => '')
|
|
408
|
+
|
|
409
|
+
client = double(:client)
|
|
410
|
+
auth_code = double(:auth_code)
|
|
411
|
+
allow(client).to receive(:auth_code).and_return(auth_code)
|
|
412
|
+
expect(subject).to receive(:client).and_return(client)
|
|
413
|
+
expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: '' }, {})
|
|
414
|
+
|
|
415
|
+
expect(subject).not_to receive(:orig_build_access_token)
|
|
416
|
+
subject.build_access_token
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
it 'should use the request_uri from params if this not an AJAX request (request from installed app) with a code parameter' do
|
|
420
|
+
allow(request).to receive(:xhr?).and_return(false)
|
|
421
|
+
allow(request).to receive(:params).and_return('code' => 'valid_code', 'redirect_uri' => 'redirect_uri')
|
|
422
|
+
|
|
423
|
+
client = double(:client)
|
|
424
|
+
auth_code = double(:auth_code)
|
|
425
|
+
allow(client).to receive(:auth_code).and_return(auth_code)
|
|
426
|
+
expect(subject).to receive(:client).and_return(client)
|
|
427
|
+
expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'redirect_uri' }, {})
|
|
428
|
+
|
|
429
|
+
expect(subject).not_to receive(:orig_build_access_token)
|
|
430
|
+
subject.build_access_token
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
it 'should read access_token from hash if this is not an AJAX request with a code parameter' do
|
|
434
|
+
allow(request).to receive(:xhr?).and_return(false)
|
|
435
|
+
allow(request).to receive(:params).and_return('access_token' => 'valid_access_token')
|
|
436
|
+
expect(subject).to receive(:verify_token).with('valid_access_token').and_return true
|
|
437
|
+
expect(subject).to receive(:client).and_return(:client)
|
|
438
|
+
|
|
439
|
+
token = subject.build_access_token
|
|
440
|
+
expect(token).to be_instance_of(::OAuth2::AccessToken)
|
|
441
|
+
expect(token.token).to eq('valid_access_token')
|
|
442
|
+
expect(token.client).to eq(:client)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
it 'reads the code from a json request body' do
|
|
446
|
+
body = StringIO.new(%({"code":"json_access_token"}))
|
|
447
|
+
client = double(:client)
|
|
448
|
+
auth_code = double(:auth_code)
|
|
449
|
+
|
|
450
|
+
allow(request).to receive(:xhr?).and_return(false)
|
|
451
|
+
allow(request).to receive(:content_type).and_return('application/json')
|
|
452
|
+
allow(request).to receive(:body).and_return(body)
|
|
453
|
+
allow(client).to receive(:auth_code).and_return(auth_code)
|
|
454
|
+
expect(subject).to receive(:client).and_return(client)
|
|
455
|
+
|
|
456
|
+
expect(auth_code).to receive(:get_token).with('json_access_token', { redirect_uri: 'postmessage' }, {})
|
|
457
|
+
|
|
458
|
+
subject.build_access_token
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
it 'should use callback_url without query_string if this is not an AJAX request' do
|
|
462
|
+
allow(request).to receive(:xhr?).and_return(false)
|
|
463
|
+
allow(request).to receive(:params).and_return('code' => 'valid_code')
|
|
464
|
+
allow(request).to receive(:content_type).and_return('application/x-www-form-urlencoded')
|
|
465
|
+
|
|
466
|
+
client = double(:client)
|
|
467
|
+
auth_code = double(:auth_code)
|
|
468
|
+
allow(client).to receive(:auth_code).and_return(auth_code)
|
|
469
|
+
allow(subject).to receive(:callback_url).and_return('redirect_uri_without_query_string')
|
|
470
|
+
|
|
471
|
+
expect(subject).to receive(:client).and_return(client)
|
|
472
|
+
expect(auth_code).to receive(:get_token).with('valid_code', { redirect_uri: 'redirect_uri_without_query_string' }, {})
|
|
473
|
+
subject.build_access_token
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
describe 'verify_token' do
|
|
478
|
+
before(:each) do
|
|
479
|
+
subject.options.client_options[:connection_build] = proc do |builder|
|
|
480
|
+
builder.request :url_encoded
|
|
481
|
+
builder.adapter :test do |stub|
|
|
482
|
+
stub.get('/v2/oauth2/userinfo?access_token=valid_access_token') do
|
|
483
|
+
[200, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(
|
|
484
|
+
{
|
|
485
|
+
identity_provider_display_name: "ORCID",
|
|
486
|
+
sub: "abc",
|
|
487
|
+
preferred_username: "0000-0003-1419-2405@orcid.org",
|
|
488
|
+
identity_provider: "def",
|
|
489
|
+
organization: "DataCite",
|
|
490
|
+
email: "mfenner@datacite.org",
|
|
491
|
+
name: "Martin Fenner",
|
|
492
|
+
exp: 1568009648,
|
|
493
|
+
iss: "https://auth.globus.org"
|
|
494
|
+
}
|
|
495
|
+
)]
|
|
496
|
+
end
|
|
497
|
+
stub.get('/v2/oauth2/userinfo?access_token=invalid_access_token') do
|
|
498
|
+
[400, { 'Content-Type' => 'application/json; charset=UTF-8' }, JSON.dump(error_description: 'Invalid Value')]
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# it 'should verify token if access_token is valid' do
|
|
505
|
+
# expect(subject.send(:verify_token, 'valid_access_token')).to eq(true)
|
|
506
|
+
# end
|
|
507
|
+
|
|
508
|
+
it 'should raise error if access_token is invalid' do
|
|
509
|
+
expect do
|
|
510
|
+
subject.send(:verify_token, 'invalid_access_token')
|
|
511
|
+
end.to raise_error(OAuth2::Error)
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
Bundler.setup
|
|
5
|
+
|
|
6
|
+
require "simplecov"
|
|
7
|
+
SimpleCov.start
|
|
8
|
+
|
|
9
|
+
require "rspec"
|
|
10
|
+
require "rack/test"
|
|
11
|
+
require "webmock/rspec"
|
|
12
|
+
require "omniauth-globus"
|
|
13
|
+
|
|
14
|
+
def fixture_path
|
|
15
|
+
File.expand_path("fixtures", __dir__) + "/"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
RSpec.configure do |config|
|
|
19
|
+
config.include WebMock::API
|
|
20
|
+
config.include Rack::Test::Methods
|
|
21
|
+
config.extend OmniAuth::Test::StrategyMacros, type: :strategy
|
|
22
|
+
config.expect_with :rspec do |c|
|
|
23
|
+
c.syntax = :expect
|
|
24
|
+
end
|
|
25
|
+
end
|