gregwebs-oauth 0.3.6.1
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/History.txt +102 -0
- data/License.txt +20 -0
- data/Manifest.txt +84 -0
- data/README.rdoc +71 -0
- data/Rakefile +36 -0
- data/TODO +31 -0
- data/bin/oauth +5 -0
- data/examples/yql.rb +44 -0
- data/lib/oauth.rb +4 -0
- data/lib/oauth/cli.rb +378 -0
- data/lib/oauth/client.rb +4 -0
- data/lib/oauth/client/action_controller_request.rb +54 -0
- data/lib/oauth/client/helper.rb +85 -0
- data/lib/oauth/client/net_http.rb +103 -0
- data/lib/oauth/consumer.rb +354 -0
- 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 +78 -0
- data/lib/oauth/oauth.rb +11 -0
- data/lib/oauth/oauth_test_helper.rb +25 -0
- data/lib/oauth/request_proxy.rb +24 -0
- data/lib/oauth/request_proxy/action_controller_request.rb +61 -0
- data/lib/oauth/request_proxy/base.rb +166 -0
- data/lib/oauth/request_proxy/jabber_request.rb +41 -0
- data/lib/oauth/request_proxy/mock_request.rb +44 -0
- data/lib/oauth/request_proxy/net_http.rb +68 -0
- data/lib/oauth/request_proxy/rack_request.rb +40 -0
- data/lib/oauth/server.rb +66 -0
- data/lib/oauth/signature.rb +40 -0
- data/lib/oauth/signature/base.rb +91 -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 +9 -0
- data/lib/oauth/signature/hmac/sha2.rb +9 -0
- data/lib/oauth/signature/md5.rb +13 -0
- data/lib/oauth/signature/plaintext.rb +23 -0
- data/lib/oauth/signature/rsa/sha1.rb +45 -0
- data/lib/oauth/signature/sha1.rb +13 -0
- data/lib/oauth/token.rb +7 -0
- data/lib/oauth/tokens/access_token.rb +68 -0
- data/lib/oauth/tokens/consumer_token.rb +33 -0
- data/lib/oauth/tokens/request_token.rb +32 -0
- data/lib/oauth/tokens/server_token.rb +9 -0
- data/lib/oauth/tokens/token.rb +17 -0
- data/lib/oauth/version.rb +3 -0
- data/oauth.gemspec +49 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/cases/oauth_case.rb +19 -0
- data/test/cases/spec/1_0-final/test_construct_request_url.rb +62 -0
- data/test/cases/spec/1_0-final/test_normalize_request_parameters.rb +88 -0
- data/test/cases/spec/1_0-final/test_parameter_encodings.rb +86 -0
- data/test/cases/spec/1_0-final/test_signature_base_strings.rb +77 -0
- data/test/keys/rsa.cert +11 -0
- data/test/keys/rsa.pem +16 -0
- data/test/test_access_token.rb +26 -0
- data/test/test_action_controller_request_proxy.rb +129 -0
- data/test/test_consumer.rb +362 -0
- data/test/test_helper.rb +14 -0
- data/test/test_hmac_sha1.rb +20 -0
- data/test/test_net_http_client.rb +185 -0
- data/test/test_net_http_request_proxy.rb +72 -0
- data/test/test_oauth_helper.rb +49 -0
- data/test/test_rack_request_proxy.rb +40 -0
- data/test/test_request_token.rb +51 -0
- data/test/test_rsa_sha1.rb +59 -0
- data/test/test_server.rb +40 -0
- data/test/test_signature.rb +19 -0
- data/test/test_signature_base.rb +32 -0
- data/test/test_signature_plain_text.rb +31 -0
- data/test/test_token.rb +14 -0
- data/website/index.html +87 -0
- data/website/index.txt +73 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +217 -0
data/lib/oauth/errors.rb
ADDED
data/lib/oauth/helper.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module OAuth
|
5
|
+
module Helper
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# Escape +value+ by URL encoding all non-reserved character.
|
9
|
+
#
|
10
|
+
# See Also: {OAuth core spec version 1.0, section 5.1}[http://oauth.net/core/1.0#rfc.section.5.1]
|
11
|
+
def escape(value)
|
12
|
+
URI::escape(value.to_s, OAuth::RESERVED_CHARACTERS)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Generate a random key of up to +size+ bytes. The value returned is Base64 encoded with non-word
|
16
|
+
# characters removed.
|
17
|
+
def generate_key(size=32)
|
18
|
+
Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :generate_nonce, :generate_key
|
22
|
+
|
23
|
+
def generate_timestamp #:nodoc:
|
24
|
+
Time.now.to_i.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
# Normalize a +Hash+ of parameter values. Parameters are sorted by name, using lexicographical
|
28
|
+
# byte value ordering. If two or more parameters share the same name, they are sorted by their value.
|
29
|
+
# Parameters are concatenated in their sorted order into a single string. For each parameter, the name
|
30
|
+
# is separated from the corresponding value by an "=" character, even if the value is empty. Each
|
31
|
+
# name-value pair is separated by an "&" character.
|
32
|
+
#
|
33
|
+
# See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
|
34
|
+
def normalize(params)
|
35
|
+
params.sort.map do |k, values|
|
36
|
+
|
37
|
+
if values.is_a?(Array)
|
38
|
+
# multiple values were provided for a single key
|
39
|
+
values.sort.collect do |v|
|
40
|
+
[escape(k),escape(v)] * "="
|
41
|
+
end
|
42
|
+
else
|
43
|
+
[escape(k),escape(values)] * "="
|
44
|
+
end
|
45
|
+
end * "&"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Parse an Authorization / WWW-Authenticate header into a hash. Takes care of unescaping and
|
49
|
+
# removing surrounding quotes. Raises a OAuth::Problem if the header is not parsable into a
|
50
|
+
# valid hash. Does not validate the keys or values.
|
51
|
+
#
|
52
|
+
# hash = parse_header(headers['Authorization'] || headers['WWW-Authenticate'])
|
53
|
+
# hash['oauth_timestamp']
|
54
|
+
# #=>"1234567890"
|
55
|
+
#
|
56
|
+
def parse_header(header)
|
57
|
+
# decompose
|
58
|
+
params = header[6,header.length].split(/[,=]/)
|
59
|
+
|
60
|
+
# odd number of arguments - must be a malformed header.
|
61
|
+
raise OAuth::Problem.new("Invalid authorization header") if params.size % 2 != 0
|
62
|
+
|
63
|
+
params.map! do |v|
|
64
|
+
# strip and unescape
|
65
|
+
val = unescape(v.strip)
|
66
|
+
# strip quotes
|
67
|
+
val.sub(/^\"(.*)\"$/, '\1')
|
68
|
+
end
|
69
|
+
|
70
|
+
# convert into a Hash
|
71
|
+
Hash[*params.flatten]
|
72
|
+
end
|
73
|
+
|
74
|
+
def unescape(value)
|
75
|
+
URI.unescape(value.gsub('+', '%2B'))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/oauth/oauth.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module OAuth
|
2
|
+
# request tokens are passed between the consumer and the provider out of
|
3
|
+
# band (i.e. callbacks cannot be used), per section 6.1.1
|
4
|
+
OUT_OF_BAND = "oob"
|
5
|
+
|
6
|
+
# required parameters, per sections 6.1.1, 6.3.1, and 7
|
7
|
+
PARAMETERS = %w(oauth_callback oauth_consumer_key oauth_token oauth_signature_method oauth_timestamp oauth_nonce oauth_verifier oauth_version oauth_signature)
|
8
|
+
|
9
|
+
# reserved character regexp, per section 5.1
|
10
|
+
RESERVED_CHARACTERS = /[^a-zA-Z0-9\-\.\_\~]/
|
11
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'action_controller/test_process'
|
3
|
+
|
4
|
+
module OAuth
|
5
|
+
module OAuthTestHelper
|
6
|
+
def mock_incoming_request_with_query(request)
|
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
|
+
incoming
|
13
|
+
end
|
14
|
+
|
15
|
+
def mock_incoming_request_with_authorize_header(request)
|
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
|
+
incoming
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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,61 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'action_controller'
|
3
|
+
require 'action_controller/request'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module OAuth::RequestProxy
|
7
|
+
class ActionControllerRequest < OAuth::RequestProxy::Base
|
8
|
+
proxies(defined?(ActionController::AbstractRequest) ? ActionController::AbstractRequest : ActionController::Request)
|
9
|
+
|
10
|
+
def method
|
11
|
+
request.method.to_s.upcase
|
12
|
+
end
|
13
|
+
|
14
|
+
def uri
|
15
|
+
request.url
|
16
|
+
end
|
17
|
+
|
18
|
+
def parameters
|
19
|
+
if options[:clobber_request]
|
20
|
+
options[:parameters] || {}
|
21
|
+
else
|
22
|
+
params = request_params.merge(query_params).merge(header_params)
|
23
|
+
params.stringify_keys! if params.respond_to?(:stringify_keys!)
|
24
|
+
params.merge(options[:parameters] || {})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Override from OAuth::RequestProxy::Base to avoid roundtrip
|
29
|
+
# conversion to Hash or Array and thus preserve the original
|
30
|
+
# parameter names
|
31
|
+
def parameters_for_signature
|
32
|
+
params = []
|
33
|
+
params << options[:parameters].to_query if options[:parameters]
|
34
|
+
|
35
|
+
unless options[:clobber_request]
|
36
|
+
params << header_params.to_query
|
37
|
+
params << request.query_string unless request.query_string.blank?
|
38
|
+
if request.post? && request.content_type == Mime::Type.lookup("application/x-www-form-urlencoded")
|
39
|
+
params << request.raw_post
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
params.
|
44
|
+
join('&').split('&').
|
45
|
+
reject(&:blank?).
|
46
|
+
map { |p| p.split('=').map{|esc| CGI.unescape(esc)} }.
|
47
|
+
reject { |kv| kv[0] == 'oauth_signature'}
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def query_params
|
53
|
+
request.query_parameters
|
54
|
+
end
|
55
|
+
|
56
|
+
def request_params
|
57
|
+
request.request_parameters
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'oauth/request_proxy'
|
2
|
+
require 'oauth/helper'
|
3
|
+
|
4
|
+
module OAuth::RequestProxy
|
5
|
+
class Base
|
6
|
+
include OAuth::Helper
|
7
|
+
|
8
|
+
def self.proxies(klass)
|
9
|
+
OAuth::RequestProxy.available_proxies[klass] = self
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :request, :options, :unsigned_parameters
|
13
|
+
|
14
|
+
def initialize(request, options = {})
|
15
|
+
@request = request
|
16
|
+
@unsigned_parameters = (options[:unsigned_parameters] || []).map {|param| param.to_s}
|
17
|
+
@options = options
|
18
|
+
end
|
19
|
+
|
20
|
+
## OAuth parameters
|
21
|
+
|
22
|
+
def oauth_callback
|
23
|
+
parameters['oauth_callback']
|
24
|
+
end
|
25
|
+
|
26
|
+
def oauth_consumer_key
|
27
|
+
parameters['oauth_consumer_key']
|
28
|
+
end
|
29
|
+
|
30
|
+
def oauth_nonce
|
31
|
+
parameters['oauth_nonce']
|
32
|
+
end
|
33
|
+
|
34
|
+
def oauth_signature
|
35
|
+
# TODO can this be nil?
|
36
|
+
parameters['oauth_signature'] || ""
|
37
|
+
end
|
38
|
+
|
39
|
+
def oauth_signature_method
|
40
|
+
case parameters['oauth_signature_method']
|
41
|
+
when Array
|
42
|
+
parameters['oauth_signature_method'].first
|
43
|
+
else
|
44
|
+
parameters['oauth_signature_method']
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def oauth_timestamp
|
49
|
+
parameters['oauth_timestamp']
|
50
|
+
end
|
51
|
+
|
52
|
+
def oauth_token
|
53
|
+
parameters['oauth_token']
|
54
|
+
end
|
55
|
+
|
56
|
+
def oauth_verifier
|
57
|
+
parameters['oauth_verifier']
|
58
|
+
end
|
59
|
+
|
60
|
+
def oauth_version
|
61
|
+
parameters["oauth_version"]
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO deprecate these
|
65
|
+
alias_method :consumer_key, :oauth_consumer_key
|
66
|
+
alias_method :token, :oauth_token
|
67
|
+
alias_method :nonce, :oauth_nonce
|
68
|
+
alias_method :timestamp, :oauth_timestamp
|
69
|
+
alias_method :signature, :oauth_signature
|
70
|
+
alias_method :signature_method, :oauth_signature_method
|
71
|
+
|
72
|
+
## Parameter accessors
|
73
|
+
|
74
|
+
def parameters
|
75
|
+
raise NotImplementedError, "Must be implemented by subclasses"
|
76
|
+
end
|
77
|
+
|
78
|
+
def parameters_for_signature
|
79
|
+
parameters.reject { |k,v| k == "oauth_signature" || unsigned_parameters.include?(k)}
|
80
|
+
end
|
81
|
+
|
82
|
+
def oauth_parameters
|
83
|
+
parameters.select { |k,v| OAuth::PARAMETERS.include?(k) }.reject { |k,v| v == "" }
|
84
|
+
end
|
85
|
+
|
86
|
+
def non_oauth_parameters
|
87
|
+
parameters.reject { |k,v| OAuth::PARAMETERS.include?(k) }
|
88
|
+
end
|
89
|
+
|
90
|
+
# See 9.1.2 in specs
|
91
|
+
def normalized_uri
|
92
|
+
u = URI.parse(uri)
|
93
|
+
"#{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 : '/'}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# See 9.1.1. in specs Normalize Request Parameters
|
97
|
+
def normalized_parameters
|
98
|
+
normalize(parameters_for_signature)
|
99
|
+
end
|
100
|
+
|
101
|
+
def sign(options = {})
|
102
|
+
OAuth::Signature.sign(self, options)
|
103
|
+
end
|
104
|
+
|
105
|
+
def sign!(options = {})
|
106
|
+
parameters["oauth_signature"] = sign(options)
|
107
|
+
@signed = true
|
108
|
+
signature
|
109
|
+
end
|
110
|
+
|
111
|
+
# See 9.1 in specs
|
112
|
+
def signature_base_string
|
113
|
+
base = [method, normalized_uri, normalized_parameters]
|
114
|
+
base.map { |v| escape(v) }.join("&")
|
115
|
+
end
|
116
|
+
|
117
|
+
# Has this request been signed yet?
|
118
|
+
def signed?
|
119
|
+
@signed
|
120
|
+
end
|
121
|
+
|
122
|
+
# URI, including OAuth parameters
|
123
|
+
def signed_uri(with_oauth = true)
|
124
|
+
if signed?
|
125
|
+
if with_oauth
|
126
|
+
params = parameters
|
127
|
+
else
|
128
|
+
params = non_oauth_parameters
|
129
|
+
end
|
130
|
+
|
131
|
+
[uri, normalize(params)] * "?"
|
132
|
+
else
|
133
|
+
STDERR.puts "This request has not yet been signed!"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Authorization header for OAuth
|
138
|
+
def oauth_header(options = {})
|
139
|
+
header_params_str = oauth_parameters.map { |k,v| "#{k}=\"#{escape(v)}\"" }.join(', ')
|
140
|
+
|
141
|
+
realm = "realm=\"#{options[:realm]}\", " if options[:realm]
|
142
|
+
"OAuth #{realm}#{header_params_str}"
|
143
|
+
end
|
144
|
+
|
145
|
+
protected
|
146
|
+
|
147
|
+
def header_params
|
148
|
+
%w( X-HTTP_AUTHORIZATION Authorization HTTP_AUTHORIZATION ).each do |header|
|
149
|
+
next unless request.env.include?(header)
|
150
|
+
|
151
|
+
header = request.env[header]
|
152
|
+
next unless header[0,6] == 'OAuth '
|
153
|
+
|
154
|
+
# parse the header into a Hash
|
155
|
+
oauth_params = OAuth::Helper.parse_header(header)
|
156
|
+
|
157
|
+
# remove non-OAuth parameters
|
158
|
+
oauth_params.reject! { |k,v| k !~ /^oauth_/ }
|
159
|
+
|
160
|
+
return oauth_params
|
161
|
+
end
|
162
|
+
|
163
|
+
return {}
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'xmpp4r'
|
2
|
+
require 'oauth/request_proxy/base'
|
3
|
+
|
4
|
+
module OAuth
|
5
|
+
module RequestProxy
|
6
|
+
class JabberRequest < OAuth::RequestProxy::Base
|
7
|
+
proxies Jabber::Iq
|
8
|
+
proxies Jabber::Presence
|
9
|
+
proxies Jabber::Message
|
10
|
+
|
11
|
+
def parameters
|
12
|
+
return @params if @params
|
13
|
+
|
14
|
+
@params = {}
|
15
|
+
|
16
|
+
oauth = @request.get_elements('//oauth').first
|
17
|
+
return @params unless oauth
|
18
|
+
|
19
|
+
%w( oauth_token oauth_consumer_key oauth_signature_method oauth_signature
|
20
|
+
oauth_timestamp oauth_nonce oauth_version ).each do |param|
|
21
|
+
next unless element = oauth.first_element(param)
|
22
|
+
@params[param] = element.text
|
23
|
+
end
|
24
|
+
|
25
|
+
@params
|
26
|
+
end
|
27
|
+
|
28
|
+
def method
|
29
|
+
@request.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def uri
|
33
|
+
[@request.from.strip.to_s, @request.to.strip.to_s].join("&")
|
34
|
+
end
|
35
|
+
|
36
|
+
def normalized_uri
|
37
|
+
uri
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|