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.
- data/{CHANGELOG → CHANGELOG.md} +13 -6
- data/README.md +1 -3
- data/Rakefile +1 -1
- data/lib/signet/errors.rb +2 -2
- data/lib/signet/oauth_1/client.rb +78 -125
- data/lib/signet/oauth_2.rb +6 -6
- data/lib/signet/oauth_2/client.rb +103 -137
- data/lib/signet/version.rb +2 -2
- data/spec/signet/oauth_1/client_spec.rb +31 -34
- data/spec/signet/oauth_1/services/google_spec.rb +72 -94
- data/spec/signet/oauth_2/client_spec.rb +577 -0
- data/spec/signet/oauth_2_spec.rb +22 -0
- data/tasks/gem.rake +3 -4
- data/tasks/git.rake +1 -1
- data/tasks/rdoc.rake +1 -1
- data/tasks/rubyforge.rake +1 -1
- data/tasks/spec.rake +6 -1
- data/tasks/wiki.rake +38 -0
- data/tasks/yard.rake +1 -1
- metadata +11 -21
@@ -15,8 +15,7 @@
|
|
15
15
|
require 'spec_helper'
|
16
16
|
|
17
17
|
require 'signet/oauth_1/client'
|
18
|
-
require '
|
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
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
:
|
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
|
200
|
-
|
201
|
-
|
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
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
:
|
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 =>
|
228
|
-
|
229
|
-
|
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
|
233
|
-
|
234
|
-
|
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
|