af-oauth 0.3.4.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.
Files changed (85) hide show
  1. data/History.txt +83 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +84 -0
  4. data/README.rdoc +71 -0
  5. data/Rakefile +36 -0
  6. data/TODO +31 -0
  7. data/bin/oauth +5 -0
  8. data/examples/yql.rb +44 -0
  9. data/lib/oauth.rb +4 -0
  10. data/lib/oauth/cli.rb +300 -0
  11. data/lib/oauth/client.rb +4 -0
  12. data/lib/oauth/client/action_controller_request.rb +54 -0
  13. data/lib/oauth/client/helper.rb +81 -0
  14. data/lib/oauth/client/net_http.rb +94 -0
  15. data/lib/oauth/consumer.rb +297 -0
  16. data/lib/oauth/errors.rb +3 -0
  17. data/lib/oauth/errors/error.rb +4 -0
  18. data/lib/oauth/errors/problem.rb +14 -0
  19. data/lib/oauth/errors/unauthorized.rb +12 -0
  20. data/lib/oauth/helper.rb +77 -0
  21. data/lib/oauth/oauth.rb +7 -0
  22. data/lib/oauth/oauth_test_helper.rb +25 -0
  23. data/lib/oauth/request_proxy.rb +24 -0
  24. data/lib/oauth/request_proxy/action_controller_request.rb +63 -0
  25. data/lib/oauth/request_proxy/base.rb +159 -0
  26. data/lib/oauth/request_proxy/jabber_request.rb +41 -0
  27. data/lib/oauth/request_proxy/mock_request.rb +44 -0
  28. data/lib/oauth/request_proxy/net_http.rb +65 -0
  29. data/lib/oauth/request_proxy/rack_request.rb +40 -0
  30. data/lib/oauth/server.rb +66 -0
  31. data/lib/oauth/signature.rb +37 -0
  32. data/lib/oauth/signature/base.rb +99 -0
  33. data/lib/oauth/signature/hmac/base.rb +12 -0
  34. data/lib/oauth/signature/hmac/md5.rb +9 -0
  35. data/lib/oauth/signature/hmac/rmd160.rb +9 -0
  36. data/lib/oauth/signature/hmac/sha1.rb +9 -0
  37. data/lib/oauth/signature/hmac/sha2.rb +9 -0
  38. data/lib/oauth/signature/md5.rb +13 -0
  39. data/lib/oauth/signature/plaintext.rb +23 -0
  40. data/lib/oauth/signature/rsa/sha1.rb +45 -0
  41. data/lib/oauth/signature/sha1.rb +13 -0
  42. data/lib/oauth/token.rb +7 -0
  43. data/lib/oauth/tokens/access_token.rb +68 -0
  44. data/lib/oauth/tokens/consumer_token.rb +32 -0
  45. data/lib/oauth/tokens/request_token.rb +28 -0
  46. data/lib/oauth/tokens/server_token.rb +9 -0
  47. data/lib/oauth/tokens/token.rb +17 -0
  48. data/lib/oauth/version.rb +3 -0
  49. data/oauth.gemspec +49 -0
  50. data/script/destroy +14 -0
  51. data/script/generate +14 -0
  52. data/script/txt2html +74 -0
  53. data/setup.rb +1585 -0
  54. data/tasks/deployment.rake +34 -0
  55. data/tasks/environment.rake +7 -0
  56. data/tasks/website.rake +17 -0
  57. data/test/cases/oauth_case.rb +19 -0
  58. data/test/cases/spec/1_0-final/test_construct_request_url.rb +62 -0
  59. data/test/cases/spec/1_0-final/test_normalize_request_parameters.rb +88 -0
  60. data/test/cases/spec/1_0-final/test_parameter_encodings.rb +86 -0
  61. data/test/cases/spec/1_0-final/test_signature_base_strings.rb +77 -0
  62. data/test/keys/rsa.cert +11 -0
  63. data/test/keys/rsa.pem +16 -0
  64. data/test/test_access_token.rb +28 -0
  65. data/test/test_action_controller_request_proxy.rb +127 -0
  66. data/test/test_consumer.rb +327 -0
  67. data/test/test_helper.rb +10 -0
  68. data/test/test_hmac_sha1.rb +21 -0
  69. data/test/test_net_http_client.rb +187 -0
  70. data/test/test_net_http_request_proxy.rb +73 -0
  71. data/test/test_oauth_helper.rb +50 -0
  72. data/test/test_rack_request_proxy.rb +40 -0
  73. data/test/test_request_token.rb +53 -0
  74. data/test/test_rsa_sha1.rb +59 -0
  75. data/test/test_server.rb +40 -0
  76. data/test/test_signature.rb +19 -0
  77. data/test/test_signature_base.rb +32 -0
  78. data/test/test_signature_plain_text.rb +31 -0
  79. data/test/test_token.rb +14 -0
  80. data/website/index.html +87 -0
  81. data/website/index.txt +73 -0
  82. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  83. data/website/stylesheets/screen.css +138 -0
  84. data/website/template.rhtml +48 -0
  85. metadata +241 -0
@@ -0,0 +1,4 @@
1
+ module OAuth
2
+ module Client
3
+ end
4
+ end
@@ -0,0 +1,54 @@
1
+ require 'oauth/client/helper'
2
+ require 'oauth/request_proxy/action_controller_request'
3
+ require 'action_controller/test_process'
4
+
5
+ module ActionController
6
+ class Base
7
+ def process_with_oauth(request, response=nil)
8
+ request.apply_oauth!
9
+ process_without_oauth(request, response)
10
+ end
11
+
12
+ alias_method_chain :process, :oauth
13
+ end
14
+
15
+ class TestRequest
16
+ def self.use_oauth=(bool)
17
+ @use_oauth = bool
18
+ end
19
+
20
+ def self.use_oauth?
21
+ @use_oauth
22
+ end
23
+
24
+ def configure_oauth(consumer = nil, token = nil, options = {})
25
+ @oauth_options = { :consumer => consumer,
26
+ :token => token,
27
+ :scheme => 'header',
28
+ :signature_method => nil,
29
+ :nonce => nil,
30
+ :timestamp => nil }.merge(options)
31
+ end
32
+
33
+ def apply_oauth!
34
+ return unless ActionController::TestRequest.use_oauth? && @oauth_options
35
+
36
+ @oauth_helper = OAuth::Client::Helper.new(self, @oauth_options.merge(:request_uri => request_uri))
37
+ @oauth_helper.amend_user_agent_header(env)
38
+
39
+ self.send("set_oauth_#{@oauth_options[:scheme]}")
40
+ end
41
+
42
+ def set_oauth_header
43
+ env['Authorization'] = @oauth_helper.header
44
+ end
45
+
46
+ def set_oauth_parameters
47
+ @query_parameters = @oauth_helper.parameters_with_oauth
48
+ @query_parameters.merge!(:oauth_signature => @oauth_helper.signature)
49
+ end
50
+
51
+ def set_oauth_query_string
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,81 @@
1
+ require 'oauth/client'
2
+ require 'oauth/consumer'
3
+ require 'oauth/helper'
4
+ require 'oauth/token'
5
+ require 'oauth/version'
6
+ require 'oauth/signature/hmac/sha1'
7
+
8
+ module OAuth::Client
9
+ class Helper
10
+ include OAuth::Helper
11
+
12
+ def initialize(request, options = {})
13
+ @request = request
14
+ @options = options
15
+ @options[:signature_method] ||= 'HMAC-SHA1'
16
+ end
17
+
18
+ def options
19
+ @options
20
+ end
21
+
22
+ def nonce
23
+ options[:nonce] ||= generate_key
24
+ end
25
+
26
+ def timestamp
27
+ options[:timestamp] ||= generate_timestamp
28
+ end
29
+
30
+ def oauth_parameters
31
+ {
32
+ 'oauth_consumer_key' => options[:consumer].key,
33
+ 'oauth_token' => options[:token] ? options[:token].token : '',
34
+ 'oauth_signature_method' => options[:signature_method],
35
+ 'oauth_timestamp' => timestamp,
36
+ 'oauth_nonce' => nonce,
37
+ 'oauth_version' => '1.0'
38
+ }.reject { |k,v| v.to_s == "" }
39
+ end
40
+
41
+ def signature(extra_options = {})
42
+ OAuth::Signature.sign(@request, { :uri => options[:request_uri],
43
+ :consumer => options[:consumer],
44
+ :token => options[:token] }.merge(extra_options) )
45
+ end
46
+
47
+ def signature_base_string(extra_options = {})
48
+ OAuth::Signature.signature_base_string(@request, { :uri => options[:request_uri],
49
+ :consumer => options[:consumer],
50
+ :token => options[:token],
51
+ :parameters => oauth_parameters}.merge(extra_options) )
52
+ end
53
+
54
+ def amend_user_agent_header(headers)
55
+ @oauth_ua_string ||= "OAuth gem v#{OAuth::VERSION}"
56
+ if headers['User-Agent']
57
+ headers['User-Agent'] += " (#{@oauth_ua_string})"
58
+ else
59
+ headers['User-Agent'] = @oauth_ua_string
60
+ end
61
+ end
62
+
63
+ def header
64
+ parameters = oauth_parameters
65
+ parameters.merge!('oauth_signature' => signature(options.merge(:parameters => parameters)))
66
+
67
+ header_params_str = parameters.map { |k,v| "#{k}=\"#{escape(v)}\"" }.join(', ')
68
+
69
+ realm = "realm=\"#{options[:realm]}\", " if options[:realm]
70
+ "OAuth #{realm}#{header_params_str}"
71
+ end
72
+
73
+ def parameters
74
+ OAuth::RequestProxy.proxy(@request).parameters
75
+ end
76
+
77
+ def parameters_with_oauth
78
+ oauth_parameters.merge(parameters)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,94 @@
1
+ require 'oauth/helper'
2
+ require 'oauth/client/helper'
3
+ require 'oauth/request_proxy/net_http'
4
+
5
+ class Net::HTTPRequest
6
+ include OAuth::Helper
7
+
8
+ attr_reader :oauth_helper
9
+
10
+ # Add the OAuth information to an HTTP request. Depending on the <tt>options[:scheme]</tt> setting
11
+ # this may add a header, additional query string parameters, or additional POST body parameters.
12
+ # The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
13
+ # header.
14
+ #
15
+ # This method also modifies the <tt>User-Agent</tt> header to add the OAuth gem version.
16
+ #
17
+ # See Also: {OAuth core spec version 1.0, section 5.4.1}[http://oauth.net/core/1.0#rfc.section.5.4.1]
18
+ def oauth!(http, consumer = nil, token = nil, options = {})
19
+ options = { :request_uri => oauth_full_request_uri(http),
20
+ :consumer => consumer,
21
+ :token => token,
22
+ :scheme => 'header',
23
+ :signature_method => nil,
24
+ :nonce => nil,
25
+ :timestamp => nil }.merge(options)
26
+
27
+ @oauth_helper = OAuth::Client::Helper.new(self, options)
28
+ @oauth_helper.amend_user_agent_header(self)
29
+ self.send("set_oauth_#{options[:scheme]}")
30
+ end
31
+
32
+ # Create a string suitable for signing for an HTTP request. This process involves parameter
33
+ # normalization as specified in the OAuth specification. The exact normalization also depends
34
+ # on the <tt>options[:scheme]</tt> being used so this must match what will be used for the request
35
+ # itself. The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
36
+ # header.
37
+ #
38
+ # See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1]
39
+ def signature_base_string(http, consumer = nil, token = nil, options = {})
40
+ options = { :request_uri => oauth_full_request_uri(http),
41
+ :consumer => consumer,
42
+ :token => token,
43
+ :scheme => 'header',
44
+ :signature_method => nil,
45
+ :nonce => nil,
46
+ :timestamp => nil }.merge(options)
47
+
48
+ OAuth::Client::Helper.new(self, options).signature_base_string
49
+ end
50
+
51
+ private
52
+
53
+ def oauth_full_request_uri(http)
54
+ uri = URI.parse(self.path)
55
+ uri.host = http.address
56
+ uri.port = http.port
57
+
58
+ if http.respond_to?(:use_ssl?) && http.use_ssl?
59
+ uri.scheme = "https"
60
+ else
61
+ uri.scheme = "http"
62
+ end
63
+
64
+ uri.to_s
65
+ end
66
+
67
+ def set_oauth_header
68
+ self['Authorization'] = @oauth_helper.header
69
+ end
70
+
71
+ # FIXME: if you're using a POST body and query string parameters, using this
72
+ # method will convert those parameters on the query string into parameters in
73
+ # the body. this is broken, and should be fixed.
74
+ def set_oauth_body
75
+ self.set_form_data(@oauth_helper.parameters_with_oauth)
76
+ params_with_sig = @oauth_helper.parameters.merge(:oauth_signature => @oauth_helper.signature)
77
+ self.set_form_data(params_with_sig)
78
+ end
79
+
80
+ def set_oauth_query_string
81
+ oauth_params_str = @oauth_helper.oauth_parameters.map { |k,v| [escape(k), escape(v)] * "=" }.join("&")
82
+
83
+ uri = URI.parse(path)
84
+ if uri.query.to_s == ""
85
+ uri.query = oauth_params_str
86
+ else
87
+ uri.query = uri.query + "&" + oauth_params_str
88
+ end
89
+
90
+ @path = uri.to_s
91
+
92
+ @path << "&oauth_signature=#{escape(oauth_helper.signature)}"
93
+ end
94
+ end
@@ -0,0 +1,297 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'oauth/oauth'
4
+ require 'oauth/client/net_http'
5
+ require 'oauth/errors'
6
+
7
+ module OAuth
8
+ class Consumer
9
+ # determine the certificate authority path to verify SSL certs
10
+ CA_FILES = %w(/etc/ssl/certs/ca-certificates.crt /usr/share/curl/curl-ca-bundle.crt)
11
+ CA_FILES.each do |ca_file|
12
+ if File.exists?(ca_file)
13
+ CA_FILE = ca_file
14
+ break
15
+ end
16
+ end
17
+ CA_FILE = nil unless defined?(CA_FILE)
18
+
19
+ @@default_options = {
20
+ # Signature method used by server. Defaults to HMAC-SHA1
21
+ :signature_method => 'HMAC-SHA1',
22
+
23
+ # default paths on site. These are the same as the defaults set up by the generators
24
+ :request_token_path => '/oauth/request_token',
25
+ :authorize_path => '/oauth/authorize',
26
+ :access_token_path => '/oauth/access_token',
27
+
28
+ # How do we send the oauth values to the server see
29
+ # http://oauth.net/core/1.0/#consumer_req_param for more info
30
+ #
31
+ # Possible values:
32
+ #
33
+ # :header - via the Authorize header (Default) ( option 1. in spec)
34
+ # :body - url form encoded in body of POST request ( option 2. in spec)
35
+ # :query_string - via the query part of the url ( option 3. in spec)
36
+ :scheme => :header,
37
+
38
+ # Default http method used for OAuth Token Requests (defaults to :post)
39
+ :http_method => :post,
40
+
41
+ :oauth_version => "1.0"
42
+ }
43
+
44
+ attr_accessor :options, :key, :secret
45
+ attr_writer :site, :http
46
+
47
+ # Create a new consumer instance by passing it a configuration hash:
48
+ #
49
+ # @consumer = OAuth::Consumer.new(key, secret, {
50
+ # :site => "http://term.ie",
51
+ # :scheme => :header,
52
+ # :http_method => :post,
53
+ # :request_token_path => "/oauth/example/request_token.php",
54
+ # :access_token_path => "/oauth/example/access_token.php",
55
+ # :authorize_path => "/oauth/example/authorize.php"
56
+ # })
57
+ #
58
+ # Start the process by requesting a token
59
+ #
60
+ # @request_token = @consumer.get_request_token
61
+ # session[:request_token] = @request_token
62
+ # redirect_to @request_token.authorize_url
63
+ #
64
+ # When user returns create an access_token
65
+ #
66
+ # @access_token = @request_token.get_access_token
67
+ # @photos=@access_token.get('/photos.xml')
68
+ #
69
+ def initialize(consumer_key, consumer_secret, options = {})
70
+ @key = consumer_key
71
+ @secret = consumer_secret
72
+
73
+ # ensure that keys are symbols
74
+ @options = @@default_options.merge(options.inject({}) { |options, (key, value)|
75
+ options[key.to_sym] = value
76
+ options
77
+ })
78
+ end
79
+
80
+ # The default http method
81
+ def http_method
82
+ @http_method ||= @options[:http_method] || :post
83
+ end
84
+
85
+ # The HTTP object for the site. The HTTP Object is what you get when you do Net::HTTP.new
86
+ def http
87
+ @http ||= create_http
88
+ end
89
+
90
+ # Contains the root URI for this site
91
+ def uri(custom_uri = nil)
92
+ if custom_uri
93
+ @uri = custom_uri
94
+ @http = create_http # yike, oh well. less intrusive this way
95
+ else # if no custom passed, we use existing, which, if unset, is set to site uri
96
+ @uri ||= URI.parse(site)
97
+ end
98
+ end
99
+
100
+ # Makes a request to the service for a new OAuth::RequestToken
101
+ #
102
+ # @request_token = @consumer.get_request_token
103
+ #
104
+ def get_request_token(request_options = {}, *arguments)
105
+ response = token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil, request_options, *arguments)
106
+ OAuth::RequestToken.new(self, response[:oauth_token], response[:oauth_token_secret])
107
+ end
108
+
109
+ # Creates, signs and performs an http request.
110
+ # It's recommended to use the OAuth::Token classes to set this up correctly.
111
+ # The arguments parameters are a hash or string encoded set of parameters if it's a post request as well as optional http headers.
112
+ #
113
+ # @consumer.request(:get, '/people', @token, { :scheme => :query_string })
114
+ # @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
115
+ #
116
+ def request(http_method, path, token = nil, request_options = {}, *arguments)
117
+ if path !~ /^\//
118
+ @http = create_http(path)
119
+ _uri = URI.parse(path)
120
+ path = "#{_uri.path}#{_uri.query ? "?#{_uri.query}" : ""}"
121
+ end
122
+
123
+ rsp = http.request(create_signed_request(http_method, path, token, request_options, *arguments))
124
+
125
+ # check for an error reported by the Problem Reporting extension
126
+ # (http://wiki.oauth.net/ProblemReporting)
127
+ # note: a 200 may actually be an error; check for an oauth_problem key to be sure
128
+ if !(headers = rsp.to_hash["www-authenticate"]).nil? &&
129
+ (h = headers.select { |h| h =~ /^OAuth / }).any? &&
130
+ h.first =~ /oauth_problem/
131
+
132
+ # puts "Header: #{h.first}"
133
+
134
+ # TODO doesn't handle broken responses from api.login.yahoo.com
135
+ # remove debug code when done
136
+ params = OAuth::Helper.parse_header(h.first)
137
+
138
+ # puts "Params: #{params.inspect}"
139
+ # puts "Body: #{rsp.body}"
140
+
141
+ raise OAuth::Problem.new(params.delete("oauth_problem"), rsp, params)
142
+ end
143
+
144
+ rsp
145
+ end
146
+
147
+ # Creates and signs an http request.
148
+ # It's recommended to use the Token classes to set this up correctly
149
+ def create_signed_request(http_method, path, token = nil, request_options = {}, *arguments)
150
+ request = create_http_request(http_method, path, *arguments)
151
+ sign!(request, token, request_options)
152
+ request
153
+ end
154
+
155
+ # Creates a request and parses the result as url_encoded. This is used internally for the RequestToken and AccessToken requests.
156
+ def token_request(http_method, path, token = nil, request_options = {}, *arguments)
157
+ response = request(http_method, path, token, request_options, *arguments)
158
+
159
+ case response.code.to_i
160
+
161
+ when (200..299)
162
+ CGI.parse(response.body).inject({}) { |h,(k,v)| h[k.to_sym] = v.first; h }
163
+ when (300..399)
164
+ # this is a redirect
165
+ response.error!
166
+ when (400..499)
167
+ raise OAuth::Unauthorized, response
168
+ else
169
+ response.error!
170
+ end
171
+ end
172
+
173
+ # Sign the Request object. Use this if you have an externally generated http request object you want to sign.
174
+ def sign!(request, token = nil, request_options = {})
175
+ request.oauth!(http, self, token, options.merge(request_options))
176
+ end
177
+
178
+ # Return the signature_base_string
179
+ def signature_base_string(request, token = nil, request_options = {})
180
+ request.signature_base_string(http, self, token, options.merge(request_options))
181
+ end
182
+
183
+ def site
184
+ @options[:site].to_s
185
+ end
186
+
187
+ def scheme
188
+ @options[:scheme]
189
+ end
190
+
191
+ def request_token_path
192
+ @options[:request_token_path]
193
+ end
194
+
195
+ def authorize_path
196
+ @options[:authorize_path]
197
+ end
198
+
199
+ def access_token_path
200
+ @options[:access_token_path]
201
+ end
202
+
203
+ # TODO this is ugly, rewrite
204
+ def request_token_url
205
+ @options[:request_token_url] || site + request_token_path
206
+ end
207
+
208
+ def request_token_url?
209
+ @options.has_key?(:request_token_url)
210
+ end
211
+
212
+ def authorize_url
213
+ @options[:authorize_url] || site + authorize_path
214
+ end
215
+
216
+ def authorize_url?
217
+ @options.has_key?(:authorize_url)
218
+ end
219
+
220
+ def access_token_url
221
+ @options[:access_token_url] || site + access_token_path
222
+ end
223
+
224
+ def access_token_url?
225
+ @options.has_key?(:access_token_url)
226
+ end
227
+
228
+ protected
229
+
230
+ # Instantiates the http object
231
+ def create_http(_url = nil)
232
+ if _url.nil? || _url[0] =~ /^\//
233
+ our_uri = URI.parse(site)
234
+ else
235
+ our_uri = URI.parse(_url)
236
+ end
237
+
238
+ http_object = Net::HTTP.new(our_uri.host, our_uri.port)
239
+
240
+ http_object.use_ssl = (our_uri.scheme == 'https')
241
+
242
+ if CA_FILE
243
+ http_object.ca_file = CA_FILE
244
+ http_object.verify_mode = OpenSSL::SSL::VERIFY_PEER
245
+ http_object.verify_depth = 5
246
+ else
247
+ http_object.verify_mode = OpenSSL::SSL::VERIFY_NONE
248
+ end
249
+
250
+ http_object
251
+ end
252
+
253
+ # create the http request object for a given http_method and path
254
+ def create_http_request(http_method, path, *arguments)
255
+ http_method = http_method.to_sym
256
+
257
+ if [:post, :put].include?(http_method)
258
+ data = arguments.shift
259
+ end
260
+
261
+ headers = arguments.first.is_a?(Hash) ? arguments.shift : {}
262
+
263
+ case http_method
264
+ when :post
265
+ request = Net::HTTP::Post.new(path,headers)
266
+ request["Content-Length"] = 0 # Default to 0
267
+ when :put
268
+ request = Net::HTTP::Put.new(path,headers)
269
+ request["Content-Length"] = 0 # Default to 0
270
+ when :get
271
+ request = Net::HTTP::Get.new(path,headers)
272
+ when :delete
273
+ request = Net::HTTP::Delete.new(path,headers)
274
+ when :head
275
+ request = Net::HTTP::Head.new(path,headers)
276
+ else
277
+ raise ArgumentError, "Don't know how to handle http_method: :#{http_method.to_s}"
278
+ end
279
+
280
+ if data.is_a?(Hash)
281
+ request.set_form_data(data)
282
+ elsif data
283
+ request.body = data.to_s
284
+ request["Content-Length"] = request.body.length
285
+ end
286
+
287
+ request
288
+ end
289
+
290
+ # Unset cached http instance because it cannot be marshalled when
291
+ # it has already been used and use_ssl is set to true
292
+ def marshal_dump(*args)
293
+ @http = nil
294
+ self
295
+ end
296
+ end
297
+ end