oauth 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oauth might be problematic. Click here for more details.
- data/History.txt +35 -17
- data/Manifest.txt +13 -1
- data/README.rdoc +5 -7
- data/Rakefile +6 -4
- data/TODO +18 -0
- data/bin/oauth +1 -1
- data/examples/yql.rb +44 -0
- data/lib/oauth.rb +1 -0
- data/lib/oauth/cli.rb +201 -31
- data/lib/oauth/client/action_controller_request.rb +13 -12
- data/lib/oauth/client/helper.rb +10 -14
- data/lib/oauth/client/net_http.rb +25 -22
- data/lib/oauth/consumer.rb +164 -110
- data/lib/oauth/errors.rb +3 -0
- data/lib/oauth/errors/error.rb +4 -0
- data/lib/oauth/errors/problem.rb +14 -0
- data/lib/oauth/errors/unauthorized.rb +12 -0
- data/lib/oauth/helper.rb +44 -6
- data/lib/oauth/oauth.rb +7 -0
- data/lib/oauth/oauth_test_helper.rb +12 -13
- data/lib/oauth/request_proxy/action_controller_request.rb +5 -6
- data/lib/oauth/request_proxy/base.rb +95 -45
- data/lib/oauth/request_proxy/jabber_request.rb +1 -2
- data/lib/oauth/request_proxy/mock_request.rb +8 -0
- data/lib/oauth/request_proxy/net_http.rb +2 -2
- data/lib/oauth/request_proxy/rack_request.rb +7 -7
- data/lib/oauth/server.rb +31 -33
- data/lib/oauth/signature/base.rb +23 -21
- data/lib/oauth/signature/hmac/base.rb +1 -1
- data/lib/oauth/signature/hmac/sha1.rb +0 -1
- data/lib/oauth/signature/plaintext.rb +2 -2
- data/lib/oauth/signature/rsa/sha1.rb +5 -4
- data/lib/oauth/token.rb +6 -136
- data/lib/oauth/tokens/access_token.rb +68 -0
- data/lib/oauth/tokens/consumer_token.rb +32 -0
- data/lib/oauth/tokens/request_token.rb +28 -0
- data/lib/oauth/tokens/server_token.rb +9 -0
- data/lib/oauth/tokens/token.rb +17 -0
- data/lib/oauth/version.rb +1 -1
- data/oauth.gemspec +12 -6
- data/test/cases/spec/1_0-final/test_construct_request_url.rb +1 -1
- data/test/test_access_token.rb +28 -0
- data/test/test_action_controller_request_proxy.rb +17 -0
- data/test/test_consumer.rb +3 -4
- data/test/test_helper.rb +0 -5
- data/test/test_request_token.rb +53 -0
- data/test/test_server.rb +1 -1
- data/website/index.html +2 -2
- metadata +37 -4
- data/specs.txt +0 -13
data/lib/oauth/errors.rb
ADDED
data/lib/oauth/helper.rb
CHANGED
@@ -1,17 +1,55 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
require 'base64'
|
3
|
-
|
3
|
+
|
4
4
|
module OAuth
|
5
5
|
module Helper
|
6
6
|
extend self
|
7
7
|
|
8
8
|
def escape(value)
|
9
|
-
|
9
|
+
URI::escape(value.to_s, OAuth::RESERVED_CHARACTERS)
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def generate_key(size=32)
|
13
|
-
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/,'')
|
14
|
-
end
|
15
|
-
|
13
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :generate_nonce, :generate_key
|
17
|
+
|
18
|
+
def generate_timestamp
|
19
|
+
Time.now.to_i.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def normalize(params)
|
23
|
+
params.sort.map do |k, values|
|
24
|
+
|
25
|
+
if values.is_a?(Array)
|
26
|
+
# multiple values were provided for a single key
|
27
|
+
values.sort.collect do |v|
|
28
|
+
[escape(k),escape(v)] * "="
|
29
|
+
end
|
30
|
+
else
|
31
|
+
[escape(k),escape(values)] * "="
|
32
|
+
end
|
33
|
+
end * "&"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Parse an Authorization / WWW-Authenticate header into a hash
|
37
|
+
def parse_header(header)
|
38
|
+
# decompose
|
39
|
+
params = header[6,header.length].split(/[,=]/)
|
40
|
+
|
41
|
+
# strip and unescape
|
42
|
+
params.map! { |v| unescape(v.strip) }
|
43
|
+
|
44
|
+
# strip quotes
|
45
|
+
params.map! { |v| v =~ /^\".*\"$/ ? v[1..-2] : v }
|
46
|
+
|
47
|
+
# convert into a Hash
|
48
|
+
Hash[*params.flatten]
|
49
|
+
end
|
50
|
+
|
51
|
+
def unescape(value)
|
52
|
+
URI.unescape(value.gsub('+', '%2B'))
|
53
|
+
end
|
16
54
|
end
|
17
55
|
end
|
data/lib/oauth/oauth.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
module OAuth
|
2
|
+
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
3
|
+
PARAMETERS = %w(oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_version oauth_signature)
|
4
|
+
|
5
|
+
# reserved character regexp, per section 5.1
|
6
|
+
RESERVED_CHARACTERS = /[^\w\d\-\.\_\~]/
|
7
|
+
end
|
@@ -1,26 +1,25 @@
|
|
1
1
|
require 'action_controller'
|
2
2
|
require 'action_controller/test_process'
|
3
|
+
|
3
4
|
module OAuth
|
4
5
|
module OAuthTestHelper
|
5
|
-
|
6
6
|
def mock_incoming_request_with_query(request)
|
7
|
-
incoming=ActionController::TestRequest.new(request.to_hash)
|
8
|
-
incoming.request_uri=request.path
|
9
|
-
incoming.
|
10
|
-
incoming.
|
11
|
-
incoming.env['REQUEST_METHOD']=request.http_method
|
7
|
+
incoming = ActionController::TestRequest.new(request.to_hash)
|
8
|
+
incoming.request_uri = request.path
|
9
|
+
incoming.host = request.uri.host
|
10
|
+
incoming.env["SERVER_PORT"] = request.uri.port
|
11
|
+
incoming.env['REQUEST_METHOD'] = request.http_method
|
12
12
|
incoming
|
13
13
|
end
|
14
14
|
|
15
15
|
def mock_incoming_request_with_authorize_header(request)
|
16
|
-
incoming=ActionController::TestRequest.new
|
17
|
-
incoming.
|
18
|
-
incoming.
|
19
|
-
incoming.env["
|
20
|
-
incoming.
|
21
|
-
incoming.env['REQUEST_METHOD']=request.http_method
|
16
|
+
incoming = ActionController::TestRequest.new
|
17
|
+
incoming.request_uri = request.path
|
18
|
+
incoming.host = request.uri.host
|
19
|
+
incoming.env["HTTP_AUTHORIZATION"] = request.to_auth_string
|
20
|
+
incoming.env["SERVER_PORT"] = request.uri.port
|
21
|
+
incoming.env['REQUEST_METHOD'] = request.http_method
|
22
22
|
incoming
|
23
23
|
end
|
24
|
-
|
25
24
|
end
|
26
25
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'active_support'
|
3
2
|
require 'action_controller/request'
|
4
3
|
require 'oauth/request_proxy/base'
|
@@ -25,7 +24,7 @@ module OAuth::RequestProxy
|
|
25
24
|
params.merge(options[:parameters] || {})
|
26
25
|
end
|
27
26
|
end
|
28
|
-
|
27
|
+
|
29
28
|
# Override from OAuth::RequestProxy::Base to avoid roundtrip
|
30
29
|
# conversion to Hash or Array and thus preserve the original
|
31
30
|
# parameter names
|
@@ -37,18 +36,18 @@ module OAuth::RequestProxy
|
|
37
36
|
params << header_params.to_query
|
38
37
|
params << request.query_string unless request.query_string.blank?
|
39
38
|
if request.content_type == Mime::Type.lookup("application/x-www-form-urlencoded")
|
40
|
-
params <<
|
39
|
+
params << request.raw_post
|
41
40
|
end
|
42
41
|
end
|
43
|
-
|
42
|
+
|
44
43
|
params.
|
45
44
|
join('&').split('&').
|
46
45
|
reject { |kv| kv =~ /^oauth_signature=.*/}.
|
47
46
|
reject(&:blank?).
|
48
|
-
map { |p| p.split('=') }
|
47
|
+
map { |p| p.split('=').map{|esc| CGI.unescape(esc)} }
|
49
48
|
end
|
50
49
|
|
51
|
-
|
50
|
+
protected
|
52
51
|
|
53
52
|
def query_params
|
54
53
|
request.query_parameters
|
@@ -16,70 +16,125 @@ module OAuth::RequestProxy
|
|
16
16
|
@options = options
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
parameters['oauth_token']
|
21
|
-
end
|
19
|
+
## OAuth parameters
|
22
20
|
|
23
|
-
def
|
21
|
+
def oauth_consumer_key
|
24
22
|
parameters['oauth_consumer_key']
|
25
23
|
end
|
26
24
|
|
27
|
-
def
|
28
|
-
p = parameters.dup
|
29
|
-
p.delete("oauth_signature")
|
30
|
-
p
|
31
|
-
end
|
32
|
-
|
33
|
-
def nonce
|
25
|
+
def oauth_nonce
|
34
26
|
parameters['oauth_nonce']
|
35
27
|
end
|
36
28
|
|
37
|
-
def
|
38
|
-
|
29
|
+
def oauth_signature
|
30
|
+
# TODO can this be nil?
|
31
|
+
parameters['oauth_signature'] || ""
|
39
32
|
end
|
40
33
|
|
41
|
-
def
|
34
|
+
def oauth_signature_method
|
42
35
|
case parameters['oauth_signature_method']
|
43
|
-
when Array
|
36
|
+
when Array
|
37
|
+
parameters['oauth_signature_method'].first
|
44
38
|
else
|
45
39
|
parameters['oauth_signature_method']
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
49
|
-
def
|
50
|
-
parameters['
|
43
|
+
def oauth_timestamp
|
44
|
+
parameters['oauth_timestamp']
|
45
|
+
end
|
46
|
+
|
47
|
+
def oauth_token
|
48
|
+
parameters['oauth_token']
|
49
|
+
end
|
50
|
+
|
51
|
+
def oauth_version
|
52
|
+
parameters["oauth_version"]
|
53
|
+
end
|
54
|
+
|
55
|
+
# TODO deprecate these
|
56
|
+
alias_method :consumer_key, :oauth_consumer_key
|
57
|
+
alias_method :token, :oauth_token
|
58
|
+
alias_method :nonce, :oauth_nonce
|
59
|
+
alias_method :timestamp, :oauth_timestamp
|
60
|
+
alias_method :signature, :oauth_signature
|
61
|
+
alias_method :signature_method, :oauth_signature_method
|
62
|
+
|
63
|
+
## Parameter accessors
|
64
|
+
|
65
|
+
def parameters
|
66
|
+
raise NotImplementedError, "Must be implemented by subclasses"
|
67
|
+
end
|
68
|
+
|
69
|
+
def parameters_for_signature
|
70
|
+
parameters.reject { |k,v| k == "oauth_signature" }
|
71
|
+
end
|
72
|
+
|
73
|
+
def oauth_parameters
|
74
|
+
parameters.select { |k,v| OAuth::PARAMETERS.include?(k) }.reject { |k,v| v == "" }
|
75
|
+
end
|
76
|
+
|
77
|
+
def non_oauth_parameters
|
78
|
+
parameters.reject { |k,v| OAuth::PARAMETERS.include?(k) }
|
51
79
|
end
|
52
|
-
|
80
|
+
|
53
81
|
# See 9.1.2 in specs
|
54
82
|
def normalized_uri
|
55
|
-
u=URI.parse(uri)
|
56
|
-
"#{u.scheme.downcase}://#{u.host.downcase}#{(u.scheme.downcase=='http'&&u.port!=80)||(u.scheme.downcase=='https'&&u.port!=443) ? ":#{u.port}" : ""}#{(u.path&&u.path!='') ? u.path : '/'}"
|
83
|
+
u = URI.parse(uri)
|
84
|
+
"#{u.scheme.downcase}://#{u.host.downcase}#{(u.scheme.downcase == 'http' && u.port != 80) || (u.scheme.downcase == 'https' && u.port != 443) ? ":#{u.port}" : ""}#{(u.path && u.path != '') ? u.path : '/'}"
|
57
85
|
end
|
58
|
-
|
86
|
+
|
59
87
|
# See 9.1.1. in specs Normalize Request Parameters
|
60
88
|
def normalized_parameters
|
61
|
-
parameters_for_signature
|
89
|
+
normalize(parameters_for_signature)
|
90
|
+
end
|
62
91
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end * "&"
|
92
|
+
def sign(options = {})
|
93
|
+
OAuth::Signature.sign(self, options)
|
94
|
+
end
|
95
|
+
|
96
|
+
def sign!(options = {})
|
97
|
+
parameters["oauth_signature"] = sign(options)
|
98
|
+
@signed = true
|
99
|
+
signature
|
72
100
|
end
|
73
|
-
|
101
|
+
|
74
102
|
# See 9.1 in specs
|
75
103
|
def signature_base_string
|
76
104
|
base = [method, normalized_uri, normalized_parameters]
|
77
105
|
base.map { |v| escape(v) }.join("&")
|
78
106
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
107
|
+
|
108
|
+
# Has this request been signed yet?
|
109
|
+
def signed?
|
110
|
+
@signed
|
111
|
+
end
|
112
|
+
|
113
|
+
# URI, including OAuth parameters
|
114
|
+
def signed_uri(with_oauth = true)
|
115
|
+
if signed?
|
116
|
+
if with_oauth
|
117
|
+
params = parameters
|
118
|
+
else
|
119
|
+
params = non_oauth_parameters
|
120
|
+
end
|
121
|
+
|
122
|
+
[uri, normalize(params)] * "?"
|
123
|
+
else
|
124
|
+
STDERR.puts "This request has not yet been signed!"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Authorization header for OAuth
|
129
|
+
def oauth_header(options = {})
|
130
|
+
header_params_str = oauth_parameters.map { |k,v| "#{k}=\"#{escape(v)}\"" }.join(', ')
|
131
|
+
|
132
|
+
realm = "realm=\"#{options[:realm]}\", " if options[:realm]
|
133
|
+
"OAuth #{realm}#{header_params_str}"
|
134
|
+
end
|
135
|
+
|
136
|
+
protected
|
137
|
+
|
83
138
|
def header_params
|
84
139
|
%w( X-HTTP_AUTHORIZATION Authorization HTTP_AUTHORIZATION ).each do |header|
|
85
140
|
next unless request.env.include?(header)
|
@@ -87,10 +142,10 @@ module OAuth::RequestProxy
|
|
87
142
|
header = request.env[header]
|
88
143
|
next unless header[0,6] == 'OAuth '
|
89
144
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
145
|
+
# parse the header into a Hash
|
146
|
+
oauth_params = OAuth::Helper.parse_header(header)
|
147
|
+
|
148
|
+
# remove non-OAuth parameters
|
94
149
|
oauth_params.reject! { |k,v| k !~ /^oauth_/ }
|
95
150
|
|
96
151
|
return oauth_params
|
@@ -98,10 +153,5 @@ module OAuth::RequestProxy
|
|
98
153
|
|
99
154
|
return {}
|
100
155
|
end
|
101
|
-
|
102
|
-
def unescape(value)
|
103
|
-
URI.unescape(value.gsub('+', '%2B'))
|
104
|
-
end
|
105
|
-
|
106
156
|
end
|
107
157
|
end
|
@@ -28,6 +28,14 @@ module OAuth
|
|
28
28
|
@request["method"]
|
29
29
|
end
|
30
30
|
|
31
|
+
def normalized_uri
|
32
|
+
super
|
33
|
+
rescue
|
34
|
+
# if this is a non-standard URI, it may not parse properly
|
35
|
+
# in that case, assume that it's already been normalized
|
36
|
+
uri
|
37
|
+
end
|
38
|
+
|
31
39
|
def uri
|
32
40
|
@request["uri"]
|
33
41
|
end
|
@@ -25,7 +25,7 @@ module OAuth::RequestProxy::Net
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
private
|
29
29
|
|
30
30
|
def all_parameters
|
31
31
|
request_params = CGI.parse(query_string)
|
@@ -47,7 +47,7 @@ module OAuth::RequestProxy::Net
|
|
47
47
|
params << post_params if method.to_s.upcase == 'POST' && is_form_urlencoded
|
48
48
|
params.compact.join('&')
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
def query_params
|
52
52
|
URI.parse(request.path).query
|
53
53
|
end
|
@@ -5,11 +5,11 @@ require 'rack'
|
|
5
5
|
module OAuth::RequestProxy
|
6
6
|
class RackRequest < OAuth::RequestProxy::Base
|
7
7
|
proxies Rack::Request
|
8
|
-
|
8
|
+
|
9
9
|
def method
|
10
|
-
request.request_method
|
10
|
+
request.env["rack.methodoverride.original_method"] || request.request_method
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def uri
|
14
14
|
request.url
|
15
15
|
end
|
@@ -22,12 +22,12 @@ module OAuth::RequestProxy
|
|
22
22
|
params.merge(options[:parameters] || {})
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def signature
|
27
27
|
parameters['oauth_signature']
|
28
28
|
end
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
protected
|
31
31
|
|
32
32
|
def query_params
|
33
33
|
request.GET
|
@@ -37,4 +37,4 @@ module OAuth::RequestProxy
|
|
37
37
|
request.params
|
38
38
|
end
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|