signet 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/Gemfile +5 -5
- data/Gemfile.lock +12 -7
- data/README.md +1 -0
- data/Rakefile +3 -11
- data/lib/signet/errors.rb +8 -1
- data/lib/signet/oauth_1/client.rb +18 -10
- data/lib/signet/oauth_1/server.rb +505 -0
- data/lib/signet/oauth_2/client.rb +13 -5
- data/lib/signet/version.rb +2 -2
- data/spec/signet/oauth_1/client_spec.rb +26 -14
- data/spec/signet/oauth_1/credential_spec.rb +4 -0
- data/spec/signet/oauth_1/server_spec.rb +846 -0
- data/spec/signet/oauth_1/services/google_spec.rb +5 -1
- data/spec/signet/oauth_1/signature_methods/hmac_sha1_spec.rb +4 -0
- data/spec/signet/oauth_1_spec.rb +4 -0
- data/spec/signet/oauth_2/client_spec.rb +13 -9
- data/spec/signet/oauth_2_spec.rb +4 -0
- data/spec/signet_spec.rb +4 -0
- data/spec/spec.opts +1 -1
- data/spec/spec_helper.rb +2 -0
- data/tasks/gem.rake +6 -6
- data/tasks/spec.rake +26 -45
- data/tasks/yard.rake +16 -22
- metadata +129 -75
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
source :rubygems
|
2
2
|
|
3
3
|
gem 'addressable', '>= 2.2.3'
|
4
|
-
gem 'faraday', '~> 0.
|
5
|
-
gem 'multi_json', '>= 1.
|
6
|
-
gem 'jwt', '>= 0.1.
|
4
|
+
gem 'faraday', '~> 0.8.1'
|
5
|
+
gem 'multi_json', '>= 1.0.0'
|
6
|
+
gem 'jwt', '>= 0.1.5'
|
7
7
|
gem 'extlib', '>= 0.9.15'
|
8
8
|
gem 'jruby-openssl', :platforms => :jruby
|
9
9
|
|
10
10
|
group :development do
|
11
|
-
gem 'launchy'
|
11
|
+
gem 'launchy', '>= 2.0.0'
|
12
12
|
gem 'yard'
|
13
13
|
gem 'redcarpet'
|
14
14
|
end
|
15
15
|
|
16
16
|
group :test, :development do
|
17
17
|
gem 'rake', '>= 0.9.0'
|
18
|
-
gem 'rspec', '
|
18
|
+
gem 'rspec', '>= 2.11.0'
|
19
19
|
gem 'rcov', '>= 0.9.9', :platform => :mri_18
|
20
20
|
end
|
data/Gemfile.lock
CHANGED
@@ -3,11 +3,10 @@ GEM
|
|
3
3
|
specs:
|
4
4
|
addressable (2.2.8)
|
5
5
|
bouncy-castle-java (1.5.0146.1)
|
6
|
+
diff-lcs (1.1.3)
|
6
7
|
extlib (0.9.15)
|
7
|
-
faraday (0.
|
8
|
-
addressable (~> 2.2)
|
8
|
+
faraday (0.8.1)
|
9
9
|
multipart-post (~> 1.1)
|
10
|
-
rack (~> 1.1)
|
11
10
|
ffi (1.0.11-java)
|
12
11
|
jruby-openssl (0.7.7)
|
13
12
|
bouncy-castle-java (>= 1.5.0146.1)
|
@@ -23,11 +22,17 @@ GEM
|
|
23
22
|
spoon (~> 0.0.1)
|
24
23
|
multi_json (1.3.5)
|
25
24
|
multipart-post (1.1.5)
|
26
|
-
rack (1.4.1)
|
27
25
|
rake (0.9.2.2)
|
28
26
|
rcov (1.0.0)
|
29
27
|
redcarpet (2.1.1)
|
30
|
-
rspec (
|
28
|
+
rspec (2.10.0)
|
29
|
+
rspec-core (~> 2.10.0)
|
30
|
+
rspec-expectations (~> 2.10.0)
|
31
|
+
rspec-mocks (~> 2.10.0)
|
32
|
+
rspec-core (2.10.0)
|
33
|
+
rspec-expectations (2.10.0)
|
34
|
+
diff-lcs (~> 1.1.3)
|
35
|
+
rspec-mocks (2.10.0)
|
31
36
|
spoon (0.0.1)
|
32
37
|
yard (0.8.1)
|
33
38
|
|
@@ -38,7 +43,7 @@ PLATFORMS
|
|
38
43
|
DEPENDENCIES
|
39
44
|
addressable (>= 2.2.3)
|
40
45
|
extlib (>= 0.9.15)
|
41
|
-
faraday (~> 0.
|
46
|
+
faraday (~> 0.8.1)
|
42
47
|
jruby-openssl
|
43
48
|
jwt (>= 0.1.4)
|
44
49
|
launchy
|
@@ -46,5 +51,5 @@ DEPENDENCIES
|
|
46
51
|
rake (>= 0.9.0)
|
47
52
|
rcov (>= 0.9.9)
|
48
53
|
redcarpet
|
49
|
-
rspec (~>
|
54
|
+
rspec (~> 2.10.0)
|
50
55
|
yard
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -5,14 +5,6 @@ $:.uniq!
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'rake'
|
7
7
|
|
8
|
-
begin
|
9
|
-
require 'spec/rake/spectask'
|
10
|
-
rescue LoadError
|
11
|
-
STDERR.puts "Please install rspec:"
|
12
|
-
STDERR.puts "sudo gem install rspec"
|
13
|
-
exit(1)
|
14
|
-
end
|
15
|
-
|
16
8
|
require File.join(File.dirname(__FILE__), 'lib/signet', 'version')
|
17
9
|
|
18
10
|
PKG_DISPLAY_NAME = 'Signet'
|
@@ -36,11 +28,11 @@ PKG_FILES = FileList[
|
|
36
28
|
"[A-Z]*", "Rakefile"
|
37
29
|
].exclude(/database\.yml/).exclude(/[_\.]git$/)
|
38
30
|
|
39
|
-
RCOV_ENABLED = !!(RUBY_PLATFORM !=
|
31
|
+
RCOV_ENABLED = !!(RUBY_PLATFORM != 'java' && RUBY_VERSION =~ /^1\.8/)
|
40
32
|
if RCOV_ENABLED
|
41
|
-
task :default =>
|
33
|
+
task :default => 'spec:rcov'
|
42
34
|
else
|
43
|
-
task :default =>
|
35
|
+
task :default => 'spec:normal'
|
44
36
|
end
|
45
37
|
|
46
38
|
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
|
data/lib/signet/errors.rb
CHANGED
@@ -27,7 +27,14 @@ module Signet
|
|
27
27
|
end
|
28
28
|
|
29
29
|
##
|
30
|
-
# An error indicating the server
|
30
|
+
# An error indicating that the server considers the Authorization header to
|
31
|
+
# be malformed(missing/unsupported/invalid parameters), and the request
|
32
|
+
# should be considered invalid.
|
33
|
+
class MalformedAuthorizationError < StandardError
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# An error indicating the remote server refused to authorize the client.
|
31
38
|
class AuthorizationError < StandardError
|
32
39
|
##
|
33
40
|
# Creates a new authentication error.
|
@@ -12,7 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
gem 'faraday', '~> 0.
|
15
|
+
gem 'faraday', '~> 0.8.1'
|
16
16
|
require 'faraday'
|
17
17
|
require 'faraday/utils'
|
18
18
|
|
@@ -538,7 +538,8 @@ module Signet
|
|
538
538
|
options = {
|
539
539
|
:signature_method => 'HMAC-SHA1',
|
540
540
|
:additional_parameters => [],
|
541
|
-
:realm => nil
|
541
|
+
:realm => nil,
|
542
|
+
:connection => Faraday.default_connection
|
542
543
|
}.merge(options)
|
543
544
|
method = :post
|
544
545
|
parameters = ::Signet::OAuth1.unsigned_temporary_credential_parameters(
|
@@ -565,8 +566,10 @@ module Signet
|
|
565
566
|
headers << ['Content-Type', 'application/x-www-form-urlencoded']
|
566
567
|
headers << ['Content-Length', '0']
|
567
568
|
end
|
568
|
-
return
|
569
|
-
req.url(Addressable::URI.parse(
|
569
|
+
return options[:connection].build_request(method.to_s.downcase.to_sym) do |req|
|
570
|
+
req.url(Addressable::URI.parse(
|
571
|
+
self.temporary_credential_uri.to_str
|
572
|
+
).normalize.to_s)
|
570
573
|
req.headers = Faraday::Utils::Headers.new(headers)
|
571
574
|
end
|
572
575
|
end
|
@@ -603,6 +606,7 @@ module Signet
|
|
603
606
|
options[:connection] ||= Faraday.default_connection
|
604
607
|
request = self.generate_temporary_credential_request(options)
|
605
608
|
request_env = request.to_env(options[:connection])
|
609
|
+
request_env[:request] ||= request
|
606
610
|
response = options[:connection].app.call(request_env)
|
607
611
|
if response.status.to_i == 200
|
608
612
|
return ::Signet::OAuth1.parse_form_encoded_credentials(response.body)
|
@@ -689,7 +693,8 @@ module Signet
|
|
689
693
|
end
|
690
694
|
options = {
|
691
695
|
:signature_method => 'HMAC-SHA1',
|
692
|
-
:realm => nil
|
696
|
+
:realm => nil,
|
697
|
+
:connection => Faraday.default_connection
|
693
698
|
}.merge(options)
|
694
699
|
method = :post
|
695
700
|
parameters = ::Signet::OAuth1.unsigned_token_credential_parameters(
|
@@ -718,8 +723,10 @@ module Signet
|
|
718
723
|
headers << ['Content-Type', 'application/x-www-form-urlencoded']
|
719
724
|
headers << ['Content-Length', '0']
|
720
725
|
end
|
721
|
-
return
|
722
|
-
req.url(Addressable::URI.parse(
|
726
|
+
return options[:connection].build_request(method.to_s.downcase.to_sym) do |req|
|
727
|
+
req.url(Addressable::URI.parse(
|
728
|
+
self.token_credential_uri.to_str
|
729
|
+
).normalize.to_s)
|
723
730
|
req.headers = Faraday::Utils::Headers.new(headers)
|
724
731
|
end
|
725
732
|
end
|
@@ -754,6 +761,7 @@ module Signet
|
|
754
761
|
options[:connection] ||= Faraday.default_connection
|
755
762
|
request = self.generate_token_credential_request(options)
|
756
763
|
request_env = request.to_env(options[:connection])
|
764
|
+
request_env[:request] ||= request
|
757
765
|
response = options[:connection].app.call(request_env)
|
758
766
|
if response.status.to_i == 200
|
759
767
|
return ::Signet::OAuth1.parse_form_encoded_credentials(response.body)
|
@@ -889,9 +897,8 @@ module Signet
|
|
889
897
|
raise TypeError, "Expected String, got #{body.class}."
|
890
898
|
end
|
891
899
|
method = method.to_s.downcase.to_sym
|
892
|
-
|
893
|
-
|
894
|
-
req.url(Addressable::URI.parse(uri))
|
900
|
+
request = options[:connection].build_request(method) do |req|
|
901
|
+
req.url(Addressable::URI.parse(uri).normalize.to_s)
|
895
902
|
req.headers = Faraday::Utils::Headers.new(headers)
|
896
903
|
req.body = body
|
897
904
|
end
|
@@ -978,6 +985,7 @@ module Signet
|
|
978
985
|
options[:connection] ||= Faraday.default_connection
|
979
986
|
request = self.generate_authenticated_request(options)
|
980
987
|
request_env = request.to_env(options[:connection])
|
988
|
+
request_env[:request] ||= request
|
981
989
|
response = options[:connection].app.call(request_env)
|
982
990
|
if response.status.to_i == 401
|
983
991
|
# When accessing a protected resource, we only want to raise an
|
@@ -0,0 +1,505 @@
|
|
1
|
+
# Copyright (C) 2011 The Yakima Herald-Republic.
|
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 'faraday'
|
16
|
+
|
17
|
+
require 'stringio'
|
18
|
+
require 'addressable/uri'
|
19
|
+
require 'signet'
|
20
|
+
require 'signet/errors'
|
21
|
+
require 'signet/oauth_1'
|
22
|
+
require 'signet/oauth_1/credential'
|
23
|
+
|
24
|
+
module Signet
|
25
|
+
module OAuth1
|
26
|
+
class Server
|
27
|
+
|
28
|
+
# @return [Proc] lookup the value from this Proc.
|
29
|
+
attr_accessor :nonce_timestamp, :client_credential, :token_credential,
|
30
|
+
:temporary_credential, :verifier
|
31
|
+
|
32
|
+
##
|
33
|
+
# Creates an OAuth 1.0 server.
|
34
|
+
# @overload initialize(options)
|
35
|
+
# @param [Proc] nonce_timestamp verify a nonce/timestamp pair.
|
36
|
+
# @param [Proc] client_credential find a client credential.
|
37
|
+
# @param [Proc] token_credential find a token credential.
|
38
|
+
# @param [Proc] temporary_credential find a temporary credential.
|
39
|
+
# @param [Proc] verifier validate a verifier value.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# server = Signet::OAuth1::Server.new(
|
43
|
+
# :nonce_timestamp =>
|
44
|
+
# lambda { |n,t| OauthNonce.remember(n,t) },
|
45
|
+
# :client_credential =>
|
46
|
+
# lambda { |key| ClientCredential.find_by_key(key).to_hash },
|
47
|
+
# :token_credential =>
|
48
|
+
# lambda { |key| TokenCredential.find_by_key(key).to_hash },
|
49
|
+
# :temporary_credential =>
|
50
|
+
# lambda { |key| TemporaryCredential.find_by_key(key).to_hash },
|
51
|
+
# :verifier =>
|
52
|
+
# lambda {|verifier| Verifier.find_by_verifier(verifier).active? }
|
53
|
+
# )
|
54
|
+
def initialize(options={})
|
55
|
+
[:nonce_timestamp, :client_credential, :token_credential,
|
56
|
+
:temporary_credential, :verifier].each do |attr|
|
57
|
+
instance_variable_set("@#{attr}", options[attr])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Determine if the supplied nonce/timestamp pair is valid by calling
|
63
|
+
# the {#nonce_timestamp} Proc.
|
64
|
+
#
|
65
|
+
# @param [String, #to_str] nonce value from the request
|
66
|
+
# @param [String, #to_str] timestamp value from the request
|
67
|
+
# @return [Boolean] if the nonce/timestamp pair is valid.
|
68
|
+
def validate_nonce_timestamp(nonce, timestamp)
|
69
|
+
nonce =
|
70
|
+
@nonce_timestamp.call(nonce, timestamp) if
|
71
|
+
@nonce_timestamp.respond_to?(:call)
|
72
|
+
nonce ? true : false
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Find the appropriate client credential by calling
|
77
|
+
# the {#client_credential} Proc.
|
78
|
+
#
|
79
|
+
# @param [String] key provided to the {#client_credential} Proc.
|
80
|
+
# @return [Signet::OAuth1::Credential] The client credential.
|
81
|
+
def find_client_credential(key)
|
82
|
+
call_credential_lookup(@client_credential, key)
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Find the appropriate client credential by calling
|
87
|
+
# the {#token_credential} Proc.
|
88
|
+
#
|
89
|
+
# @param [String] key provided to the {#token_credential} Proc.
|
90
|
+
# @return [Signet::OAuth1::Credential] if the credential is found.
|
91
|
+
def find_token_credential(key)
|
92
|
+
call_credential_lookup(@token_credential, key)
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Find the appropriate client credential by calling
|
97
|
+
# the {#temporary_credential} Proc.
|
98
|
+
#
|
99
|
+
# @param [String] key provided to the {#temporary_credential} Proc.
|
100
|
+
# @return [Signet::OAuth1::Credential] if the credential is found.
|
101
|
+
def find_temporary_credential(key)
|
102
|
+
call_credential_lookup(@temporary_credential, key)
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Call a credential lookup, and cast the result to a proper Credential.
|
107
|
+
#
|
108
|
+
# @param [Proc] credential to call.
|
109
|
+
# @param [String] key provided to the Proc in <code>credential</code>
|
110
|
+
# @return [Signet::OAuth1::Credential] credential provided by
|
111
|
+
# <code>credential</code> (if any).
|
112
|
+
def call_credential_lookup(credential, key)
|
113
|
+
cred = credential.call(key) if
|
114
|
+
credential.respond_to?(:call)
|
115
|
+
return nil if cred.nil?
|
116
|
+
return nil unless (cred.respond_to?(:to_str) ||
|
117
|
+
cred.respond_to?(:to_ary) ||
|
118
|
+
cred.respond_to?(:to_hash) )
|
119
|
+
if(cred.instance_of?(::Signet::OAuth1::Credential))
|
120
|
+
cred
|
121
|
+
else
|
122
|
+
::Signet::OAuth1::Credential.new(cred)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# Determine if the verifier is valid by calling the Proc in {#verifier}.
|
128
|
+
#
|
129
|
+
# @param [String] Key provided to the {#verifier} Proc.
|
130
|
+
# @return [Boolean] if the verifier Proc returns anything other than
|
131
|
+
# <code>nil</code> or <code>false</code>.
|
132
|
+
def find_verifier(verifier)
|
133
|
+
verified = @verifier.call(verifier) if @verifier.respond_to?(:call)
|
134
|
+
verified ? true : false
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
##
|
139
|
+
# Validate and normalize the components from an HTTP request.
|
140
|
+
# @overload verify_request_components(options)
|
141
|
+
# @param [Faraday::Request] request A pre-constructed request to verify.
|
142
|
+
# @param [String] method the HTTP method , defaults to <code>GET</code>
|
143
|
+
# @param [Addressable::URI, String] uri the URI .
|
144
|
+
# @param [Hash, Array] headers the HTTP headers.
|
145
|
+
# @param [StringIO, String] body The HTTP body.
|
146
|
+
# @param [HTTPAdapter] adapter The HTTP adapter(optional).
|
147
|
+
# @return [Hash] normalized request components
|
148
|
+
def verify_request_components(options={})
|
149
|
+
if options[:request]
|
150
|
+
if options[:request].kind_of?(Faraday::Request) || options[:request].kind_of?(Array)
|
151
|
+
request = options[:request]
|
152
|
+
elsif options[:adapter]
|
153
|
+
request = options[:adapter].adapt_request(options[:request])
|
154
|
+
end
|
155
|
+
method = request.method
|
156
|
+
uri = request.path
|
157
|
+
headers = request.headers
|
158
|
+
body = request.body
|
159
|
+
else
|
160
|
+
method = options[:method] || :get
|
161
|
+
uri = options[:uri]
|
162
|
+
headers = options[:headers] || []
|
163
|
+
body = options[:body] || ''
|
164
|
+
end
|
165
|
+
|
166
|
+
headers = headers.to_a if headers.kind_of?(Hash)
|
167
|
+
method = method.to_s.upcase
|
168
|
+
|
169
|
+
request_components = {
|
170
|
+
:method => method,
|
171
|
+
:uri => uri,
|
172
|
+
:headers => headers
|
173
|
+
}
|
174
|
+
|
175
|
+
# Verify that we have all the pieces required to validate the HTTP request
|
176
|
+
request_components.each do |(key, value)|
|
177
|
+
unless value
|
178
|
+
raise ArgumentError, "Missing :#{key} parameter."
|
179
|
+
end
|
180
|
+
end
|
181
|
+
request_components[:body] = body
|
182
|
+
request_components
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# Validate and normalize the HTTP Authorization header.
|
187
|
+
#
|
188
|
+
# @param [Array] headers from HTTP request.
|
189
|
+
# @return [Hash] Hash of Authorization header.
|
190
|
+
def verify_auth_header_components(headers)
|
191
|
+
auth_header = headers.find{|x| x[0] == 'Authorization'}
|
192
|
+
if(auth_header.nil? || auth_header[1] == '')
|
193
|
+
raise MalformedAuthorizationError.new('Authorization header is missing')
|
194
|
+
end
|
195
|
+
auth_hash = ::Signet::OAuth1.parse_authorization_header(
|
196
|
+
auth_header[1] ).inject({}) {|acc, (key,val)| acc[key.downcase] = val; acc}
|
197
|
+
|
198
|
+
auth_hash
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
##
|
203
|
+
# @overload request_realm(options)
|
204
|
+
# @param [Hash] request A pre-constructed request to verify.
|
205
|
+
# @param [String] method the HTTP method , defaults to <code>GET</code>
|
206
|
+
# @param [Addressable::URI, String] uri the URI .
|
207
|
+
# @param [Hash, Array] headers the HTTP headers.
|
208
|
+
# @param [StringIO, String] body The HTTP body.
|
209
|
+
# @param [HTTPAdapter] adapter The HTTP adapter(optional).
|
210
|
+
# @return [String] The Authorization realm(see RFC 2617) of the request.
|
211
|
+
def request_realm(options={})
|
212
|
+
if(options[:request])
|
213
|
+
request_components = verify_request_components(
|
214
|
+
:request=>options[:request],
|
215
|
+
:adapter=>options[:adapter] )
|
216
|
+
else
|
217
|
+
request_components = verify_request_components(
|
218
|
+
:method=>options[:method],
|
219
|
+
:uri=>options[:uri],
|
220
|
+
:headers=>options[:headers],
|
221
|
+
:body=>options[:body] )
|
222
|
+
end
|
223
|
+
|
224
|
+
auth_header = request_components[:headers].find{|x| x[0] == 'Authorization'}
|
225
|
+
if(auth_header.nil? || auth_header[1] == '')
|
226
|
+
raise MalformedAuthorizationError.new('Authorization header is missing')
|
227
|
+
end
|
228
|
+
auth_hash = ::Signet::OAuth1.parse_authorization_header(
|
229
|
+
auth_header[1] ).inject({}) {|acc, (key,val)| acc[key.downcase] = val; acc}
|
230
|
+
auth_hash['realm']
|
231
|
+
end
|
232
|
+
|
233
|
+
##
|
234
|
+
# Authenticates a temporary credential request. If no oauth_callback is
|
235
|
+
# present in the request, <code>oob</code> will be returned.
|
236
|
+
#
|
237
|
+
# @overload authenticate_temporary_credential_request(options)
|
238
|
+
# @param [Hash] request The configuration parameters for the request.
|
239
|
+
# @param [String] method the HTTP method , defaults to <code>GET</code>
|
240
|
+
# @param [Addressable::URI, String] uri the URI .
|
241
|
+
# @param [Hash, Array] headers the HTTP headers.
|
242
|
+
# @param [StringIO, String] body The HTTP body.
|
243
|
+
# @param [HTTPAdapter] adapter The HTTP adapter(optional).
|
244
|
+
# @return [String] The oauth_callback value, or <code>false</code> if not valid.
|
245
|
+
def authenticate_temporary_credential_request(options={})
|
246
|
+
verifications = {
|
247
|
+
:client_credential =>
|
248
|
+
lambda { |x| ::Signet::OAuth1::Credential.new('Client credential key',
|
249
|
+
'Client credential secret'
|
250
|
+
)
|
251
|
+
}
|
252
|
+
}
|
253
|
+
verifications.each do |(key, value)|
|
254
|
+
raise ArgumentError, "#{key} was not set." unless self.send(key)
|
255
|
+
end
|
256
|
+
|
257
|
+
if(options[:request])
|
258
|
+
request_components = verify_request_components(
|
259
|
+
:request=>options[:request],
|
260
|
+
:adapter=>options[:adapter] )
|
261
|
+
else
|
262
|
+
request_components = verify_request_components(
|
263
|
+
:method=>options[:method],
|
264
|
+
:uri=>options[:uri],
|
265
|
+
:headers=>options[:headers] )
|
266
|
+
end
|
267
|
+
# body should be blank; we don't care in any case.
|
268
|
+
method = request_components[:method]
|
269
|
+
uri = request_components[:uri]
|
270
|
+
headers = request_components[:headers]
|
271
|
+
|
272
|
+
auth_hash = verify_auth_header_components(headers)
|
273
|
+
return false unless(client_credential = find_client_credential(
|
274
|
+
auth_hash['oauth_consumer_key']) )
|
275
|
+
|
276
|
+
return false unless validate_nonce_timestamp(auth_hash['oauth_nonce'],
|
277
|
+
auth_hash['oauth_timestamp'])
|
278
|
+
client_credential_secret = client_credential.secret if client_credential
|
279
|
+
|
280
|
+
computed_signature = ::Signet::OAuth1.sign_parameters(
|
281
|
+
method,
|
282
|
+
uri,
|
283
|
+
# Realm isn't used, and will throw the signature off.
|
284
|
+
auth_hash.reject{|k,v| k=='realm'}.to_a,
|
285
|
+
client_credential_secret,
|
286
|
+
nil
|
287
|
+
)
|
288
|
+
if(computed_signature == auth_hash['oauth_signature'])
|
289
|
+
if(auth_hash.fetch('oauth_callback', 'oob').empty?)
|
290
|
+
'oob'
|
291
|
+
else
|
292
|
+
auth_hash.fetch('oauth_callback')
|
293
|
+
end
|
294
|
+
else
|
295
|
+
false
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
##
|
301
|
+
# Authenticates a token credential request.
|
302
|
+
# @overload authenticate_token_credential_request(options)
|
303
|
+
# @param [Hash] request The configuration parameters for the request.
|
304
|
+
# @param [String] method the HTTP method , defaults to <code>GET</code>
|
305
|
+
# @param [Addressable::URI, String] uri the URI .
|
306
|
+
# @param [Hash, Array] headers the HTTP headers.
|
307
|
+
# @param [StringIO, String] body The HTTP body.
|
308
|
+
# @param [HTTPAdapter] adapter The HTTP adapter(optional).
|
309
|
+
# @return [Hash] A hash of credentials and realm for a valid request,
|
310
|
+
# or <code>nil</code> if not valid.
|
311
|
+
def authenticate_token_credential_request(options={})
|
312
|
+
verifications = {
|
313
|
+
:client_credential =>
|
314
|
+
lambda {|x| ::Signet::OAuth1::Credential.new('Client credential key',
|
315
|
+
'Client credential secret')
|
316
|
+
},
|
317
|
+
:temporary_credential =>
|
318
|
+
lambda {|x| ::Signet::OAuth1::Credential.new('Temporary credential key',
|
319
|
+
'Temporary credential secret')
|
320
|
+
},
|
321
|
+
:verifier =>
|
322
|
+
lambda {|x| 'Verifier' }
|
323
|
+
}
|
324
|
+
verifications.each do |(key, value)|
|
325
|
+
unless self.send(key)
|
326
|
+
raise ArgumentError, "#{key} was not set."
|
327
|
+
end
|
328
|
+
end
|
329
|
+
if(options[:request])
|
330
|
+
request_components = verify_request_components(
|
331
|
+
:request=>options[:request],
|
332
|
+
:adapter=>options[:adapter]
|
333
|
+
)
|
334
|
+
else
|
335
|
+
request_components = verify_request_components(
|
336
|
+
:method=>options[:method],
|
337
|
+
:uri=>options[:uri],
|
338
|
+
:headers=>options[:headers],
|
339
|
+
:body=>options[:body]
|
340
|
+
)
|
341
|
+
end
|
342
|
+
# body should be blank; we don't care in any case.
|
343
|
+
method = request_components[:method]
|
344
|
+
uri = request_components[:uri]
|
345
|
+
headers = request_components[:headers]
|
346
|
+
|
347
|
+
auth_hash = verify_auth_header_components(headers)
|
348
|
+
return false unless(
|
349
|
+
client_credential = find_client_credential(auth_hash['oauth_consumer_key'])
|
350
|
+
)
|
351
|
+
return false unless(
|
352
|
+
temporary_credential = find_temporary_credential(auth_hash['oauth_token'])
|
353
|
+
)
|
354
|
+
return false unless validate_nonce_timestamp(
|
355
|
+
auth_hash['oauth_nonce'], auth_hash['oauth_timestamp'])
|
356
|
+
|
357
|
+
computed_signature = ::Signet::OAuth1.sign_parameters(
|
358
|
+
method,
|
359
|
+
uri,
|
360
|
+
# Realm isn't used, and will throw the signature off.
|
361
|
+
auth_hash.reject{|k,v| k=='realm'}.to_a,
|
362
|
+
client_credential.secret,
|
363
|
+
temporary_credential.secret
|
364
|
+
)
|
365
|
+
|
366
|
+
if(computed_signature == auth_hash['oauth_signature'])
|
367
|
+
{:client_credential=>client_credential,
|
368
|
+
:temporary_credential=>temporary_credential,
|
369
|
+
:realm=>auth_hash['realm']
|
370
|
+
}
|
371
|
+
else
|
372
|
+
nil
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
##
|
377
|
+
# Authenticates a request for a protected resource.
|
378
|
+
# @overload authenticate_resource_request(options)
|
379
|
+
# @param [Hash] request The configuration parameters for the request.
|
380
|
+
# @param [String] method the HTTP method , defaults to <code>GET</code>
|
381
|
+
# @param [Addressable::URI, String] uri the URI .
|
382
|
+
# @param [Hash, Array] headers the HTTP headers.
|
383
|
+
# @param [StringIO, String] body The HTTP body.
|
384
|
+
# @param [Boolean] two_legged skip the token_credential lookup?
|
385
|
+
# @param [HTTPAdapter] adapter The HTTP adapter(optional).
|
386
|
+
#
|
387
|
+
# @return [Hash] A hash of the credentials and realm for a valid request,
|
388
|
+
# or <code>nil</code> if not valid.
|
389
|
+
def authenticate_resource_request(options={})
|
390
|
+
verifications = {
|
391
|
+
:client_credential =>
|
392
|
+
lambda do |x|
|
393
|
+
::Signet::OAuth1::Credential.new('Client credential key',
|
394
|
+
'Client credential secret')
|
395
|
+
end
|
396
|
+
}
|
397
|
+
|
398
|
+
unless(options[:two_legged] == true)
|
399
|
+
verifications.update(
|
400
|
+
:token_credential =>
|
401
|
+
lambda do |x|
|
402
|
+
::Signet::OAuth1::Credential.new('Token credential key',
|
403
|
+
'Token credential secret')
|
404
|
+
end
|
405
|
+
)
|
406
|
+
end
|
407
|
+
# Make sure all required state is set
|
408
|
+
verifications.each do |(key, value)|
|
409
|
+
unless self.send(key)
|
410
|
+
raise ArgumentError, "#{key} was not set."
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
if(options[:request])
|
415
|
+
request_components = verify_request_components(
|
416
|
+
:request=>options[:request],
|
417
|
+
:adapter=>options[:adapter] )
|
418
|
+
else
|
419
|
+
request_components = verify_request_components(
|
420
|
+
:method=>options[:method],
|
421
|
+
:uri=>options[:uri],
|
422
|
+
:headers=>options[:headers],
|
423
|
+
:body=>options[:body] )
|
424
|
+
end
|
425
|
+
method = request_components[:method]
|
426
|
+
uri = request_components[:uri]
|
427
|
+
headers = request_components[:headers]
|
428
|
+
body = request_components[:body]
|
429
|
+
|
430
|
+
|
431
|
+
if !body.kind_of?(String) && body.respond_to?(:each)
|
432
|
+
# Just in case we get a chunked body
|
433
|
+
merged_body = StringIO.new
|
434
|
+
body.each do |chunk|
|
435
|
+
merged_body.write(chunk)
|
436
|
+
end
|
437
|
+
body = merged_body.string
|
438
|
+
end
|
439
|
+
if !body.kind_of?(String)
|
440
|
+
raise TypeError, "Expected String, got #{body.class}."
|
441
|
+
end
|
442
|
+
|
443
|
+
media_type = nil
|
444
|
+
headers.each do |(header, value)|
|
445
|
+
if header.downcase == 'Content-Type'.downcase
|
446
|
+
media_type = value.gsub(/^([^;]+)(;.*?)?$/, '\1')
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
auth_hash = verify_auth_header_components(headers)
|
451
|
+
|
452
|
+
auth_token = auth_hash['oauth_token']
|
453
|
+
|
454
|
+
|
455
|
+
unless(options[:two_legged])
|
456
|
+
return nil if(auth_token.nil?)
|
457
|
+
return nil unless(token_credential = find_token_credential(auth_token))
|
458
|
+
token_credential_secret = token_credential.secret if token_credential
|
459
|
+
end
|
460
|
+
|
461
|
+
return nil unless(client_credential =
|
462
|
+
find_client_credential(auth_hash['oauth_consumer_key']))
|
463
|
+
|
464
|
+
return nil unless validate_nonce_timestamp(auth_hash['oauth_nonce'],
|
465
|
+
auth_hash['oauth_timestamp'])
|
466
|
+
|
467
|
+
if(method == ('POST' || 'PUT') &&
|
468
|
+
media_type == 'application/x-www-form-urlencoded')
|
469
|
+
request_components[:body] = body
|
470
|
+
post_parameters = Addressable::URI.form_unencode(body)
|
471
|
+
post_parameters.each {|param| param[1] = "" if param[1].nil?}
|
472
|
+
# If the auth header doesn't have the same params as the body, it
|
473
|
+
# can't have been signed correctly(5849#3.4.1.3)
|
474
|
+
unless(post_parameters.sort == auth_hash.reject{|k,v| k.index('oauth_')}.to_a.sort)
|
475
|
+
raise MalformedAuthorizationError.new(
|
476
|
+
'Request is of type application/x-www-form-urlencoded ' +
|
477
|
+
'but Authentication header did not include form values'
|
478
|
+
)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
client_credential_secret = client_credential.secret if client_credential
|
483
|
+
|
484
|
+
computed_signature = ::Signet::OAuth1.sign_parameters(
|
485
|
+
method,
|
486
|
+
uri,
|
487
|
+
# Realm isn't used, and will throw the signature off.
|
488
|
+
auth_hash.reject{|k,v| k=='realm'}.to_a,
|
489
|
+
client_credential_secret,
|
490
|
+
token_credential_secret
|
491
|
+
)
|
492
|
+
|
493
|
+
if(computed_signature == auth_hash['oauth_signature'])
|
494
|
+
{:client_credential=>client_credential,
|
495
|
+
:token_credential=>token_credential,
|
496
|
+
:realm=>auth_hash['realm']
|
497
|
+
}
|
498
|
+
else
|
499
|
+
nil
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|