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.

Files changed (50) hide show
  1. data/History.txt +35 -17
  2. data/Manifest.txt +13 -1
  3. data/README.rdoc +5 -7
  4. data/Rakefile +6 -4
  5. data/TODO +18 -0
  6. data/bin/oauth +1 -1
  7. data/examples/yql.rb +44 -0
  8. data/lib/oauth.rb +1 -0
  9. data/lib/oauth/cli.rb +201 -31
  10. data/lib/oauth/client/action_controller_request.rb +13 -12
  11. data/lib/oauth/client/helper.rb +10 -14
  12. data/lib/oauth/client/net_http.rb +25 -22
  13. data/lib/oauth/consumer.rb +164 -110
  14. data/lib/oauth/errors.rb +3 -0
  15. data/lib/oauth/errors/error.rb +4 -0
  16. data/lib/oauth/errors/problem.rb +14 -0
  17. data/lib/oauth/errors/unauthorized.rb +12 -0
  18. data/lib/oauth/helper.rb +44 -6
  19. data/lib/oauth/oauth.rb +7 -0
  20. data/lib/oauth/oauth_test_helper.rb +12 -13
  21. data/lib/oauth/request_proxy/action_controller_request.rb +5 -6
  22. data/lib/oauth/request_proxy/base.rb +95 -45
  23. data/lib/oauth/request_proxy/jabber_request.rb +1 -2
  24. data/lib/oauth/request_proxy/mock_request.rb +8 -0
  25. data/lib/oauth/request_proxy/net_http.rb +2 -2
  26. data/lib/oauth/request_proxy/rack_request.rb +7 -7
  27. data/lib/oauth/server.rb +31 -33
  28. data/lib/oauth/signature/base.rb +23 -21
  29. data/lib/oauth/signature/hmac/base.rb +1 -1
  30. data/lib/oauth/signature/hmac/sha1.rb +0 -1
  31. data/lib/oauth/signature/plaintext.rb +2 -2
  32. data/lib/oauth/signature/rsa/sha1.rb +5 -4
  33. data/lib/oauth/token.rb +6 -136
  34. data/lib/oauth/tokens/access_token.rb +68 -0
  35. data/lib/oauth/tokens/consumer_token.rb +32 -0
  36. data/lib/oauth/tokens/request_token.rb +28 -0
  37. data/lib/oauth/tokens/server_token.rb +9 -0
  38. data/lib/oauth/tokens/token.rb +17 -0
  39. data/lib/oauth/version.rb +1 -1
  40. data/oauth.gemspec +12 -6
  41. data/test/cases/spec/1_0-final/test_construct_request_url.rb +1 -1
  42. data/test/test_access_token.rb +28 -0
  43. data/test/test_action_controller_request_proxy.rb +17 -0
  44. data/test/test_consumer.rb +3 -4
  45. data/test/test_helper.rb +0 -5
  46. data/test/test_request_token.rb +53 -0
  47. data/test/test_server.rb +1 -1
  48. data/website/index.html +2 -2
  49. metadata +37 -4
  50. data/specs.txt +0 -13
@@ -0,0 +1,3 @@
1
+ require 'oauth/errors/error'
2
+ require 'oauth/errors/unauthorized'
3
+ require 'oauth/errors/problem'
@@ -0,0 +1,4 @@
1
+ module OAuth
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ module OAuth
2
+ class Problem < OAuth::Unauthorized
3
+ attr_reader :problem, :params
4
+ def initialize(problem, request = nil, params = {})
5
+ super(request)
6
+ @problem = problem
7
+ @params = params
8
+ end
9
+
10
+ def to_s
11
+ problem
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module OAuth
2
+ class Unauthorized < OAuth::Error
3
+ attr_reader :request
4
+ def initialize(request = nil)
5
+ @request = request
6
+ end
7
+
8
+ def to_s
9
+ [request.code, request.message] * " "
10
+ end
11
+ end
12
+ end
@@ -1,17 +1,55 @@
1
1
  require 'openssl'
2
2
  require 'base64'
3
- require 'cgi'
3
+
4
4
  module OAuth
5
5
  module Helper
6
6
  extend self
7
7
 
8
8
  def escape(value)
9
- CGI.escape(value.to_s).gsub("%7E", '~').gsub("+", "%20")
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
@@ -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.env["SERVER_PORT"]=request.uri.port
10
- incoming.host=request.uri.host
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.env["HTTP_AUTHORIZATION"]=request.to_auth_string
18
- incoming.request_uri=request.path
19
- incoming.env["SERVER_PORT"]=request.uri.port
20
- incoming.host=request.uri.host
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 << CGI.unescape(request.raw_post)
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
- protected
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
- def token
20
- parameters['oauth_token']
21
- end
19
+ ## OAuth parameters
22
20
 
23
- def consumer_key
21
+ def oauth_consumer_key
24
22
  parameters['oauth_consumer_key']
25
23
  end
26
24
 
27
- def parameters_for_signature
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 timestamp
38
- parameters['oauth_timestamp']
29
+ def oauth_signature
30
+ # TODO can this be nil?
31
+ parameters['oauth_signature'] || ""
39
32
  end
40
33
 
41
- def signature_method
34
+ def oauth_signature_method
42
35
  case parameters['oauth_signature_method']
43
- when Array: parameters['oauth_signature_method'].first
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 signature
50
- parameters['oauth_signature'] || ""
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.sort.map do |k, values|
89
+ normalize(parameters_for_signature)
90
+ end
62
91
 
63
- if values.is_a?(Array)
64
- # multiple values were provided for a single key
65
- values.sort.collect do |v|
66
- [escape(k),escape(v)] * "="
67
- end
68
- else
69
- [escape(k),escape(values)] * "="
70
- end
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
- protected
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
- oauth_param_string = header[6,header.length].split(/[,=]/)
91
- oauth_param_string.map! { |v| unescape(v.strip) }
92
- oauth_param_string.map! { |v| v =~ /^\".*\"$/ ? v[1..-2] : v }
93
- oauth_params = Hash[*oauth_param_string.flatten]
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
@@ -32,11 +32,10 @@ module OAuth
32
32
  def uri
33
33
  [@request.from.strip.to_s, @request.to.strip.to_s].join("&")
34
34
  end
35
-
35
+
36
36
  def normalized_uri
37
37
  uri
38
38
  end
39
-
40
39
  end
41
40
  end
42
41
  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
- private
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
- protected
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