signet 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,163 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'signet/oauth_1/credential'
18
+
19
+ describe Signet::OAuth1::Credential, 'with a Hash for initialization' do
20
+ it 'should accept "oauth_token" and "oauth_token_secret" pairs' do
21
+ token = Signet::OAuth1::Credential.new({
22
+ "oauth_token" => "dpf43f3p2l4k3l03",
23
+ "oauth_token_secret" => "kd94hf93k423kf44"
24
+ })
25
+ token.key.should == "dpf43f3p2l4k3l03"
26
+ token.secret.should == "kd94hf93k423kf44"
27
+ end
28
+
29
+ it 'should accept :oauth_token and :oauth_token_secret pairs' do
30
+ token = Signet::OAuth1::Credential.new({
31
+ :oauth_token => "dpf43f3p2l4k3l03",
32
+ :oauth_token_secret => "kd94hf93k423kf44"
33
+ })
34
+ token.key.should == "dpf43f3p2l4k3l03"
35
+ token.secret.should == "kd94hf93k423kf44"
36
+ end
37
+
38
+ it 'should accept "key" and "secret" pairs' do
39
+ token = Signet::OAuth1::Credential.new({
40
+ "key" => "dpf43f3p2l4k3l03",
41
+ "secret" => "kd94hf93k423kf44"
42
+ })
43
+ token.key.should == "dpf43f3p2l4k3l03"
44
+ token.secret.should == "kd94hf93k423kf44"
45
+ end
46
+
47
+ it 'should accept :key and :secret pairs' do
48
+ token = Signet::OAuth1::Credential.new(
49
+ :key => "dpf43f3p2l4k3l03",
50
+ :secret => "kd94hf93k423kf44"
51
+ )
52
+ token.key.should == "dpf43f3p2l4k3l03"
53
+ token.secret.should == "kd94hf93k423kf44"
54
+ end
55
+
56
+ it 'should not complain about additional parameters' do
57
+ token = Signet::OAuth1::Credential.new({
58
+ "oauth_token" => "dpf43f3p2l4k3l03",
59
+ "oauth_token_secret" => "kd94hf93k423kf44",
60
+ "oauth_version" => "1.0"
61
+ })
62
+ token.key.should == "dpf43f3p2l4k3l03"
63
+ token.secret.should == "kd94hf93k423kf44"
64
+ end
65
+
66
+ it 'should allow parameters to be specified as an implicit Hash' do
67
+ class ParameterHashSet
68
+ def initialize(parameters)
69
+ @parameters = Hash[parameters]
70
+ end
71
+
72
+ def to_hash
73
+ return @parameters
74
+ end
75
+ end
76
+
77
+ token = Signet::OAuth1::Credential.new(ParameterHashSet.new({
78
+ "oauth_token" => "dpf43f3p2l4k3l03",
79
+ "oauth_token_secret" => "kd94hf93k423kf44",
80
+ "oauth_version" => "1.0"
81
+ }))
82
+ token.key.should == "dpf43f3p2l4k3l03"
83
+ token.secret.should == "kd94hf93k423kf44"
84
+ end
85
+
86
+ it 'should allow parameters to be specified as an Enumerable' do
87
+ token = Signet::OAuth1::Credential.new([
88
+ ["oauth_token", "dpf43f3p2l4k3l03"],
89
+ ["oauth_token_secret", "kd94hf93k423kf44"],
90
+ ["oauth_version", "1.0"]
91
+ ])
92
+ token.key.should == "dpf43f3p2l4k3l03"
93
+ token.secret.should == "kd94hf93k423kf44"
94
+ end
95
+
96
+ it 'should allow parameters to be specified as an implicit Array' do
97
+ class ParameterArraySet
98
+ def initialize(parameters)
99
+ @parameters = parameters
100
+ end
101
+
102
+ def to_ary
103
+ return @parameters
104
+ end
105
+ end
106
+
107
+ token = Signet::OAuth1::Credential.new(ParameterArraySet.new([
108
+ ["oauth_token", "dpf43f3p2l4k3l03"],
109
+ ["oauth_token_secret", "kd94hf93k423kf44"],
110
+ ["oauth_version", "1.0"]
111
+ ]))
112
+ token.key.should == "dpf43f3p2l4k3l03"
113
+ token.secret.should == "kd94hf93k423kf44"
114
+ end
115
+
116
+ it 'should raise an error if key and secret are not present' do
117
+ (lambda do
118
+ Signet::OAuth1::Credential.new({})
119
+ end).should raise_error(ArgumentError)
120
+ end
121
+
122
+ it 'should allow key and secret to be passed in as a tuple' do
123
+ token = Signet::OAuth1::Credential.new(
124
+ ["dpf43f3p2l4k3l03", "kd94hf93k423kf44"]
125
+ )
126
+ token.key.should == "dpf43f3p2l4k3l03"
127
+ token.secret.should == "kd94hf93k423kf44"
128
+ end
129
+
130
+ it 'should allow key and secret to be passed in as normal parameters' do
131
+ token = Signet::OAuth1::Credential.new(
132
+ "dpf43f3p2l4k3l03", "kd94hf93k423kf44"
133
+ )
134
+ token.key.should == "dpf43f3p2l4k3l03"
135
+ token.secret.should == "kd94hf93k423kf44"
136
+ end
137
+
138
+ it 'should raise an error if key or secret are of the wrong type' do
139
+ (lambda do
140
+ Signet::OAuth1::Credential.new("dpf43f3p2l4k3l03", 42)
141
+ end).should raise_error(TypeError)
142
+ (lambda do
143
+ Signet::OAuth1::Credential.new(42, "kd94hf93k423kf44")
144
+ end).should raise_error(TypeError)
145
+ end
146
+
147
+ it 'should raise an error if the wrong number of arguments are passed' do
148
+ (lambda do
149
+ Signet::OAuth1::Credential.new(
150
+ "dpf43f3p2l4k3l03", "kd94hf93k423kf44", "something else"
151
+ )
152
+ end).should raise_error(ArgumentError)
153
+ end
154
+
155
+ it 'should convert to a Hash object' do
156
+ token = Signet::OAuth1::Credential.new(
157
+ "dpf43f3p2l4k3l03", "kd94hf93k423kf44"
158
+ )
159
+ parameters = Hash[token]
160
+ parameters['oauth_token'].should == "dpf43f3p2l4k3l03"
161
+ parameters['oauth_token_secret'].should == "kd94hf93k423kf44"
162
+ end
163
+ end
@@ -0,0 +1,234 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'signet/oauth_1/client'
18
+ require 'httpadapter/adapters/typhoeus'
19
+
20
+ def merge_body(chunked_body)
21
+ merged_body = StringIO.new
22
+ chunked_body.each do |chunk|
23
+ merged_body.write(chunk)
24
+ end
25
+ return merged_body.string
26
+ end
27
+
28
+ describe Signet::OAuth1::Client, 'configured for standard Google APIs' do
29
+ before do
30
+ @client = Signet::OAuth1::Client.new(
31
+ :temporary_credential_uri =>
32
+ 'https://www.google.com/accounts/OAuthGetRequestToken',
33
+ :authorization_uri =>
34
+ 'https://www.google.com/accounts/OAuthAuthorizeToken',
35
+ :token_credential_uri =>
36
+ 'https://www.google.com/accounts/OAuthGetAccessToken',
37
+ :client_credential_key => 'anonymous',
38
+ :client_credential_secret => 'anonymous'
39
+ )
40
+ end
41
+
42
+ it 'should raise an error if scope is omitted' do
43
+ (lambda do
44
+ @client.fetch_temporary_credential!
45
+ end).should raise_error(Signet::AuthorizationError)
46
+ end
47
+
48
+ it 'should raise an error if the server gives an unexpected status' do
49
+ (lambda do
50
+ hydra = Typhoeus::Hydra.new
51
+ stubbed_response = Typhoeus::Response.new(
52
+ :code => 999,
53
+ :headers => '',
54
+ :body => 'Rate limit hit or something.'
55
+ )
56
+ hydra.stub(
57
+ :post,
58
+ 'https://www.google.com/accounts/OAuthGetRequestToken'
59
+ ).and_return(stubbed_response)
60
+ connection = HTTPAdapter::Connection.new(
61
+ 'www.google.com', 443, hydra,
62
+ :join => [:run, [], nil]
63
+ )
64
+ @client.fetch_temporary_credential!(
65
+ :adapter => HTTPAdapter::TyphoeusRequestAdapter,
66
+ :connection => connection,
67
+ :additional_parameters => {
68
+ :scope => 'https://www.google.com/m8/feeds/'
69
+ }
70
+ )
71
+ end).should raise_error(Signet::AuthorizationError)
72
+ end
73
+
74
+ it 'should be able to obtain temporary credentials for the Contacts API' do
75
+ @client.fetch_temporary_credential!(:additional_parameters => {
76
+ :scope => 'https://www.google.com/m8/feeds/'
77
+ })
78
+ @client.temporary_credential_key.size.should > 0
79
+ @client.temporary_credential_secret.size.should > 0
80
+ end
81
+
82
+ it 'should have the correct authorization URI' do
83
+ @client.fetch_temporary_credential!(:additional_parameters => {
84
+ :scope => 'https://www.google.com/m8/feeds/'
85
+ })
86
+ @client.authorization_uri.query_values["oauth_token"].should ==
87
+ @client.temporary_credential_key
88
+ end
89
+
90
+ it 'should raise an error if the temporary credentials are bogus' do
91
+ (lambda do
92
+ @client.temporary_credential_key = '12345'
93
+ @client.temporary_credential_secret = '12345'
94
+ @client.fetch_token_credential!(:verifier => 'XbVKagBShNsAGBRJWoC4gtFR')
95
+ end).should raise_error(Signet::AuthorizationError)
96
+ end
97
+
98
+ it 'should raise an error if the token credentials are bogus' do
99
+ (lambda do
100
+ @client.token_credential_key = '12345'
101
+ @client.token_credential_secret = '12345'
102
+ @client.fetch_protected_resource(
103
+ :uri =>
104
+ 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
105
+ )
106
+ end).should raise_error(Signet::AuthorizationError)
107
+ end
108
+
109
+ # We have to stub responses for the token credentials
110
+
111
+ it 'should be able to obtain token credentials for the Contacts API' do
112
+ hydra = Typhoeus::Hydra.new
113
+ stubbed_response = Typhoeus::Response.new(
114
+ :code => 200,
115
+ :headers => '',
116
+ :body => (
117
+ 'oauth_token=1%2FYFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ&' +
118
+ 'oauth_token_secret=Ew3YHAY4bcBryiOUvbdHGa57'
119
+ )
120
+ )
121
+ hydra.stub(
122
+ :post,
123
+ 'https://www.google.com/accounts/OAuthGetAccessToken'
124
+ ).and_return(stubbed_response)
125
+ connection = HTTPAdapter::Connection.new(
126
+ 'www.google.com', 443, hydra,
127
+ :join => [:run, [], nil]
128
+ )
129
+ @client.temporary_credential_key = '4/oegn2eP-3yswD7HiESnJOB-8oh2i'
130
+ @client.temporary_credential_secret = '8E1BF0J6ovMva0j87atj/tTG'
131
+ @client.fetch_token_credential!(
132
+ :verifier => 'XbVKagBShNsAGBRJWoC4gtFR',
133
+ :adapter => HTTPAdapter::TyphoeusRequestAdapter,
134
+ :connection => connection,
135
+ :additional_parameters => {
136
+ :scope => 'https://www.google.com/m8/feeds/'
137
+ }
138
+ )
139
+ @client.token_credential_key.should ==
140
+ '1/YFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ'
141
+ @client.token_credential_secret.should == 'Ew3YHAY4bcBryiOUvbdHGa57'
142
+ end
143
+
144
+ it 'should raise an error if the server gives an unexpected status' do
145
+ (lambda do
146
+ hydra = Typhoeus::Hydra.new
147
+ stubbed_response = Typhoeus::Response.new(
148
+ :code => 999,
149
+ :headers => '',
150
+ :body => 'Rate limit hit or something.'
151
+ )
152
+ hydra.stub(
153
+ :post,
154
+ 'https://www.google.com/accounts/OAuthGetAccessToken'
155
+ ).and_return(stubbed_response)
156
+ connection = HTTPAdapter::Connection.new(
157
+ 'www.google.com', 443, hydra,
158
+ :join => [:run, [], nil]
159
+ )
160
+ @client.temporary_credential_key = '4/oegn2eP-3yswD7HiESnJOB-8oh2i'
161
+ @client.temporary_credential_secret = '8E1BF0J6ovMva0j87atj/tTG'
162
+ @client.fetch_token_credential!(
163
+ :verifier => 'XbVKagBShNsAGBRJWoC4gtFR',
164
+ :adapter => HTTPAdapter::TyphoeusRequestAdapter,
165
+ :connection => connection,
166
+ :additional_parameters => {
167
+ :scope => 'https://www.google.com/m8/feeds/'
168
+ }
169
+ )
170
+ end).should raise_error(Signet::AuthorizationError)
171
+ end
172
+
173
+ it 'should correctly fetch the protected resource' do
174
+ hydra = Typhoeus::Hydra.new
175
+ stubbed_response = Typhoeus::Response.new(
176
+ :code => 200,
177
+ :headers => "Content-Type: application/json\r\n",
178
+ :body => '{"data":"goes here"}'
179
+ )
180
+ hydra.stub(
181
+ :get,
182
+ 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
183
+ ).and_return(stubbed_response)
184
+ connection = HTTPAdapter::Connection.new(
185
+ 'www.google.com', 443, hydra,
186
+ :join => [:run, [], nil]
187
+ )
188
+ @client.token_credential_key =
189
+ '1/YFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ'
190
+ @client.token_credential_secret = 'Ew3YHAY4bcBryiOUvbdHGa57'
191
+ response = @client.fetch_protected_resource(
192
+ :adapter => HTTPAdapter::TyphoeusRequestAdapter,
193
+ :connection => connection,
194
+ :uri =>
195
+ 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
196
+ )
197
+ status, headers, body = response
198
+ status.should == 200
199
+ Hash[headers]['Content-Type'].should == 'application/json'
200
+ merge_body(body).should == '{"data":"goes here"}'
201
+ end
202
+
203
+ it 'should correctly fetch the protected resource' do
204
+ hydra = Typhoeus::Hydra.new
205
+ stubbed_response = Typhoeus::Response.new(
206
+ :code => 200,
207
+ :headers => "Content-Type: application/json\r\n",
208
+ :body => '{"data":"goes here"}'
209
+ )
210
+ hydra.stub(
211
+ :get,
212
+ 'http://www-opensocial.googleusercontent.com/api/people/@me/@self'
213
+ ).and_return(stubbed_response)
214
+ connection = HTTPAdapter::Connection.new(
215
+ 'www.google.com', 443, hydra,
216
+ :join => [:run, [], nil]
217
+ )
218
+ @client.token_credential_key =
219
+ '1/YFw6UH2Dn7W691-qAbCfsmqEHQrPb7ptIvYx9m6YkUQ'
220
+ @client.token_credential_secret = 'Ew3YHAY4bcBryiOUvbdHGa57'
221
+ response = @client.fetch_protected_resource(
222
+ :adapter => HTTPAdapter::TyphoeusRequestAdapter,
223
+ :connection => connection,
224
+ :request => Typhoeus::Request.new(
225
+ 'http://www-opensocial.googleusercontent.com/api/people/@me/@self',
226
+ :method => :get
227
+ )
228
+ )
229
+ status, headers, body = response
230
+ status.should == 200
231
+ Hash[headers]['Content-Type'].should == 'application/json'
232
+ merge_body(body).should == '{"data":"goes here"}'
233
+ end
234
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'signet'
18
+ require 'signet/oauth_1/signature_methods/hmac_sha1'
19
+
20
+ describe Signet::OAuth1::HMACSHA1 do
21
+ it 'should correctly generate a signature' do
22
+ method = "GET"
23
+ uri = "http://photos.example.net/photos"
24
+ parameters = {
25
+ "oauth_consumer_key" => "dpf43f3p2l4k3l03",
26
+ "oauth_token" => "nnch734d00sl2jdk",
27
+ "oauth_signature_method" => "HMAC-SHA1",
28
+ "oauth_timestamp" => "1191242096",
29
+ "oauth_nonce" => "kllo9940pd9333jh",
30
+ "oauth_version" => "1.0",
31
+ "file" => "vacation.jpg",
32
+ "size" => "original"
33
+ }
34
+ client_credential_secret = "kd94hf93k423kf44"
35
+ token_credential_secret = "pfkkdhi9sl3r4s00"
36
+ base_string = Signet::OAuth1.generate_base_string(method, uri, parameters)
37
+ Signet::OAuth1::HMACSHA1.generate_signature(
38
+ base_string, client_credential_secret, token_credential_secret
39
+ ).should == "tR3+Ty81lMeYAr/Fid0kMTYa/WM="
40
+ end
41
+
42
+ it 'should correctly generate a signature' do
43
+ method = "GET"
44
+ uri = "http://photos.example.net/photos"
45
+ parameters = {
46
+ "oauth_consumer_key" => "www.example.com",
47
+ "oauth_token" => "4/QL2GT6b5uznYem1ZGH6v+-9mMvRL",
48
+ "oauth_signature_method" => "HMAC-SHA1",
49
+ "oauth_timestamp" => "1191242096",
50
+ "oauth_nonce" => "kllo9940pd9333jh",
51
+ "oauth_version" => "1.0",
52
+ "file" => "vacation.jpg",
53
+ "size" => "original"
54
+ }
55
+ client_credential_secret = "Kv+o2XXL/9RxkQW3lO3QTVlH"
56
+ token_credential_secret = "QllSuL9eQ5FXFO1Z/HcgL4ON"
57
+ base_string = Signet::OAuth1.generate_base_string(method, uri, parameters)
58
+ Signet::OAuth1::HMACSHA1.generate_signature(
59
+ base_string, client_credential_secret, token_credential_secret
60
+ ).should == "G/nkdbmbpEA+6RD1Sc5uIefhFfQ="
61
+ end
62
+ end