oauth 0.1.1 → 0.2.0
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 +9 -0
- data/License.txt +1 -1
- data/Manifest.txt +25 -7
- data/config/hoe.rb +1 -1
- data/lib/oauth.rb +1 -12
- data/lib/oauth/client.rb +4 -0
- data/lib/oauth/client/action_controller_request.rb +51 -0
- data/lib/oauth/client/helper.rb +74 -0
- data/lib/oauth/client/net_http.rb +72 -0
- data/lib/oauth/consumer.rb +112 -43
- data/lib/oauth/{key.rb → helper.rb} +6 -7
- data/lib/oauth/request_proxy.rb +24 -0
- data/lib/oauth/request_proxy/action_controller_request.rb +65 -0
- data/lib/oauth/request_proxy/base.rb +50 -0
- data/lib/oauth/request_proxy/net_http.rb +64 -0
- data/lib/oauth/server.rb +12 -9
- data/lib/oauth/signature.rb +15 -142
- data/lib/oauth/signature/base.rb +69 -0
- data/lib/oauth/signature/hmac/base.rb +12 -0
- data/lib/oauth/signature/hmac/md5.rb +9 -0
- data/lib/oauth/signature/hmac/rmd160.rb +9 -0
- data/lib/oauth/signature/hmac/sha1.rb +10 -0
- data/lib/oauth/signature/hmac/sha2.rb +9 -0
- data/lib/oauth/signature/md5.rb +13 -0
- data/lib/oauth/signature/plaintext.rb +19 -0
- data/lib/oauth/signature/rsa/sha1.rb +20 -0
- data/lib/oauth/signature/sha1.rb +13 -0
- data/lib/oauth/token.rb +54 -14
- data/lib/oauth/version.rb +2 -2
- data/test/test_action_controller_request_proxy.rb +10 -0
- data/test/test_consumer.rb +144 -57
- data/test/test_helper.rb +4 -0
- data/test/test_hmac_sha1.rb +21 -0
- data/test/test_net_http_client.rb +139 -0
- data/test/test_net_http_request_proxy.rb +38 -0
- data/test/test_server.rb +1 -8
- data/test/test_signature.rb +11 -113
- data/test/test_signature_base.rb +32 -0
- data/test/test_token.rb +14 -0
- data/website/index.html +9 -8
- data/website/index.txt +5 -6
- metadata +37 -13
- data/lib/oauth/consumer_credentials.rb +0 -12
- data/lib/oauth/oauth_test_helper.rb +0 -24
- data/lib/oauth/request.rb +0 -258
- data/test/test_oauth.rb +0 -11
- data/test/test_request.rb +0 -282
@@ -1,15 +1,14 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
require 'base64'
|
3
3
|
module OAuth
|
4
|
-
module
|
5
|
-
def generate_key(size=32)
|
6
|
-
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/,'')
|
7
|
-
end
|
8
|
-
|
9
|
-
# Based on Blaine's example from the Oauth mailing list
|
4
|
+
module Helper
|
10
5
|
def escape(value)
|
11
|
-
CGI.escape(value.to_s).gsub("%7E",
|
6
|
+
CGI.escape(value.to_s).gsub("%7E", '~').gsub("+", "%20")
|
12
7
|
end
|
13
8
|
|
9
|
+
def generate_key(size=32)
|
10
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/,'')
|
11
|
+
end
|
12
|
+
|
14
13
|
end
|
15
14
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OAuth
|
2
|
+
module RequestProxy
|
3
|
+
def self.available_proxies #:nodoc:
|
4
|
+
@available_proxies ||= {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.proxy(request, options = {})
|
8
|
+
return request if request.kind_of?(OAuth::RequestProxy::Base)
|
9
|
+
|
10
|
+
klass = available_proxies[request.class]
|
11
|
+
|
12
|
+
# Search for possible superclass matches.
|
13
|
+
if klass.nil?
|
14
|
+
request_parent = available_proxies.keys.find { |rc| request.kind_of?(rc) }
|
15
|
+
klass = available_proxies[request_parent]
|
16
|
+
end
|
17
|
+
|
18
|
+
raise UnknownRequestType, request.class.to_s unless klass
|
19
|
+
klass.new(request, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
class UnknownRequestType < Exception; end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'action_controller/request'
|
4
|
+
require 'oauth/request_proxy/base'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module OAuth::RequestProxy
|
8
|
+
class ActionControllerRequest < OAuth::RequestProxy::Base
|
9
|
+
proxies ActionController::AbstractRequest
|
10
|
+
|
11
|
+
def method
|
12
|
+
request.method.to_s.upcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def uri
|
16
|
+
uri = URI.parse(request.protocol + request.host + request.port_string + request.path)
|
17
|
+
uri.query = nil
|
18
|
+
uri.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def parameters
|
22
|
+
if options[:clobber_request]
|
23
|
+
options[:parameters] || {}
|
24
|
+
else
|
25
|
+
params = request_params.merge(query_params).merge(header_params)
|
26
|
+
params.stringify_keys! if params.respond_to?(:stringify_keys!)
|
27
|
+
params.merge(options[:parameters] || {})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def header_params
|
34
|
+
%w( X-HTTP_AUTHORIZATION Authorization HTTP_AUTHORIZATION ).each do |header|
|
35
|
+
next unless request.env.include?(header)
|
36
|
+
|
37
|
+
header = request.env[header]
|
38
|
+
next unless header[0,6] == 'OAuth '
|
39
|
+
|
40
|
+
oauth_param_string = header[6,header.length].split(/[,=]/)
|
41
|
+
oauth_param_string.map! { |v| unescape(v.strip) }
|
42
|
+
oauth_param_string.map! { |v| v =~ /^\".*\"$/ ? v[1..-2] : v }
|
43
|
+
oauth_params = Hash[*oauth_param_string.flatten]
|
44
|
+
oauth_params.reject! { |k,v| k !~ /^oauth_/ }
|
45
|
+
|
46
|
+
return oauth_params
|
47
|
+
end
|
48
|
+
|
49
|
+
return {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def query_params
|
53
|
+
request.query_parameters
|
54
|
+
end
|
55
|
+
|
56
|
+
def request_params
|
57
|
+
request.request_parameters
|
58
|
+
end
|
59
|
+
|
60
|
+
def unescape(value)
|
61
|
+
URI.unescape(value.gsub('+', '%2B'))
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'oauth/request_proxy'
|
2
|
+
|
3
|
+
module OAuth::RequestProxy
|
4
|
+
class Base
|
5
|
+
def self.proxies(klass)
|
6
|
+
OAuth::RequestProxy.available_proxies[klass] = self
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :request, :options
|
10
|
+
|
11
|
+
def initialize(request, options = {})
|
12
|
+
@request = request
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def token
|
17
|
+
parameters['oauth_token']
|
18
|
+
end
|
19
|
+
|
20
|
+
def consumer_key
|
21
|
+
parameters['oauth_consumer_key']
|
22
|
+
end
|
23
|
+
|
24
|
+
def parameters_for_signature
|
25
|
+
p = parameters.dup
|
26
|
+
p.delete("oauth_signature")
|
27
|
+
p
|
28
|
+
end
|
29
|
+
|
30
|
+
def nonce
|
31
|
+
parameters['oauth_nonce']
|
32
|
+
end
|
33
|
+
|
34
|
+
def timestamp
|
35
|
+
parameters['oauth_timestamp']
|
36
|
+
end
|
37
|
+
|
38
|
+
def signature_method
|
39
|
+
case parameters['oauth_signature_method']
|
40
|
+
when Array: parameters['oauth_signature_method'].first
|
41
|
+
else
|
42
|
+
parameters['oauth_signature_method']
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def signature
|
47
|
+
parameters['oauth_signature'] || ""
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'oauth/request_proxy/base'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
module OAuth::RequestProxy::Net
|
7
|
+
module HTTP
|
8
|
+
class HTTPRequest < OAuth::RequestProxy::Base
|
9
|
+
proxies ::Net::HTTPRequest
|
10
|
+
|
11
|
+
def method
|
12
|
+
request.method
|
13
|
+
end
|
14
|
+
|
15
|
+
def uri
|
16
|
+
uri = options[:uri]
|
17
|
+
uri = URI.parse(uri) unless uri.kind_of?(URI)
|
18
|
+
uri.query = nil
|
19
|
+
uri.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def parameters
|
23
|
+
if options[:clobber_request]
|
24
|
+
options[:parameters]
|
25
|
+
else
|
26
|
+
all_parameters
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def all_parameters
|
33
|
+
request_params = CGI.parse(query_string)
|
34
|
+
if options[:parameters]
|
35
|
+
options[:parameters].each do |k,v|
|
36
|
+
if request_params.has_key?(k)
|
37
|
+
request_params[k] << v
|
38
|
+
else
|
39
|
+
request_params[k] = [v].flatten
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
request_params
|
44
|
+
end
|
45
|
+
|
46
|
+
def query_string
|
47
|
+
[ query_params, post_params, auth_header_params ].compact.join('&')
|
48
|
+
end
|
49
|
+
|
50
|
+
def query_params
|
51
|
+
URI.parse(request.path).query
|
52
|
+
end
|
53
|
+
|
54
|
+
def post_params
|
55
|
+
request.body
|
56
|
+
end
|
57
|
+
|
58
|
+
def auth_header_params
|
59
|
+
return nil unless request['Authorization'] && request['Authorization'][0,5] == 'OAuth'
|
60
|
+
auth_params = request['Authorization']
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/oauth/server.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'oauth/helper'
|
2
|
+
require 'oauth/consumer'
|
1
3
|
module OAuth
|
2
4
|
# This is mainly used to create consumer credentials and can pretty much be ignored if you want to create your own
|
3
5
|
class Server
|
4
|
-
include OAuth::
|
6
|
+
include OAuth::Helper
|
5
7
|
attr_accessor :base_url
|
6
8
|
|
7
9
|
@@server_paths={
|
@@ -20,19 +22,20 @@ module OAuth
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def generate_consumer_credentials(params={})
|
23
|
-
|
25
|
+
Consumer.new( *generate_credentials)
|
24
26
|
end
|
25
27
|
|
26
28
|
# mainly for testing purposes
|
27
29
|
def create_consumer
|
28
30
|
credentials=generate_credentials
|
29
|
-
Consumer.new(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
Consumer.new(
|
32
|
+
credentials[0],
|
33
|
+
credentials[1],
|
34
|
+
{
|
35
|
+
:site=>base_url,
|
36
|
+
:request_token_path=>request_token_path,
|
37
|
+
:authorize_path=>authorize_path,
|
38
|
+
:access_token_path=>access_token_path
|
36
39
|
})
|
37
40
|
end
|
38
41
|
|
data/lib/oauth/signature.rb
CHANGED
@@ -1,155 +1,28 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
require 'hmac' # make sure to install: sudo gem install ruby-hmac
|
3
|
-
require 'hmac-sha1'
|
4
|
-
require 'hmac-md5'
|
5
|
-
require 'hmac-sha2'
|
6
|
-
require 'hmac-rmd160'
|
7
|
-
|
8
|
-
require 'base64'
|
9
1
|
module OAuth
|
10
|
-
# Much of this code has been blatantly stolen fron Blaine Cooke of Twitter and Larry Halff of ma.gnolia.com
|
11
|
-
# and lovingly hand modified with the utmost respect.
|
12
|
-
|
13
|
-
# You should not need to use this directly as the request object encapsulates it in the sign and verify methods
|
14
2
|
module Signature
|
15
|
-
def self.
|
16
|
-
|
17
|
-
when 'hmac-md5': OAuth::Signature::HashedMessageAuth::MD5
|
18
|
-
when 'hmac-sha1': OAuth::Signature::HashedMessageAuth::SHA1
|
19
|
-
when 'hmac-sha2': OAuth::Signature::HashedMessageAuth::SHA2
|
20
|
-
when 'hmac-rmd160': OAuth::Signature::HashedMessageAuth::RMD160
|
21
|
-
when 'plaintext':
|
22
|
-
if oauth_request.uri.scheme=="https"
|
23
|
-
OAuth::Signature::PLAINTEXT
|
24
|
-
else
|
25
|
-
raise InsecureSignatureMethod
|
26
|
-
end
|
27
|
-
when 'rsa-sha1': OAuth::Signature::RSA::SHA1
|
28
|
-
when 'sha1': raise InsecureSignatureMethod, oauth_request.signature_method
|
29
|
-
when 'md5': raise InsecureSignatureMethod, oauth_request.signature_method
|
30
|
-
else
|
31
|
-
raise UnknownSignatureMethod, oauth_request.signature_method
|
32
|
-
end
|
33
|
-
|
34
|
-
klass.new(oauth_request,consumer_secret,token_secret)
|
3
|
+
def self.available_methods
|
4
|
+
@available_methods ||= {}
|
35
5
|
end
|
36
6
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
include OAuth::Key
|
43
|
-
|
44
|
-
attr_accessor :request
|
45
|
-
|
46
|
-
def initialize(request,consumer_secret,token_secret=nil)
|
47
|
-
@request=request
|
48
|
-
@consumer_secret=consumer_secret
|
49
|
-
@token_secret=token_secret
|
50
|
-
end
|
51
|
-
|
52
|
-
def base_string
|
53
|
-
[@request.http_method,@request.normalized_url,@request.to_query_without_signature].collect{|p| @request.escape(p)}.join('&')
|
54
|
-
end
|
55
|
-
|
56
|
-
def key
|
57
|
-
"#{@consumer_secret}&#{@token_secret}"
|
58
|
-
end
|
59
|
-
|
60
|
-
def consumer_secret
|
61
|
-
@consumer_secret||=""
|
62
|
-
end
|
63
|
-
|
64
|
-
def token_secret
|
65
|
-
@token_secret||=""
|
66
|
-
end
|
67
|
-
|
68
|
-
def sign
|
69
|
-
Base64.encode64(digest).chomp
|
70
|
-
end
|
71
|
-
|
72
|
-
def sign!
|
73
|
-
@request.signature=sign
|
74
|
-
end
|
75
|
-
|
76
|
-
def verify?
|
77
|
-
return false unless @request.signed?
|
78
|
-
@request.signature==sign
|
79
|
-
end
|
80
|
-
|
81
|
-
protected
|
82
|
-
|
83
|
-
def digest
|
84
|
-
digest_class.digest(base_string)
|
85
|
-
end
|
7
|
+
def self.build(request, options = {}, &block)
|
8
|
+
request = OAuth::RequestProxy.proxy(request, options)
|
9
|
+
klass = available_methods[(request.signature_method || "").downcase]
|
10
|
+
raise UnknownSignatureMethod, request.signature_method unless klass
|
11
|
+
klass.new(request, options, &block)
|
86
12
|
end
|
87
|
-
|
88
|
-
class PLAINTEXT < Base
|
89
|
-
|
90
|
-
def sign
|
91
|
-
base_string
|
92
|
-
end
|
93
|
-
|
94
|
-
def base_string
|
95
|
-
"#{escape(consumer_secret)}&#{escape(token_secret)}"
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
13
|
|
100
|
-
|
14
|
+
def self.sign(request, options = {}, &block)
|
15
|
+
self.build(request, options, &block).signature
|
101
16
|
end
|
102
|
-
|
103
|
-
module HashedMessageAuth
|
104
|
-
class Base < OAuth::Signature::Base
|
105
17
|
|
106
|
-
|
107
|
-
|
108
|
-
def digest
|
109
|
-
hmac_class.digest(secret, base_string)
|
110
|
-
end
|
111
|
-
|
112
|
-
def secret
|
113
|
-
"#{escape(consumer_secret)}&#{escape(token_secret)}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
class MD5 < Base
|
118
|
-
private
|
119
|
-
def hmac_class; HMAC::MD5; end
|
120
|
-
end
|
121
|
-
|
122
|
-
class RMD160 < Base
|
123
|
-
private
|
124
|
-
def hmac_class; HMAC::RMD160; end
|
125
|
-
end
|
126
|
-
|
127
|
-
class SHA1 < Base
|
128
|
-
private
|
129
|
-
def hmac_class; HMAC::SHA1; end
|
130
|
-
end
|
131
|
-
|
132
|
-
class SHA2 < Base
|
133
|
-
private
|
134
|
-
def hmac_class; HMAC::SHA1; end
|
135
|
-
end
|
18
|
+
def self.verify(request, options = {}, &block)
|
19
|
+
self.build(request, options, &block).verify
|
136
20
|
end
|
137
21
|
|
138
|
-
|
139
|
-
|
140
|
-
def ==(cmp_signature)
|
141
|
-
public_key = OpenSSL::PKey::RSA.new(consumer_secret)
|
142
|
-
public_key.verify(OpenSSL::Digest::SHA1.new, cmp_signature, base_string)
|
143
|
-
end
|
144
|
-
|
145
|
-
private
|
146
|
-
|
147
|
-
def digest
|
148
|
-
private_key = OpenSSL::PKey::RSA.new(consumer_secret)
|
149
|
-
private_key.sign(OpenSSL::Digest::SHA1.new, base_string)
|
150
|
-
end
|
151
|
-
end
|
22
|
+
def self.signature_base_string(request, options = {}, &block)
|
23
|
+
self.build(request, options, &block).signature_base_string
|
152
24
|
end
|
153
|
-
|
25
|
+
|
26
|
+
class UnknownSignatureMethod < Exception; end
|
154
27
|
end
|
155
28
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'oauth/signature'
|
2
|
+
require 'oauth/helper'
|
3
|
+
require 'oauth/request_proxy/base'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
module OAuth::Signature
|
7
|
+
class Base
|
8
|
+
include OAuth::Helper
|
9
|
+
|
10
|
+
def self.implements(signature_method)
|
11
|
+
OAuth::Signature.available_methods[signature_method] = self
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.digest_class(digest_class = nil)
|
15
|
+
return @digest_class if digest_class.nil?
|
16
|
+
@digest_class = digest_class
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :token_secret, :consumer_secret, :request
|
20
|
+
|
21
|
+
def initialize(request, options = {}, &block)
|
22
|
+
raise TypeError unless request.kind_of?(OAuth::RequestProxy::Base)
|
23
|
+
@request = request
|
24
|
+
if block_given?
|
25
|
+
@token_secret, @consumer_secret = yield block.arity == 1 ? token : [token, consumer_key]
|
26
|
+
else
|
27
|
+
@consumer_secret = options[:consumer].secret
|
28
|
+
@token_secret = options[:token] ? options[:token].secret : ''
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def signature
|
33
|
+
Base64.encode64(digest).chomp
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(cmp_signature)
|
37
|
+
Base64.decode64(signature) == Base64.decode64(cmp_signature)
|
38
|
+
end
|
39
|
+
|
40
|
+
def verify
|
41
|
+
self == self.request.signature
|
42
|
+
end
|
43
|
+
|
44
|
+
def signature_base_string
|
45
|
+
normalized_params = request.parameters_for_signature.sort.map { |k,v| [escape(k), escape(v)] * "=" }.join("&")
|
46
|
+
base = [request.method, request.uri, normalized_params]
|
47
|
+
sbs = base.map { |v| escape(v) }.join("&")
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def token
|
53
|
+
request.token
|
54
|
+
end
|
55
|
+
|
56
|
+
def consumer_key
|
57
|
+
request.consumer_key
|
58
|
+
end
|
59
|
+
|
60
|
+
def secret
|
61
|
+
"#{escape(consumer_secret)}&#{escape(token_secret)}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def digest
|
65
|
+
self.class.digest_class.digest(signature_base_string)
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|