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.
- data/CHANGELOG +3 -0
- data/LICENSE +202 -0
- data/README +47 -0
- data/Rakefile +59 -0
- data/lib/compat/digest/hmac.rb +104 -0
- data/lib/compat/securerandom.rb +202 -0
- data/lib/signet.rb +18 -0
- data/lib/signet/errors.rb +38 -0
- data/lib/signet/oauth_1.rb +456 -0
- data/lib/signet/oauth_1/client.rb +1012 -0
- data/lib/signet/oauth_1/credential.rb +119 -0
- data/lib/signet/oauth_1/signature_methods/hmac_sha1.rb +31 -0
- data/lib/signet/version.rb +26 -0
- data/spec/force_compat/digest/hmac.rb +1 -0
- data/spec/force_compat/securerandom.rb +1 -0
- data/spec/signet/oauth_1/client_spec.rb +687 -0
- data/spec/signet/oauth_1/credential_spec.rb +163 -0
- data/spec/signet/oauth_1/services/google_spec.rb +234 -0
- data/spec/signet/oauth_1/signature_methods/hmac_sha1_spec.rb +62 -0
- data/spec/signet/oauth_1_spec.rb +883 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/clobber.rake +2 -0
- data/tasks/gem.rake +71 -0
- data/tasks/git.rake +40 -0
- data/tasks/metrics.rake +41 -0
- data/tasks/rdoc.rake +26 -0
- data/tasks/rubyforge.rake +100 -0
- data/tasks/spec.rake +69 -0
- data/tasks/yard.rake +26 -0
- data/website/index.html +95 -0
- metadata +195 -0
@@ -0,0 +1,119 @@
|
|
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
|
+
module Signet #:nodoc:
|
16
|
+
module OAuth1
|
17
|
+
class Credential
|
18
|
+
##
|
19
|
+
# Creates a token object from a key and secret.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# Signet::OAuth1::Credential.new(
|
23
|
+
# :key => "dpf43f3p2l4k3l03",
|
24
|
+
# :secret => "kd94hf93k423kf44"
|
25
|
+
# )
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# Signet::OAuth1::Credential.new([
|
29
|
+
# ["oauth_token", "dpf43f3p2l4k3l03"],
|
30
|
+
# ["oauth_token_secret", "kd94hf93k423kf44"]
|
31
|
+
# ])
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# Signet::OAuth1::Credential.new(
|
35
|
+
# "dpf43f3p2l4k3l03", "kd94hf93k423kf44"
|
36
|
+
# )
|
37
|
+
def initialize(*args)
|
38
|
+
# We want to be particularly flexible in how we initialize a token
|
39
|
+
# object for maximum interoperability. However, this flexibility
|
40
|
+
# means we need to be careful about returning an unexpected value for
|
41
|
+
# key or secret to avoid difficult-to-debug situations. Thus lots
|
42
|
+
# of type-checking.
|
43
|
+
|
44
|
+
# This is cheaper than coercing to some kind of Hash with
|
45
|
+
# indifferent access. Also uglier.
|
46
|
+
key_from_hash = lambda do |parameters|
|
47
|
+
parameters["oauth_token"] ||
|
48
|
+
parameters[:oauth_token] ||
|
49
|
+
parameters["key"] ||
|
50
|
+
parameters[:key]
|
51
|
+
end
|
52
|
+
secret_from_hash = lambda do |parameters|
|
53
|
+
parameters["oauth_token_secret"] ||
|
54
|
+
parameters[:oauth_token_secret] ||
|
55
|
+
parameters["secret"] ||
|
56
|
+
parameters[:secret]
|
57
|
+
end
|
58
|
+
if args.first.respond_to?(:to_hash)
|
59
|
+
parameters = args.first.to_hash
|
60
|
+
@key = key_from_hash.call(parameters)
|
61
|
+
@secret = secret_from_hash.call(parameters)
|
62
|
+
unless @key && @secret
|
63
|
+
raise ArgumentError,
|
64
|
+
"Could not find both key and secret in #{hash.inspect}."
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# Normalize to an Array
|
68
|
+
if !args.first.kind_of?(String) &&
|
69
|
+
!args.first.respond_to?(:to_str) &&
|
70
|
+
args.first.kind_of?(Enumerable)
|
71
|
+
# We need to special-case strings since they're technically
|
72
|
+
# Enumerable objects.
|
73
|
+
args = args.first.to_a
|
74
|
+
elsif args.first.respond_to?(:to_ary)
|
75
|
+
args = args.first.to_ary
|
76
|
+
end
|
77
|
+
if args.all? { |value| value.kind_of?(Array) }
|
78
|
+
parameters = Hash[args]
|
79
|
+
@key = key_from_hash.call(parameters)
|
80
|
+
@secret = secret_from_hash.call(parameters)
|
81
|
+
elsif args.size == 2
|
82
|
+
@key, @secret = args
|
83
|
+
else
|
84
|
+
raise ArgumentError,
|
85
|
+
"wrong number of arguments (#{args.size} for 2)"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
if @key.respond_to?(:to_str)
|
89
|
+
@key = @key.to_str
|
90
|
+
else
|
91
|
+
raise TypeError, "Expected String, got #{@key.class}."
|
92
|
+
end
|
93
|
+
if @secret.respond_to?(:to_str)
|
94
|
+
@secret = @secret.to_str
|
95
|
+
else
|
96
|
+
raise TypeError, "Expected String, got #{@secret.class}."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
attr_accessor :key, :secret
|
101
|
+
|
102
|
+
def to_hash
|
103
|
+
return {
|
104
|
+
"oauth_token" => self.key,
|
105
|
+
"oauth_token_secret" => self.secret
|
106
|
+
}
|
107
|
+
end
|
108
|
+
alias_method :to_h, :to_hash
|
109
|
+
|
110
|
+
def ==(other)
|
111
|
+
if other.respond_to?(:key) && other.respond_to?(:secret)
|
112
|
+
return self.key == other.key && self.secret == other.secret
|
113
|
+
else
|
114
|
+
return false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
begin
|
2
|
+
require 'digest/hmac'
|
3
|
+
rescue LoadError
|
4
|
+
require 'compat/digest/hmac'
|
5
|
+
end
|
6
|
+
require 'digest/sha1'
|
7
|
+
require 'base64'
|
8
|
+
|
9
|
+
require 'signet'
|
10
|
+
|
11
|
+
module Signet #:nodoc:
|
12
|
+
module OAuth1
|
13
|
+
module HMACSHA1
|
14
|
+
def self.generate_signature(
|
15
|
+
base_string, client_credential_secret, token_credential_secret)
|
16
|
+
# Both the client secret and token secret must be escaped
|
17
|
+
client_credential_secret =
|
18
|
+
Signet::OAuth1.encode(client_credential_secret)
|
19
|
+
token_credential_secret =
|
20
|
+
Signet::OAuth1.encode(token_credential_secret)
|
21
|
+
# The key for the signature is just the client secret and token
|
22
|
+
# secret joined by the '&' character. If the token secret is omitted,
|
23
|
+
# the '&' must still be present.
|
24
|
+
key = [client_credential_secret, token_credential_secret].join("&")
|
25
|
+
return Base64.encode64(Digest::HMAC.digest(
|
26
|
+
base_string, key, Digest::SHA1
|
27
|
+
)).strip
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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
|
+
# Used to prevent the class/module from being loaded more than once
|
16
|
+
unless defined? Signet::VERSION
|
17
|
+
module Signet #:nodoc:
|
18
|
+
module VERSION #:nodoc:
|
19
|
+
MAJOR = 0
|
20
|
+
MINOR = 1
|
21
|
+
TINY = 0
|
22
|
+
|
23
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
raise LoadError, "Forcing compat-mode for testing."
|
@@ -0,0 +1 @@
|
|
1
|
+
raise LoadError, "Forcing compat-mode for testing."
|
@@ -0,0 +1,687 @@
|
|
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 'addressable/uri'
|
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, 'unconfigured' do
|
29
|
+
before do
|
30
|
+
@client = Signet::OAuth1::Client.new
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should have no temporary_credential_uri' do
|
34
|
+
@client.temporary_credential_uri.should == nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should allow the temporary_credential_uri to be set to a String' do
|
38
|
+
@client.temporary_credential_uri = "http://example.com/"
|
39
|
+
@client.temporary_credential_uri.should === "http://example.com/"
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should allow the temporary_credential_uri to be set to a URI' do
|
43
|
+
@client.temporary_credential_uri =
|
44
|
+
Addressable::URI.parse("http://example.com/")
|
45
|
+
@client.temporary_credential_uri.should === "http://example.com/"
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should have no authorization_uri' do
|
49
|
+
@client.authorization_uri.should == nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should allow the authorization_uri to be set to a String' do
|
53
|
+
@client.authorization_uri = 'http://example.com/authorize'
|
54
|
+
@client.authorization_uri.to_s.should include(
|
55
|
+
'http://example.com/authorize'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should allow the authorization_uri to be set to a URI' do
|
60
|
+
@client.authorization_uri =
|
61
|
+
Addressable::URI.parse('http://example.com/authorize')
|
62
|
+
@client.authorization_uri.to_s.should include(
|
63
|
+
'http://example.com/authorize'
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should have no token_credential_uri' do
|
68
|
+
@client.token_credential_uri.should == nil
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should allow the token_credential_uri to be set to a String' do
|
72
|
+
@client.token_credential_uri = "http://example.com/"
|
73
|
+
@client.token_credential_uri.should === "http://example.com/"
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should allow the token_credential_uri to be set to a URI' do
|
77
|
+
@client.token_credential_uri =
|
78
|
+
Addressable::URI.parse("http://example.com/")
|
79
|
+
@client.token_credential_uri.should === "http://example.com/"
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should have no client_credential' do
|
83
|
+
@client.client_credential.should == nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should raise an error for partially set client credentials' do
|
87
|
+
@client.client_credential_key = "12345"
|
88
|
+
@client.client_credential_secret = nil
|
89
|
+
(lambda do
|
90
|
+
@client.client_credential
|
91
|
+
end).should raise_error(ArgumentError)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should raise an error for partially set client credentials' do
|
95
|
+
@client.client_credential_key = nil
|
96
|
+
@client.client_credential_secret = "54321"
|
97
|
+
(lambda do
|
98
|
+
@client.client_credential
|
99
|
+
end).should raise_error(ArgumentError)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should allow the client_credential to be set to a ' +
|
103
|
+
'Signet::OAuth1::Credential' do
|
104
|
+
@client.client_credential =
|
105
|
+
Signet::OAuth1::Credential.new("12345", "54321")
|
106
|
+
@client.client_credential_key.should == "12345"
|
107
|
+
@client.client_credential_secret.should == "54321"
|
108
|
+
@client.client_credential.should ==
|
109
|
+
Signet::OAuth1::Credential.new("12345", "54321")
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should allow the client_credential to be set to nil' do
|
113
|
+
@client.client_credential_key = "12345"
|
114
|
+
@client.client_credential_secret = "54321"
|
115
|
+
@client.client_credential_key.should == "12345"
|
116
|
+
@client.client_credential_secret.should == "54321"
|
117
|
+
@client.client_credential = nil
|
118
|
+
@client.client_credential.should == nil
|
119
|
+
@client.client_credential_key.should == nil
|
120
|
+
@client.client_credential_secret.should == nil
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should not allow the client_credential to be set to a bogus value' do
|
124
|
+
(lambda do
|
125
|
+
@client.client_credential = 42
|
126
|
+
end).should raise_error(TypeError)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should have no client_credential_key' do
|
130
|
+
@client.client_credential_key.should == nil
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should allow the client_credential_key to be set to a String' do
|
134
|
+
@client.client_credential_key = "12345"
|
135
|
+
@client.client_credential_key.should == "12345"
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should not allow the client_credential_key to be set to a non-String' do
|
139
|
+
(lambda do
|
140
|
+
@client.client_credential_key = 12345
|
141
|
+
end).should raise_error(TypeError)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should have no client_credential_secret' do
|
145
|
+
@client.client_credential_secret.should == nil
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should allow the client_credential_secret to be set to a String' do
|
149
|
+
@client.client_credential_secret = "54321"
|
150
|
+
@client.client_credential_secret.should === "54321"
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should not allow the client_credential_secret ' +
|
154
|
+
'to be set to a non-String' do
|
155
|
+
(lambda do
|
156
|
+
@client.client_credential_secret = 54321
|
157
|
+
end).should raise_error(TypeError)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'should have an out-of-band callback' do
|
161
|
+
@client.callback.should == ::Signet::OAuth1::OUT_OF_BAND
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should allow the callback to be set to a String' do
|
165
|
+
@client.callback = "http://example.com/callback"
|
166
|
+
@client.callback.should == "http://example.com/callback"
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should allow the callback to be set to a URI' do
|
170
|
+
@client.callback =
|
171
|
+
Addressable::URI.parse("http://example.com/callback")
|
172
|
+
@client.callback.should == "http://example.com/callback"
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should not allow the callback to be set to a non-String' do
|
176
|
+
(lambda do
|
177
|
+
@client.callback = 12345
|
178
|
+
end).should raise_error(TypeError)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should raise an error if the temporary credentials URI is not set' do
|
182
|
+
@client.client_credential_key = 'dpf43f3p2l4k3l03'
|
183
|
+
@client.client_credential_secret = 'kd94hf93k423kf44'
|
184
|
+
(lambda do
|
185
|
+
@client.generate_temporary_credential_request
|
186
|
+
end).should raise_error(ArgumentError)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should raise an error if the client credential key is not set' do
|
190
|
+
@client.temporary_credential_uri =
|
191
|
+
'http://example.com/temporary_credentials'
|
192
|
+
@client.client_credential_secret = 'kd94hf93k423kf44'
|
193
|
+
(lambda do
|
194
|
+
@client.generate_temporary_credential_request
|
195
|
+
end).should raise_error(ArgumentError)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should raise an error if the client credential secret is not set' do
|
199
|
+
@client.temporary_credential_uri =
|
200
|
+
'http://example.com/temporary_credentials'
|
201
|
+
@client.client_credential_key = 'dpf43f3p2l4k3l03'
|
202
|
+
(lambda do
|
203
|
+
@client.generate_temporary_credential_request
|
204
|
+
end).should raise_error(ArgumentError)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should have no temporary_credential' do
|
208
|
+
@client.temporary_credential.should == nil
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should raise an error for partially set temporary credentials' do
|
212
|
+
@client.temporary_credential_key = "12345"
|
213
|
+
@client.temporary_credential_secret = nil
|
214
|
+
(lambda do
|
215
|
+
@client.temporary_credential
|
216
|
+
end).should raise_error(ArgumentError)
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'should raise an error for partially set temporary credentials' do
|
220
|
+
@client.temporary_credential_key = nil
|
221
|
+
@client.temporary_credential_secret = "54321"
|
222
|
+
(lambda do
|
223
|
+
@client.temporary_credential
|
224
|
+
end).should raise_error(ArgumentError)
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'should allow the temporary_credential to be set to a ' +
|
228
|
+
'Signet::OAuth1::Credential' do
|
229
|
+
@client.temporary_credential =
|
230
|
+
Signet::OAuth1::Credential.new("12345", "54321")
|
231
|
+
@client.temporary_credential_key.should == "12345"
|
232
|
+
@client.temporary_credential_secret.should == "54321"
|
233
|
+
@client.temporary_credential.should ==
|
234
|
+
Signet::OAuth1::Credential.new("12345", "54321")
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'should allow the temporary_credential to be set to nil' do
|
238
|
+
@client.temporary_credential_key = "12345"
|
239
|
+
@client.temporary_credential_secret = "54321"
|
240
|
+
@client.temporary_credential_key.should == "12345"
|
241
|
+
@client.temporary_credential_secret.should == "54321"
|
242
|
+
@client.temporary_credential = nil
|
243
|
+
@client.temporary_credential.should == nil
|
244
|
+
@client.temporary_credential_key.should == nil
|
245
|
+
@client.temporary_credential_secret.should == nil
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should not allow the temporary_credential to be set to a bogus value' do
|
249
|
+
(lambda do
|
250
|
+
@client.temporary_credential = 42
|
251
|
+
end).should raise_error(TypeError)
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'should have no temporary_credential_key' do
|
255
|
+
@client.temporary_credential_key.should == nil
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should allow the temporary_credential_key to be set to a String' do
|
259
|
+
@client.temporary_credential_key = "12345"
|
260
|
+
@client.temporary_credential_key.should === "12345"
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should not allow the temporary_credential_key ' +
|
264
|
+
'to be set to a non-String' do
|
265
|
+
(lambda do
|
266
|
+
@client.temporary_credential_key = 12345
|
267
|
+
end).should raise_error(TypeError)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'should have no temporary_credential_secret' do
|
271
|
+
@client.temporary_credential_secret.should == nil
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'should allow the temporary_credential_secret to be set to a String' do
|
275
|
+
@client.temporary_credential_secret = "54321"
|
276
|
+
@client.temporary_credential_secret.should === "54321"
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should not allow the temporary_credential_secret ' +
|
280
|
+
'to be set to a non-String' do
|
281
|
+
(lambda do
|
282
|
+
@client.temporary_credential_secret = 54321
|
283
|
+
end).should raise_error(TypeError)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'should have no token_credential' do
|
287
|
+
@client.token_credential.should == nil
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'should raise an error for partially set token credentials' do
|
291
|
+
@client.token_credential_key = "12345"
|
292
|
+
@client.token_credential_secret = nil
|
293
|
+
(lambda do
|
294
|
+
@client.token_credential
|
295
|
+
end).should raise_error(ArgumentError)
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'should raise an error for partially set token credentials' do
|
299
|
+
@client.token_credential_key = nil
|
300
|
+
@client.token_credential_secret = "54321"
|
301
|
+
(lambda do
|
302
|
+
@client.token_credential
|
303
|
+
end).should raise_error(ArgumentError)
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'should allow the token_credential to be set to a ' +
|
307
|
+
'Signet::OAuth1::Credential' do
|
308
|
+
@client.token_credential =
|
309
|
+
Signet::OAuth1::Credential.new("12345", "54321")
|
310
|
+
@client.token_credential_key.should == "12345"
|
311
|
+
@client.token_credential_secret.should == "54321"
|
312
|
+
@client.token_credential.should ==
|
313
|
+
Signet::OAuth1::Credential.new("12345", "54321")
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'should allow the token_credential to be set to nil' do
|
317
|
+
@client.token_credential_key = "12345"
|
318
|
+
@client.token_credential_secret = "54321"
|
319
|
+
@client.token_credential_key.should == "12345"
|
320
|
+
@client.token_credential_secret.should == "54321"
|
321
|
+
@client.token_credential = nil
|
322
|
+
@client.token_credential.should == nil
|
323
|
+
@client.token_credential_key.should == nil
|
324
|
+
@client.token_credential_secret.should == nil
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should not allow the token_credential to be set to a bogus value' do
|
328
|
+
(lambda do
|
329
|
+
@client.token_credential = 42
|
330
|
+
end).should raise_error(TypeError)
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'should have no token_credential_key' do
|
334
|
+
@client.token_credential_key.should == nil
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'should allow the token_credential_key to be set to a String' do
|
338
|
+
@client.token_credential_key = "12345"
|
339
|
+
@client.token_credential_key.should === "12345"
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'should not allow the token_credential_key ' +
|
343
|
+
'to be set to a non-String' do
|
344
|
+
(lambda do
|
345
|
+
@client.token_credential_key = 12345
|
346
|
+
end).should raise_error(TypeError)
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'should have no token_credential_secret' do
|
350
|
+
@client.token_credential_secret.should == nil
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'should allow the token_credential_secret to be set to a String' do
|
354
|
+
@client.token_credential_secret = "54321"
|
355
|
+
@client.token_credential_secret.should === "54321"
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'should not allow the token_credential_secret ' +
|
359
|
+
'to be set to a non-String' do
|
360
|
+
(lambda do
|
361
|
+
@client.token_credential_secret = 54321
|
362
|
+
end).should raise_error(TypeError)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
describe Signet::OAuth1::Client, 'configured' do
|
367
|
+
before do
|
368
|
+
@client = Signet::OAuth1::Client.new
|
369
|
+
@client.temporary_credential_uri =
|
370
|
+
'http://example.com/temporary_credentials'
|
371
|
+
@client.authorization_uri =
|
372
|
+
'http://example.com/authorize'
|
373
|
+
@client.token_credential_uri =
|
374
|
+
'http://example.com/token_credentials'
|
375
|
+
@client.callback = 'http://example.com/callback'
|
376
|
+
@client.client_credential_key = 'dpf43f3p2l4k3l03'
|
377
|
+
@client.client_credential_secret = 'kd94hf93k423kf44'
|
378
|
+
@client.temporary_credential_key = 'hh5s93j4hdidpola'
|
379
|
+
@client.temporary_credential_secret = 'hdhd0244k9j7ao03'
|
380
|
+
@client.token_credential_key = 'nnch734d00sl2jdk'
|
381
|
+
@client.token_credential_secret = 'pfkkdhi9sl3r4s00'
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'should generate an authorization URI with a callback' do
|
385
|
+
@client.temporary_credential_key = nil
|
386
|
+
@client.authorization_uri.should ===
|
387
|
+
'http://example.com/authorize?oauth_callback=http://example.com/callback'
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'should generate an authorization URI with a temporary credential' do
|
391
|
+
@client.callback = nil
|
392
|
+
@client.authorization_uri.to_s.should include(
|
393
|
+
'oauth_token=hh5s93j4hdidpola'
|
394
|
+
)
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should generate an authorization URI both a callback and ' +
|
398
|
+
'a temporary credential' do
|
399
|
+
@client.authorization_uri.to_s.should include(
|
400
|
+
'oauth_callback=http://example.com/callback'
|
401
|
+
)
|
402
|
+
@client.authorization_uri.to_s.should include(
|
403
|
+
'oauth_token=hh5s93j4hdidpola'
|
404
|
+
)
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'should generate an authorization URI with additional parameters' do
|
408
|
+
authorization_uri = @client.authorization_uri(
|
409
|
+
:additional_parameters => {:domain => 'www.example.com'}
|
410
|
+
)
|
411
|
+
authorization_uri.to_s.should include(
|
412
|
+
'oauth_callback=http://example.com/callback'
|
413
|
+
)
|
414
|
+
authorization_uri.to_s.should include(
|
415
|
+
'oauth_token=hh5s93j4hdidpola'
|
416
|
+
)
|
417
|
+
authorization_uri.to_s.should include(
|
418
|
+
'domain=www.example.com'
|
419
|
+
)
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'should raise an error if the verifier is not provided' do
|
423
|
+
(lambda do
|
424
|
+
@client.generate_token_credential_request
|
425
|
+
end).should raise_error(ArgumentError)
|
426
|
+
(lambda do
|
427
|
+
@client.generate_token_credential_request(:verifier => nil)
|
428
|
+
end).should raise_error(ArgumentError)
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'should raise an error if the token credentials URI is not set' do
|
432
|
+
@client.token_credential_uri = nil
|
433
|
+
(lambda do
|
434
|
+
@client.generate_token_credential_request(:verifier => '12345')
|
435
|
+
end).should raise_error(ArgumentError)
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'should raise an error if the client credential key is not set' do
|
439
|
+
@client.client_credential_key = nil
|
440
|
+
(lambda do
|
441
|
+
@client.generate_token_credential_request(:verifier => '12345')
|
442
|
+
end).should raise_error(ArgumentError)
|
443
|
+
end
|
444
|
+
|
445
|
+
it 'should raise an error if the client credential secret is not set' do
|
446
|
+
@client.client_credential_secret = nil
|
447
|
+
(lambda do
|
448
|
+
@client.generate_token_credential_request(:verifier => '12345')
|
449
|
+
end).should raise_error(ArgumentError)
|
450
|
+
end
|
451
|
+
|
452
|
+
it 'should raise an error if the temporary credential key is not set' do
|
453
|
+
@client.temporary_credential_key = nil
|
454
|
+
(lambda do
|
455
|
+
@client.generate_token_credential_request(:verifier => '12345')
|
456
|
+
end).should raise_error(ArgumentError)
|
457
|
+
end
|
458
|
+
|
459
|
+
it 'should raise an error if the temporary credential secret is not set' do
|
460
|
+
@client.temporary_credential_secret = nil
|
461
|
+
(lambda do
|
462
|
+
@client.generate_token_credential_request(:verifier => '12345')
|
463
|
+
end).should raise_error(ArgumentError)
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'should raise an error if the client credential key is not set' do
|
467
|
+
@client.client_credential_key = nil
|
468
|
+
(lambda do
|
469
|
+
@client.generate_authenticated_request
|
470
|
+
end).should raise_error(ArgumentError)
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'should raise an error if the client credential secret is not set' do
|
474
|
+
@client.client_credential_secret = nil
|
475
|
+
(lambda do
|
476
|
+
@client.generate_authenticated_request
|
477
|
+
end).should raise_error(ArgumentError)
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'should raise an error if the token credential key is not set' do
|
481
|
+
@client.token_credential_key = nil
|
482
|
+
(lambda do
|
483
|
+
@client.generate_authenticated_request
|
484
|
+
end).should raise_error(ArgumentError)
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'should raise an error if the token credential secret is not set' do
|
488
|
+
@client.token_credential_secret = nil
|
489
|
+
(lambda do
|
490
|
+
@client.generate_authenticated_request
|
491
|
+
end).should raise_error(ArgumentError)
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'should raise an error if no request is provided' do
|
495
|
+
(lambda do
|
496
|
+
@client.generate_authenticated_request
|
497
|
+
end).should raise_error(ArgumentError)
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'should raise an error if a bogus request is provided' do
|
501
|
+
(lambda do
|
502
|
+
@client.generate_authenticated_request(
|
503
|
+
:request => []
|
504
|
+
)
|
505
|
+
end).should raise_error(ArgumentError)
|
506
|
+
end
|
507
|
+
|
508
|
+
it 'should raise an error if no URI is provided' do
|
509
|
+
(lambda do
|
510
|
+
@client.generate_authenticated_request(
|
511
|
+
:method => 'GET',
|
512
|
+
:headers => [],
|
513
|
+
:body => ''
|
514
|
+
)
|
515
|
+
end).should raise_error(ArgumentError)
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'should not raise an error if a request body is chunked' do
|
519
|
+
request = @client.generate_authenticated_request(
|
520
|
+
:method => 'POST',
|
521
|
+
:uri => 'https://photos.example.net/photos',
|
522
|
+
:body => ['A chunked body.']
|
523
|
+
)
|
524
|
+
method, uri, headers, body = request
|
525
|
+
merge_body(body).should == 'A chunked body.'
|
526
|
+
end
|
527
|
+
|
528
|
+
it 'should not raise an error if a request body is chunked' do
|
529
|
+
chunked_body = StringIO.new
|
530
|
+
chunked_body.write('A chunked body.')
|
531
|
+
chunked_body.rewind
|
532
|
+
request = @client.generate_authenticated_request(
|
533
|
+
:method => 'POST',
|
534
|
+
:uri => 'https://photos.example.net/photos',
|
535
|
+
:body => chunked_body
|
536
|
+
)
|
537
|
+
method, uri, headers, body = request
|
538
|
+
merge_body(body).should == 'A chunked body.'
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'should raise an error if a request body is of a bogus type' do
|
542
|
+
(lambda do
|
543
|
+
@client.generate_authenticated_request(
|
544
|
+
:method => 'POST',
|
545
|
+
:uri => 'https://photos.example.net/photos',
|
546
|
+
:body => 42
|
547
|
+
)
|
548
|
+
end).should raise_error(TypeError)
|
549
|
+
end
|
550
|
+
|
551
|
+
it 'should correctly fetch the temporary credentials' do
|
552
|
+
# Repeat this because signatures change from test to test
|
553
|
+
10.times do
|
554
|
+
request = @client.generate_temporary_credential_request
|
555
|
+
method, uri, headers, body = request
|
556
|
+
method.should == 'POST'
|
557
|
+
uri.should == 'http://example.com/temporary_credentials'
|
558
|
+
authorization_header = nil
|
559
|
+
headers.each do |(header, value)|
|
560
|
+
authorization_header = value if header == 'Authorization'
|
561
|
+
end
|
562
|
+
parameters = Hash[::Signet::OAuth1.parse_authorization_header(
|
563
|
+
authorization_header
|
564
|
+
)]
|
565
|
+
parameters.should_not have_key('oauth_client_credential_key')
|
566
|
+
parameters.should_not have_key('oauth_temporary_credential_key')
|
567
|
+
parameters.should_not have_key('oauth_token')
|
568
|
+
parameters['oauth_nonce'].should =~ /^\w+$/
|
569
|
+
parameters['oauth_callback'].should == @client.callback
|
570
|
+
parameters['oauth_timestamp'].should =~ /^\d+$/
|
571
|
+
parameters['oauth_signature_method'].should == 'HMAC-SHA1'
|
572
|
+
parameters['oauth_consumer_key'].should == @client.client_credential_key
|
573
|
+
parameters['oauth_signature'].should =~ /^[a-zA-Z0-9\=\/\+]+$/
|
574
|
+
parameters['oauth_version'].should == '1.0'
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
it 'should correctly fetch the token credentials' do
|
579
|
+
# Repeat this because signatures change from test to test
|
580
|
+
10.times do
|
581
|
+
request = @client.generate_token_credential_request(
|
582
|
+
:verifier => '473f82d3'
|
583
|
+
)
|
584
|
+
method, uri, headers, body = request
|
585
|
+
method.should == 'POST'
|
586
|
+
uri.should == 'http://example.com/token_credentials'
|
587
|
+
authorization_header = nil
|
588
|
+
headers.each do |(header, value)|
|
589
|
+
authorization_header = value if header == 'Authorization'
|
590
|
+
end
|
591
|
+
parameters = Hash[::Signet::OAuth1.parse_authorization_header(
|
592
|
+
authorization_header
|
593
|
+
)]
|
594
|
+
parameters.should_not have_key('oauth_client_credential_key')
|
595
|
+
parameters.should_not have_key('oauth_temporary_credential_key')
|
596
|
+
parameters.should_not have_key('oauth_callback')
|
597
|
+
parameters['oauth_nonce'].should =~ /^\w+$/
|
598
|
+
parameters['oauth_timestamp'].should =~ /^\d+$/
|
599
|
+
parameters['oauth_signature_method'].should == 'HMAC-SHA1'
|
600
|
+
parameters['oauth_consumer_key'].should == @client.client_credential_key
|
601
|
+
parameters['oauth_token'].should == @client.temporary_credential_key
|
602
|
+
parameters['oauth_signature'].should =~ /^[a-zA-Z0-9\=\/\+]+$/
|
603
|
+
parameters['oauth_verifier'].should == '473f82d3'
|
604
|
+
parameters['oauth_version'].should == '1.0'
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
it 'should correctly fetch the protected resource' do
|
609
|
+
# Repeat this because signatures change from test to test
|
610
|
+
10.times do
|
611
|
+
original_request = [
|
612
|
+
'GET',
|
613
|
+
'https://photos.example.net/photos?file=vacation.jpg&size=original',
|
614
|
+
[['Host', 'photos.example.net']],
|
615
|
+
['']
|
616
|
+
]
|
617
|
+
signed_request = @client.generate_authenticated_request(
|
618
|
+
:request => original_request
|
619
|
+
)
|
620
|
+
method, uri, headers, body = signed_request
|
621
|
+
method.should == 'GET'
|
622
|
+
uri.should ==
|
623
|
+
'https://photos.example.net/photos?file=vacation.jpg&size=original'
|
624
|
+
authorization_header = nil
|
625
|
+
headers.each do |(header, value)|
|
626
|
+
authorization_header = value if header == 'Authorization'
|
627
|
+
end
|
628
|
+
merge_body(body).should == ''
|
629
|
+
parameters = Hash[::Signet::OAuth1.parse_authorization_header(
|
630
|
+
authorization_header
|
631
|
+
)]
|
632
|
+
parameters.should_not have_key('oauth_client_credential_key')
|
633
|
+
parameters.should_not have_key('oauth_temporary_credential_key')
|
634
|
+
parameters.should_not have_key('oauth_token_credential_key')
|
635
|
+
parameters.should_not have_key('oauth_callback')
|
636
|
+
parameters['oauth_nonce'].should =~ /^\w+$/
|
637
|
+
parameters['oauth_timestamp'].should =~ /^\d+$/
|
638
|
+
parameters['oauth_signature_method'].should == 'HMAC-SHA1'
|
639
|
+
parameters['oauth_consumer_key'].should == @client.client_credential_key
|
640
|
+
parameters['oauth_token'].should == @client.token_credential_key
|
641
|
+
parameters['oauth_signature'].should =~ /^[a-zA-Z0-9\=\/\+]+$/
|
642
|
+
parameters['oauth_version'].should == '1.0'
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
it 'should correctly fetch the protected resource' do
|
647
|
+
# Repeat this because signatures change from test to test
|
648
|
+
10.times do
|
649
|
+
original_request = [
|
650
|
+
'POST',
|
651
|
+
'https://photos.example.net/photos',
|
652
|
+
[
|
653
|
+
['Host', 'photos.example.net'],
|
654
|
+
['Content-Type', 'application/x-www-form-urlencoded; charset=utf-8'],
|
655
|
+
['Content-Length', '31'],
|
656
|
+
],
|
657
|
+
['file=vacation.jpg&size=original']
|
658
|
+
]
|
659
|
+
signed_request = @client.generate_authenticated_request(
|
660
|
+
:request => original_request
|
661
|
+
)
|
662
|
+
method, uri, headers, body = signed_request
|
663
|
+
method.should == 'POST'
|
664
|
+
uri.should ==
|
665
|
+
'https://photos.example.net/photos'
|
666
|
+
authorization_header = nil
|
667
|
+
headers.each do |(header, value)|
|
668
|
+
authorization_header = value if header == 'Authorization'
|
669
|
+
end
|
670
|
+
merge_body(body).should == 'file=vacation.jpg&size=original'
|
671
|
+
parameters = Hash[::Signet::OAuth1.parse_authorization_header(
|
672
|
+
authorization_header
|
673
|
+
)]
|
674
|
+
parameters.should_not have_key('oauth_client_credential_key')
|
675
|
+
parameters.should_not have_key('oauth_temporary_credential_key')
|
676
|
+
parameters.should_not have_key('oauth_token_credential_key')
|
677
|
+
parameters.should_not have_key('oauth_callback')
|
678
|
+
parameters['oauth_nonce'].should =~ /^\w+$/
|
679
|
+
parameters['oauth_timestamp'].should =~ /^\d+$/
|
680
|
+
parameters['oauth_signature_method'].should == 'HMAC-SHA1'
|
681
|
+
parameters['oauth_consumer_key'].should == @client.client_credential_key
|
682
|
+
parameters['oauth_token'].should == @client.token_credential_key
|
683
|
+
parameters['oauth_signature'].should =~ /^[a-zA-Z0-9\=\/\+]+$/
|
684
|
+
parameters['oauth_version'].should == '1.0'
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|