signet 0.1.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.
@@ -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