signet 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,8 +15,7 @@
15
15
  require 'spec_helper'
16
16
 
17
17
  require 'signet/oauth_1/client'
18
- require 'httpadapter'
19
- require 'httpadapter/adapters/typhoeus'
18
+ require 'faraday'
20
19
  require 'stringio'
21
20
 
22
21
  def merge_body(chunked_body)
@@ -48,29 +47,23 @@ describe Signet::OAuth1::Client, 'configured for standard Google APIs' do
48
47
  end
49
48
 
50
49
  it 'should raise an error if the server gives an unexpected status' do
50
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
51
+ stub.post('/accounts/OAuthGetRequestToken') do
52
+ [509, {}, 'Rate limit hit or something.']
53
+ end
54
+ end
51
55
  (lambda do
52
- hydra = Typhoeus::Hydra.new
53
- stubbed_response = Typhoeus::Response.new(
54
- :code => 999,
55
- :headers => '',
56
- :body => 'Rate limit hit or something.'
57
- )
58
- hydra.stub(
59
- :post,
60
- 'https://www.google.com/accounts/OAuthGetRequestToken'
61
- ).and_return(stubbed_response)
62
- connection = HTTPAdapter::Connection.new(
63
- 'www.google.com', 443, hydra,
64
- :join => [:run, [], nil]
65
- )
56
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
57
+ builder.adapter(:test, stubs)
58
+ end
66
59
  @client.fetch_temporary_credential!(
67
- :adapter => HTTPAdapter::TyphoeusAdapter.new,
68
60
  :connection => connection,
69
61
  :additional_parameters => {
70
62
  :scope => 'https://www.google.com/m8/feeds/'
71
63
  }
72
64
  )
73
65
  end).should raise_error(Signet::AuthorizationError)
66
+ stubs.verify_stubbed_calls
74
67
  end
75
68
 
76
69
  it 'should be able to obtain temporary credentials for the Contacts API' do
@@ -111,28 +104,23 @@ describe Signet::OAuth1::Client, 'configured for standard Google APIs' do
111
104
  # We have to stub responses for the token credentials
112
105
 
113
106
  it 'should be able to obtain token credentials for the Contacts API' do
114
- hydra = Typhoeus::Hydra.new
115
- stubbed_response = Typhoeus::Response.new(
116
- :code => 200,
117
- :headers => '',
118
- :body => (
119
- 'oauth_token=1%2FYFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ&' +
120
- 'oauth_token_secret=Ew3YHAY4bcBryiOUvbdHGa57'
121
- )
122
- )
123
- hydra.stub(
124
- :post,
125
- 'https://www.google.com/accounts/OAuthGetAccessToken'
126
- ).and_return(stubbed_response)
127
- connection = HTTPAdapter::Connection.new(
128
- 'www.google.com', 443, hydra,
129
- :join => [:run, [], nil]
130
- )
107
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
108
+ stub.post('/accounts/OAuthGetAccessToken') do
109
+ [
110
+ 200,
111
+ {},
112
+ 'oauth_token=1%2FYFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ&' +
113
+ 'oauth_token_secret=Ew3YHAY4bcBryiOUvbdHGa57'
114
+ ]
115
+ end
116
+ end
117
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
118
+ builder.adapter(:test, stubs)
119
+ end
131
120
  @client.temporary_credential_key = '4/oegn2eP-3yswD7HiESnJOB-8oh2i'
132
121
  @client.temporary_credential_secret = '8E1BF0J6ovMva0j87atj/tTG'
133
122
  @client.fetch_token_credential!(
134
123
  :verifier => 'XbVKagBShNsAGBRJWoC4gtFR',
135
- :adapter => HTTPAdapter::TyphoeusAdapter.new,
136
124
  :connection => connection,
137
125
  :additional_parameters => {
138
126
  :scope => 'https://www.google.com/m8/feeds/'
@@ -141,99 +129,89 @@ describe Signet::OAuth1::Client, 'configured for standard Google APIs' do
141
129
  @client.token_credential_key.should ==
142
130
  '1/YFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ'
143
131
  @client.token_credential_secret.should == 'Ew3YHAY4bcBryiOUvbdHGa57'
132
+ stubs.verify_stubbed_calls
144
133
  end
145
134
 
146
135
  it 'should raise an error if the server gives an unexpected status' do
136
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
137
+ stub.post('/accounts/OAuthGetAccessToken') do
138
+ [509, {}, 'Rate limit hit or something.']
139
+ end
140
+ end
147
141
  (lambda do
148
- hydra = Typhoeus::Hydra.new
149
- stubbed_response = Typhoeus::Response.new(
150
- :code => 999,
151
- :headers => '',
152
- :body => 'Rate limit hit or something.'
153
- )
154
- hydra.stub(
155
- :post,
156
- 'https://www.google.com/accounts/OAuthGetAccessToken'
157
- ).and_return(stubbed_response)
158
- connection = HTTPAdapter::Connection.new(
159
- 'www.google.com', 443, hydra,
160
- :join => [:run, [], nil]
161
- )
142
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
143
+ builder.adapter(:test, stubs)
144
+ end
162
145
  @client.temporary_credential_key = '4/oegn2eP-3yswD7HiESnJOB-8oh2i'
163
146
  @client.temporary_credential_secret = '8E1BF0J6ovMva0j87atj/tTG'
164
147
  @client.fetch_token_credential!(
165
148
  :verifier => 'XbVKagBShNsAGBRJWoC4gtFR',
166
- :adapter => HTTPAdapter::TyphoeusAdapter.new,
167
149
  :connection => connection,
168
150
  :additional_parameters => {
169
151
  :scope => 'https://www.google.com/m8/feeds/'
170
152
  }
171
153
  )
172
154
  end).should raise_error(Signet::AuthorizationError)
155
+ stubs.verify_stubbed_calls
173
156
  end
174
157
 
175
158
  it 'should correctly fetch the protected resource' do
176
- hydra = Typhoeus::Hydra.new
177
- stubbed_response = Typhoeus::Response.new(
178
- :code => 200,
179
- :headers => "Content-Type: application/json\r\n",
180
- :body => '{"data":"goes here"}'
181
- )
182
- hydra.stub(
183
- :get,
184
- 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
185
- ).and_return(stubbed_response)
186
- connection = HTTPAdapter::Connection.new(
187
- 'www.google.com', 443, hydra,
188
- :join => [:run, [], nil]
189
- )
159
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
160
+ stub.get('/api/people/@me/@self') do
161
+ [
162
+ 200,
163
+ {'Content-Type' => 'application/json'},
164
+ '{"data":"goes here"}'
165
+ ]
166
+ end
167
+ end
168
+ connection = Faraday.new(
169
+ :url => 'http://www-opensocial.googleusercontent.com'
170
+ ) do |builder|
171
+ builder.adapter(:test, stubs)
172
+ end
190
173
  @client.token_credential_key =
191
174
  '1/YFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ'
192
175
  @client.token_credential_secret = 'Ew3YHAY4bcBryiOUvbdHGa57'
193
176
  response = @client.fetch_protected_resource(
194
- :adapter => HTTPAdapter::TyphoeusAdapter.new,
195
177
  :connection => connection,
196
178
  :uri =>
197
179
  'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
198
180
  )
199
- status, headers, body = response
200
- status.should == 200
201
- headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
202
- headers['Content-Type'].should == 'application/json'
203
- merge_body(body).should == '{"data":"goes here"}'
181
+ response.status.should == 200
182
+ response.headers['Content-Type'].should == 'application/json'
183
+ response.body.should == '{"data":"goes here"}'
204
184
  end
205
185
 
206
186
  it 'should correctly fetch the protected resource' do
207
- hydra = Typhoeus::Hydra.new
208
- stubbed_response = Typhoeus::Response.new(
209
- :code => 200,
210
- :headers => "Content-Type: application/json\r\n",
211
- :body => '{"data":"goes here"}'
212
- )
213
- hydra.stub(
214
- :get,
215
- 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
216
- ).and_return(stubbed_response)
217
- connection = HTTPAdapter::Connection.new(
218
- 'www.google.com', 443, hydra,
219
- :join => [:run, [], nil]
220
- )
187
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
188
+ stub.get('/api/people/@me/@self') do
189
+ [
190
+ 200,
191
+ {'Content-Type' => 'application/json'},
192
+ '{"data":"goes here"}'
193
+ ]
194
+ end
195
+ end
196
+ connection = Faraday.new(
197
+ :url => 'http://www-opensocial.googleusercontent.com'
198
+ ) do |builder|
199
+ builder.adapter(:test, stubs)
200
+ end
221
201
  @client.token_credential_key =
222
202
  '1/YFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ'
223
203
  @client.token_credential_secret = 'Ew3YHAY4bcBryiOUvbdHGa57'
224
204
  response = @client.fetch_protected_resource(
225
- :adapter => HTTPAdapter::TyphoeusAdapter.new,
226
205
  :connection => connection,
227
- :request => Typhoeus::Request.new(
228
- 'http://www-opensocial.googleusercontent.com/api/people/@me/@self',
229
- :method => :get
230
- )
206
+ :request => Faraday::Request.create(:get) do |req|
207
+ req.url(
208
+ 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
209
+ )
210
+ end
231
211
  )
232
- status, headers, body = response
233
- status.should == 200
234
- headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
235
- headers['Content-Type'].should == 'application/json'
236
- merge_body(body).should == '{"data":"goes here"}'
212
+ response.status.should == 200
213
+ response.headers['Content-Type'].should == 'application/json'
214
+ response.body.should == '{"data":"goes here"}'
237
215
  end
238
216
  end
239
217
 
@@ -15,12 +15,57 @@
15
15
  require 'spec_helper'
16
16
 
17
17
  require 'signet/oauth_2/client'
18
+ require 'openssl'
19
+
20
+ gem 'jwt', '~> 0.1.4'
21
+ require 'jwt'
18
22
 
19
23
  describe Signet::OAuth2::Client, 'unconfigured' do
20
24
  before do
21
25
  @client = Signet::OAuth2::Client.new
22
26
  end
23
27
 
28
+ it 'should raise an error if a bogus scope is provided' do
29
+ (lambda do
30
+ @client = Signet::OAuth2::Client.new(:scope => :bogus)
31
+ end).should raise_error(TypeError)
32
+ end
33
+
34
+ it 'should raise an error if a scope array is provided with spaces' do
35
+ (lambda do
36
+ @client = Signet::OAuth2::Client.new(:scope => [
37
+ 'legit',
38
+ 'bogus bogus'
39
+ ])
40
+ end).should raise_error(ArgumentError)
41
+ end
42
+
43
+ it 'should allow the scope to be set to a String' do
44
+ @client.scope = 'legit'
45
+ @client.scope.should == ['legit']
46
+ @client.scope = 'legit alsolegit'
47
+ @client.scope.should == ['legit', 'alsolegit']
48
+ end
49
+
50
+ it 'should allow the scope to be set to an Array' do
51
+ @client.scope = ['legit']
52
+ @client.scope.should == ['legit']
53
+ @client.scope = ['legit', 'alsolegit']
54
+ @client.scope.should == ['legit', 'alsolegit']
55
+ end
56
+
57
+ it 'should raise an error if a bogus redirect URI is provided' do
58
+ (lambda do
59
+ @client = Signet::OAuth2::Client.new(:redirect_uri => :bogus)
60
+ end).should raise_error(TypeError)
61
+ end
62
+
63
+ it 'should raise an error if a relative redirect URI is provided' do
64
+ (lambda do
65
+ @client = Signet::OAuth2::Client.new(:redirect_uri => '/relative/path')
66
+ end).should raise_error(ArgumentError)
67
+ end
68
+
24
69
  it 'should have no authorization_uri' do
25
70
  @client.authorization_uri.should == nil
26
71
  end
@@ -53,6 +98,25 @@ describe Signet::OAuth2::Client, 'unconfigured' do
53
98
  )
54
99
  end
55
100
 
101
+ it 'should require a redirect URI when getting the authorization_uri' do
102
+ @client.authorization_uri =
103
+ Addressable::URI.parse('https://example.com/authorize')
104
+ @client.client_id = 's6BhdRkqt3'
105
+ (lambda do
106
+ @client.authorization_uri
107
+ end).should raise_error(ArgumentError)
108
+ end
109
+
110
+ it 'should require a client ID when getting the authorization_uri' do
111
+ @client.authorization_uri =
112
+ Addressable::URI.parse('https://example.com/authorize')
113
+ @client.redirect_uri =
114
+ Addressable::URI.parse('https://example.client.com/callback')
115
+ (lambda do
116
+ @client.authorization_uri
117
+ end).should raise_error(ArgumentError)
118
+ end
119
+
56
120
  it 'should have no token_credential_uri' do
57
121
  @client.token_credential_uri.should == nil
58
122
  end
@@ -68,3 +132,516 @@ describe Signet::OAuth2::Client, 'unconfigured' do
68
132
  @client.token_credential_uri.should === "https://example.com/token"
69
133
  end
70
134
  end
135
+
136
+ describe Signet::OAuth2::Client, 'configured for Google userinfo API' do
137
+ before do
138
+ @client = Signet::OAuth2::Client.new(
139
+ :authorization_uri =>
140
+ 'https://accounts.google.com/o/oauth2/auth',
141
+ :token_credential_uri =>
142
+ 'https://accounts.google.com/o/oauth2/token',
143
+ :scope => 'https://www.googleapis.com/auth/userinfo.profile'
144
+ )
145
+ end
146
+
147
+ it 'should not have a grant type by default' do
148
+ @client.grant_type.should == nil
149
+ end
150
+
151
+ it 'should use the authorization_code grant type if given code' do
152
+ @client.code = '00000'
153
+ @client.redirect_uri = 'http://www.example.com/'
154
+ @client.grant_type.should == 'authorization_code'
155
+ end
156
+
157
+ it 'should use the refresh_token grant type if given refresh token' do
158
+ @client.refresh_token = '54321'
159
+ @client.grant_type.should == 'refresh_token'
160
+ end
161
+
162
+ it 'should use the password grant type if given username and password' do
163
+ @client.username = 'johndoe'
164
+ @client.password = 'incognito'
165
+ @client.grant_type.should == 'password'
166
+ end
167
+
168
+ it 'should allow the grant type to be set manually' do
169
+ @client.grant_type = 'authorization_code'
170
+ @client.grant_type.should == 'authorization_code'
171
+ @client.grant_type = 'refresh_token'
172
+ @client.grant_type.should == 'refresh_token'
173
+ @client.grant_type = 'password'
174
+ @client.grant_type.should == 'password'
175
+ end
176
+
177
+ it 'should allow the grant type to be set to an extension' do
178
+ @client.grant_type = 'urn:ietf:params:oauth:grant-type:saml2-bearer'
179
+ @client.extension_parameters['assertion'] =
180
+ 'PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU'
181
+
182
+ @client.grant_type.should ==
183
+ Addressable::URI.parse('urn:ietf:params:oauth:grant-type:saml2-bearer')
184
+ @client.extension_parameters.should ==
185
+ {'assertion' => 'PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU'}
186
+ end
187
+
188
+ it 'should raise an error if extension parameters are bogus' do
189
+ (lambda do
190
+ @client.extension_parameters = :bogus
191
+ end).should raise_error(TypeError)
192
+ end
193
+
194
+ it 'should allow the token to be updated' do
195
+ issued_at = Time.now
196
+ @client.update_token!(
197
+ :access_token => '12345',
198
+ :refresh_token => '54321',
199
+ :expires_in => 3600,
200
+ :issued_at => issued_at
201
+ )
202
+ @client.access_token.should == '12345'
203
+ @client.refresh_token.should == '54321'
204
+ @client.expires_in.should == 3600
205
+ @client.issued_at.should == issued_at
206
+ @client.should_not be_expired
207
+ end
208
+
209
+ it 'should allow the token to be updated without an expiration' do
210
+ @client.update_token!(
211
+ :access_token => '12345',
212
+ :refresh_token => '54321'
213
+ )
214
+ @client.access_token.should == '12345'
215
+ @client.refresh_token.should == '54321'
216
+ @client.expires_in.should == nil
217
+ @client.issued_at.should == nil
218
+ @client.should_not be_expired
219
+ end
220
+
221
+ it 'should allow the token expiration to be cleared' do
222
+ issued_at = Time.now
223
+ @client.update_token!(
224
+ :access_token => '12345',
225
+ :refresh_token => '54321',
226
+ :expires_in => 3600,
227
+ :issued_at => issued_at
228
+ )
229
+ @client.expires_in = nil
230
+ @client.issued_at = nil
231
+ @client.should_not be_expired
232
+ end
233
+
234
+ it 'should raise an error if the authorization endpoint is not secure' do
235
+ @client.client_id = 'client-12345'
236
+ @client.client_secret = 'secret-12345'
237
+ @client.redirect_uri = 'http://www.example.com/'
238
+ @client.authorization_uri = 'http://accounts.google.com/o/oauth2/auth'
239
+ (lambda do
240
+ @client.authorization_uri
241
+ end).should raise_error(Signet::UnsafeOperationError)
242
+ end
243
+
244
+ it 'should raise an error if token credential URI is missing' do
245
+ @client.token_credential_uri = nil
246
+ (lambda do
247
+ @client.fetch_access_token!
248
+ end).should raise_error(ArgumentError)
249
+ end
250
+
251
+ it 'should raise an error if client ID is missing' do
252
+ @client.client_secret = 'secret-12345'
253
+ (lambda do
254
+ @client.fetch_access_token!
255
+ end).should raise_error(ArgumentError)
256
+ end
257
+
258
+ it 'should raise an error if client secret is missing' do
259
+ @client.client_id = 'client-12345'
260
+ (lambda do
261
+ @client.fetch_access_token!
262
+ end).should raise_error(ArgumentError)
263
+ end
264
+
265
+ it 'should raise an error if unauthorized' do
266
+ @client.client_id = 'client-12345'
267
+ @client.client_secret = 'secret-12345'
268
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
269
+ stub.post('/o/oauth2/token') do
270
+ [401, {}, 'User authorization failed or something.']
271
+ end
272
+ end
273
+ (lambda do
274
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
275
+ builder.adapter(:test, stubs)
276
+ end
277
+ @client.fetch_access_token!(
278
+ :connection => connection
279
+ )
280
+ end).should raise_error(Signet::AuthorizationError)
281
+ stubs.verify_stubbed_calls
282
+ end
283
+
284
+ it 'should raise an error if the token server gives an unexpected status' do
285
+ @client.client_id = 'client-12345'
286
+ @client.client_secret = 'secret-12345'
287
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
288
+ stub.post('/o/oauth2/token') do
289
+ [509, {}, 'Rate limit hit or something.']
290
+ end
291
+ end
292
+ (lambda do
293
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
294
+ builder.adapter(:test, stubs)
295
+ end
296
+ @client.fetch_access_token!(
297
+ :connection => connection
298
+ )
299
+ end).should raise_error(Signet::AuthorizationError)
300
+ stubs.verify_stubbed_calls
301
+ end
302
+
303
+ it 'should correctly fetch an access token' do
304
+ @client.client_id = 'client-12345'
305
+ @client.client_secret = 'secret-12345'
306
+ @client.code = '00000'
307
+ @client.redirect_uri = 'https://www.example.com/'
308
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
309
+ stub.post('/o/oauth2/token') do
310
+ [200, {}, MultiJson.encode({
311
+ 'access_token' => '12345',
312
+ 'refresh_token' => '54321',
313
+ 'expires_in' => '3600'
314
+ })]
315
+ end
316
+ end
317
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
318
+ builder.adapter(:test, stubs)
319
+ end
320
+ @client.fetch_access_token!(
321
+ :connection => connection
322
+ )
323
+ @client.access_token.should == '12345'
324
+ @client.refresh_token.should == '54321'
325
+ @client.expires_in.should == 3600
326
+ stubs.verify_stubbed_calls
327
+ end
328
+
329
+ it 'should correctly fetch an access token with a password' do
330
+ @client.client_id = 'client-12345'
331
+ @client.client_secret = 'secret-12345'
332
+ @client.username = 'johndoe'
333
+ @client.password = 'incognito'
334
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
335
+ stub.post('/o/oauth2/token') do
336
+ [200, {}, MultiJson.encode({
337
+ 'access_token' => '12345',
338
+ 'refresh_token' => '54321',
339
+ 'expires_in' => '3600'
340
+ })]
341
+ end
342
+ end
343
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
344
+ builder.adapter(:test, stubs)
345
+ end
346
+ @client.fetch_access_token!(
347
+ :connection => connection
348
+ )
349
+ @client.access_token.should == '12345'
350
+ @client.refresh_token.should == '54321'
351
+ @client.expires_in.should == 3600
352
+ stubs.verify_stubbed_calls
353
+ end
354
+
355
+ it 'should correctly refresh an access token' do
356
+ @client.client_id = 'client-12345'
357
+ @client.client_secret = 'secret-12345'
358
+ @client.refresh_token = '54321'
359
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
360
+ stub.post('/o/oauth2/token') do
361
+ [200, {}, MultiJson.encode({
362
+ 'access_token' => '12345',
363
+ 'refresh_token' => '54321',
364
+ 'expires_in' => '3600'
365
+ })]
366
+ end
367
+ end
368
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
369
+ builder.adapter(:test, stubs)
370
+ end
371
+ @client.fetch_access_token!(
372
+ :connection => connection
373
+ )
374
+ @client.access_token.should == '12345'
375
+ @client.refresh_token.should == '54321'
376
+ @client.expires_in.should == 3600
377
+ stubs.verify_stubbed_calls
378
+ end
379
+
380
+ it 'should detect unintential grant type of none' do
381
+ @client.client_id = 'client-12345'
382
+ @client.client_secret = 'secret-12345'
383
+ @client.redirect_uri = 'https://www.example.com/'
384
+ (lambda do
385
+ @client.fetch_access_token!
386
+ end).should raise_error(ArgumentError)
387
+ end
388
+
389
+ it 'should correctly fetch protected resources' do
390
+ @client.client_id = 'client-12345'
391
+ @client.client_secret = 'secret-12345'
392
+ @client.access_token = '12345'
393
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
394
+ stub.get('/oauth2/v1/userinfo?alt=json') do
395
+ [200, {}, <<-JSON]
396
+ {
397
+ "id": "116452824309856782163",
398
+ "name": "Bob Aman",
399
+ "given_name": "Bob",
400
+ "family_name": "Aman",
401
+ "link": "https://plus.google.com/116452824309856782163"
402
+ }
403
+ JSON
404
+ end
405
+ end
406
+ connection = Faraday.new(:url => 'https://www.googleapis.com') do |builder|
407
+ builder.adapter(:test, stubs)
408
+ end
409
+ response = @client.fetch_protected_resource(
410
+ :connection => connection,
411
+ :uri => 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json'
412
+ )
413
+ response.status.should == 200
414
+ response.body.should == <<-JSON
415
+ {
416
+ "id": "116452824309856782163",
417
+ "name": "Bob Aman",
418
+ "given_name": "Bob",
419
+ "family_name": "Aman",
420
+ "link": "https://plus.google.com/116452824309856782163"
421
+ }
422
+ JSON
423
+ stubs.verify_stubbed_calls
424
+ end
425
+
426
+ it 'should correctly send the realm in the Authorization header' do
427
+ @client.client_id = 'client-12345'
428
+ @client.client_secret = 'secret-12345'
429
+ @client.access_token = '12345'
430
+ connection = Faraday.new(:url => 'https://www.googleapis.com') do |builder|
431
+ builder.adapter(:test)
432
+ end
433
+ request = @client.generate_authenticated_request(
434
+ :connection => connection,
435
+ :realm => 'Example',
436
+ :request => Faraday::Request.create(:get) do |req|
437
+ req.url('https://www.googleapis.com/oauth2/v1/userinfo?alt=json')
438
+ end
439
+ )
440
+ request.headers['Authorization'].should == 'Bearer 12345, realm="Example"'
441
+ end
442
+
443
+ it 'should correctly send the realm in the Authorization header' do
444
+ @client.client_id = 'client-12345'
445
+ @client.client_secret = 'secret-12345'
446
+ @client.access_token = '12345'
447
+ connection = Faraday.new(:url => 'https://www.googleapis.com') do |builder|
448
+ builder.adapter(:test)
449
+ end
450
+ request = @client.generate_authenticated_request(
451
+ :connection => connection,
452
+ :realm => 'Example',
453
+ :request => [
454
+ 'GET',
455
+ 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json',
456
+ {},
457
+ ['']
458
+ ]
459
+ )
460
+ request.headers['Authorization'].should == 'Bearer 12345, realm="Example"'
461
+ end
462
+
463
+ it 'should raise an error if Faraday::Request is used without connection' do
464
+ @client.client_id = 'client-12345'
465
+ @client.client_secret = 'secret-12345'
466
+ @client.access_token = '12345'
467
+ (lambda do
468
+ @client.generate_authenticated_request(
469
+ :realm => 'Example',
470
+ :request => Faraday::Request.create(:get) do |req|
471
+ req.url('https://www.googleapis.com/oauth2/v1/userinfo?alt=json')
472
+ end
473
+ )
474
+ end).should raise_error(ArgumentError)
475
+ end
476
+
477
+ it 'should raise an error if not enough information ' +
478
+ 'is supplied to create a request' do
479
+ @client.client_id = 'client-12345'
480
+ @client.client_secret = 'secret-12345'
481
+ @client.access_token = '12345'
482
+ (lambda do
483
+ @client.generate_authenticated_request(
484
+ :realm => 'Example',
485
+ :method => 'POST'
486
+ )
487
+ end).should raise_error(ArgumentError)
488
+ end
489
+
490
+ it 'should raise an error if a bogus request body is supplied' do
491
+ @client.client_id = 'client-12345'
492
+ @client.client_secret = 'secret-12345'
493
+ @client.access_token = '12345'
494
+ (lambda do
495
+ @client.generate_authenticated_request(
496
+ :realm => 'Example',
497
+ :method => 'POST',
498
+ :uri => 'http://www.example.com/',
499
+ :body => :bogus
500
+ )
501
+ end).should raise_error(TypeError)
502
+ end
503
+
504
+ it 'should raise an error if the client does not have an access token' do
505
+ @client.client_id = 'client-12345'
506
+ @client.client_secret = 'secret-12345'
507
+ (lambda do
508
+ @client.fetch_protected_resource
509
+ end).should raise_error(ArgumentError)
510
+ end
511
+
512
+ it 'should not raise an error if the API server gives an error status' do
513
+ @client.client_id = 'client-12345'
514
+ @client.client_secret = 'secret-12345'
515
+ @client.access_token = '12345'
516
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
517
+ stub.get('/oauth2/v1/userinfo?alt=json') do
518
+ [509, {}, 'Rate limit hit or something.']
519
+ end
520
+ end
521
+ connection = Faraday.new(:url => 'https://www.googleapis.com') do |builder|
522
+ builder.adapter(:test, stubs)
523
+ end
524
+ response = @client.fetch_protected_resource(
525
+ :connection => connection,
526
+ :uri => 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json'
527
+ )
528
+ response.status.should == 509
529
+ response.body.should == 'Rate limit hit or something.'
530
+ stubs.verify_stubbed_calls
531
+ end
532
+
533
+ it 'should only raise an error if the API server ' +
534
+ 'gives an authorization failed status' do
535
+ @client.client_id = 'client-12345'
536
+ @client.client_secret = 'secret-12345'
537
+ @client.access_token = '12345'
538
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
539
+ stub.get('/oauth2/v1/userinfo?alt=json') do
540
+ [401, {}, 'User authorization failed or something.']
541
+ end
542
+ end
543
+ (lambda do
544
+ connection = Faraday.new(
545
+ :url => 'https://www.googleapis.com'
546
+ ) do |builder|
547
+ builder.adapter(:test, stubs)
548
+ end
549
+ @client.fetch_protected_resource(
550
+ :connection => connection,
551
+ :uri => 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json'
552
+ )
553
+ end).should raise_error(Signet::AuthorizationError)
554
+ stubs.verify_stubbed_calls
555
+ end
556
+
557
+ it 'should correctly handle an id token' do
558
+ @client.client_id = 'client-12345'
559
+ @client.client_secret = 'secret-12345'
560
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
561
+ stub.post('/o/oauth2/token') do
562
+ [200, {}, MultiJson.encode({
563
+ 'access_token' => '12345',
564
+ 'refresh_token' => '54321',
565
+ 'expires_in' => '3600',
566
+ 'id_token' => (
567
+ 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY' +
568
+ 'XVkIjoiMTA2MDM1Nzg5MTY4OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSI' +
569
+ 'sImNpZCI6IjEwNjAzNTc4OTE2ODguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb' +
570
+ '20iLCJpZCI6IjExNjQ1MjgyNDMwOTg1Njc4MjE2MyIsInRva2VuX2hhc2giOiJ' +
571
+ '0Z2hEOUo4bjhWME4ydmN3NmVNaWpnIiwiaWF0IjoxMzIwNjcwOTc4LCJleHAiO' +
572
+ 'jEzMjA2NzQ4Nzh9.D8x_wirkxDElqKdJBcsIws3Ogesk38okz6MN7zqC7nEAA7' +
573
+ 'wcy1PxsROY1fmBvXSer0IQesAqOW-rPOCNReSn-eY8d53ph1x2HAF-AzEi3GOl' +
574
+ '6hFycH8wj7Su6JqqyEbIVLxE7q7DkAZGaMPkxbTHs1EhSd5_oaKQ6O4xO3ZnnT4'
575
+ )
576
+ })]
577
+ end
578
+ end
579
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
580
+ builder.adapter(:test, stubs)
581
+ end
582
+ @client.fetch_access_token!(
583
+ :connection => connection
584
+ )
585
+ @client.access_token.should == '12345'
586
+ @client.refresh_token.should == '54321'
587
+ @client.decoded_id_token.should == {
588
+ "token_hash" => "tghD9J8n8V0N2vcw6eMijg",
589
+ "id" => "116452824309856782163",
590
+ "aud" => "1060357891688.apps.googleusercontent.com",
591
+ "iat" => 1320670978,
592
+ "exp" => 1320674878,
593
+ "cid" => "1060357891688.apps.googleusercontent.com",
594
+ "iss" => "accounts.google.com"
595
+ }
596
+ @client.expires_in.should == 3600
597
+ stubs.verify_stubbed_calls
598
+ end
599
+
600
+ it 'should raise an error if the id token cannot be verified' do
601
+ @client.client_id = 'client-12345'
602
+ @client.client_secret = 'secret-12345'
603
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
604
+ stub.post('/o/oauth2/token') do
605
+ [200, {}, MultiJson.encode({
606
+ 'access_token' => '12345',
607
+ 'refresh_token' => '54321',
608
+ 'expires_in' => '3600',
609
+ 'id_token' => (
610
+ 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY' +
611
+ 'XVkIjoiMTA2MDM1Nzg5MTY4OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSI' +
612
+ 'sImNpZCI6IjEwNjAzNTc4OTE2ODguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb' +
613
+ '20iLCJpZCI6IjExNjQ1MjgyNDMwOTg1Njc4MjE2MyIsInRva2VuX2hhc2giOiJ' +
614
+ '0Z2hEOUo4bjhWME4ydmN3NmVNaWpnIiwiaWF0IjoxMzIwNjcwOTc4LCJleHAiO' +
615
+ 'jEzMjA2NzQ4Nzh9.D8x_wirkxDElqKdJBcsIws3Ogesk38okz6MN7zqC7nEAA7' +
616
+ 'wcy1PxsROY1fmBvXSer0IQesAqOW-rPOCNReSn-eY8d53ph1x2HAF-AzEi3GOl' +
617
+ '6hFycH8wj7Su6JqqyEbIVLxE7q7DkAZGaMPkxbTHs1EhSd5_oaKQ6O4xO3ZnnT4'
618
+ )
619
+ })]
620
+ end
621
+ end
622
+ connection = Faraday.new(:url => 'https://www.google.com') do |builder|
623
+ builder.adapter(:test, stubs)
624
+ end
625
+ @client.fetch_access_token!(
626
+ :connection => connection
627
+ )
628
+ @client.access_token.should == '12345'
629
+ @client.refresh_token.should == '54321'
630
+ @client.expires_in.should == 3600
631
+ (lambda do
632
+ pubkey = OpenSSL::PKey::RSA.new(<<-PUBKEY)
633
+ -----BEGIN PUBLIC KEY-----
634
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCaY7425h964bjaoLeUm
635
+ SlZ8sK7VtVk9zHbGmZh2ygGYwfuUf2bmMye2Ofv99yDE/rd4loVIAcu7RVvDRgHq
636
+ 3/CZTnIrSvHsiJQsHBNa3d+F1ihPfzURzf1M5k7CFReBj2SBXhDXd57oRfBQj12w
637
+ CVhhwP6kGTAWuoppbIIIBfNF2lE/Nvm7lVVYQqL9xOrP/AQ4xRbpQlB8Ll9sO9Or
638
+ SvbWhCDa/LMOWxHdmrcJi6XoSg1vnOyCoKbyAoauTt/XqdkHbkDdQ6HFbJieu9il
639
+ LDZZNliPhfENuKeC2MCGVXTEu8Cqhy1w6e4axavLlXoYf4laJIZ/e7au8SqDbY0B
640
+ xwIDAQAB
641
+ -----END PUBLIC KEY-----
642
+ PUBKEY
643
+ @client.decoded_id_token(pubkey)
644
+ end).should raise_error(JWT::DecodeError, "Signature verification failed")
645
+ stubs.verify_stubbed_calls
646
+ end
647
+ end