apigee-oauth 0.4.0

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/.gitignore +2 -0
  2. data/HISTORY +125 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +70 -0
  5. data/Rakefile +35 -0
  6. data/TODO +32 -0
  7. data/bin/oauth +5 -0
  8. data/examples/yql.rb +44 -0
  9. data/lib/apigee-oauth.rb +12 -0
  10. data/lib/digest/hmac.rb +104 -0
  11. data/lib/oauth/cli.rb +378 -0
  12. data/lib/oauth/client.rb +4 -0
  13. data/lib/oauth/client/action_controller_request.rb +54 -0
  14. data/lib/oauth/client/em_http.rb +94 -0
  15. data/lib/oauth/client/helper.rb +91 -0
  16. data/lib/oauth/client/net_http.rb +127 -0
  17. data/lib/oauth/consumer.rb +383 -0
  18. data/lib/oauth/core_ext.rb +31 -0
  19. data/lib/oauth/errors.rb +3 -0
  20. data/lib/oauth/errors/error.rb +4 -0
  21. data/lib/oauth/errors/problem.rb +14 -0
  22. data/lib/oauth/errors/unauthorized.rb +12 -0
  23. data/lib/oauth/helper.rb +88 -0
  24. data/lib/oauth/oauth.rb +13 -0
  25. data/lib/oauth/oauth_test_helper.rb +25 -0
  26. data/lib/oauth/request_proxy.rb +24 -0
  27. data/lib/oauth/request_proxy/action_controller_request.rb +61 -0
  28. data/lib/oauth/request_proxy/base.rb +166 -0
  29. data/lib/oauth/request_proxy/curb_request.rb +55 -0
  30. data/lib/oauth/request_proxy/em_http_request.rb +67 -0
  31. data/lib/oauth/request_proxy/jabber_request.rb +41 -0
  32. data/lib/oauth/request_proxy/mock_request.rb +44 -0
  33. data/lib/oauth/request_proxy/net_http.rb +72 -0
  34. data/lib/oauth/request_proxy/rack_request.rb +40 -0
  35. data/lib/oauth/request_proxy/typhoeus_request.rb +53 -0
  36. data/lib/oauth/server.rb +66 -0
  37. data/lib/oauth/signature.rb +45 -0
  38. data/lib/oauth/signature/base.rb +110 -0
  39. data/lib/oauth/signature/hmac/base.rb +15 -0
  40. data/lib/oauth/signature/hmac/md5.rb +8 -0
  41. data/lib/oauth/signature/hmac/rmd160.rb +8 -0
  42. data/lib/oauth/signature/hmac/sha1.rb +9 -0
  43. data/lib/oauth/signature/hmac/sha2.rb +8 -0
  44. data/lib/oauth/signature/md5.rb +13 -0
  45. data/lib/oauth/signature/plaintext.rb +23 -0
  46. data/lib/oauth/signature/rsa/sha1.rb +46 -0
  47. data/lib/oauth/signature/sha1.rb +13 -0
  48. data/lib/oauth/token.rb +7 -0
  49. data/lib/oauth/tokens/access_token.rb +68 -0
  50. data/lib/oauth/tokens/consumer_token.rb +33 -0
  51. data/lib/oauth/tokens/request_token.rb +32 -0
  52. data/lib/oauth/tokens/server_token.rb +9 -0
  53. data/lib/oauth/tokens/token.rb +17 -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/integration/consumer_test.rb +304 -0
  63. data/test/keys/rsa.cert +11 -0
  64. data/test/keys/rsa.pem +16 -0
  65. data/test/test_access_token.rb +26 -0
  66. data/test/test_action_controller_request_proxy.rb +132 -0
  67. data/test/test_consumer.rb +159 -0
  68. data/test/test_curb_request_proxy.rb +76 -0
  69. data/test/test_em_http_client.rb +79 -0
  70. data/test/test_em_http_request_proxy.rb +114 -0
  71. data/test/test_helper.rb +20 -0
  72. data/test/test_hmac_sha1.rb +20 -0
  73. data/test/test_net_http_client.rb +282 -0
  74. data/test/test_net_http_request_proxy.rb +72 -0
  75. data/test/test_oauth_helper.rb +49 -0
  76. data/test/test_rack_request_proxy.rb +40 -0
  77. data/test/test_request_token.rb +51 -0
  78. data/test/test_rsa_sha1.rb +59 -0
  79. data/test/test_server.rb +40 -0
  80. data/test/test_signature.rb +22 -0
  81. data/test/test_signature_base.rb +32 -0
  82. data/test/test_signature_plain_text.rb +31 -0
  83. data/test/test_token.rb +14 -0
  84. data/test/test_typhoeus_request_proxy.rb +80 -0
  85. metadata +287 -0
@@ -0,0 +1,91 @@
1
+ require 'oauth/client'
2
+ require 'oauth/consumer'
3
+ require 'oauth/helper'
4
+ require 'oauth/token'
5
+ require 'oauth/signature/hmac/sha1'
6
+
7
+ module OAuth::Client
8
+ class Helper
9
+ include OAuth::Helper
10
+
11
+ def initialize(request, options = {})
12
+ @request = request
13
+ @options = options
14
+ @options[:signature_method] ||= 'HMAC-SHA1'
15
+ end
16
+
17
+ def options
18
+ @options
19
+ end
20
+
21
+ def nonce
22
+ options[:nonce] ||= generate_key
23
+ end
24
+
25
+ def timestamp
26
+ options[:timestamp] ||= generate_timestamp
27
+ end
28
+
29
+ def oauth_parameters
30
+ {
31
+ 'oauth_body_hash' => options[:body_hash],
32
+ 'oauth_callback' => options[:oauth_callback],
33
+ 'oauth_consumer_key' => options[:consumer].key,
34
+ 'oauth_token' => options[:token] ? options[:token].token : '',
35
+ 'oauth_signature_method' => options[:signature_method],
36
+ 'oauth_timestamp' => timestamp,
37
+ 'oauth_nonce' => nonce,
38
+ 'oauth_verifier' => options[:oauth_verifier],
39
+ 'oauth_version' => (options[:oauth_version] || '1.0'),
40
+ 'oauth_session_handle' => options[:oauth_session_handle]
41
+ }.reject { |k,v| v.to_s == "" }
42
+ end
43
+
44
+ def signature(extra_options = {})
45
+ OAuth::Signature.sign(@request, { :uri => options[:request_uri],
46
+ :consumer => options[:consumer],
47
+ :token => options[:token],
48
+ :unsigned_parameters => options[:unsigned_parameters]
49
+ }.merge(extra_options) )
50
+ end
51
+
52
+ def signature_base_string(extra_options = {})
53
+ OAuth::Signature.signature_base_string(@request, { :uri => options[:request_uri],
54
+ :consumer => options[:consumer],
55
+ :token => options[:token],
56
+ :parameters => oauth_parameters}.merge(extra_options) )
57
+ end
58
+
59
+ def hash_body
60
+ @options[:body_hash] = OAuth::Signature.body_hash(@request, :parameters => oauth_parameters)
61
+ end
62
+
63
+ def amend_user_agent_header(headers)
64
+ @oauth_ua_string ||= "OAuth gem v#{OAuth::VERSION}"
65
+ # Net::HTTP in 1.9 appends Ruby
66
+ if headers['User-Agent'] && headers['User-Agent'] != 'Ruby'
67
+ headers['User-Agent'] += " (#{@oauth_ua_string})"
68
+ else
69
+ headers['User-Agent'] = @oauth_ua_string
70
+ end
71
+ end
72
+
73
+ def header
74
+ parameters = oauth_parameters
75
+ parameters.merge!('oauth_signature' => signature(options.merge(:parameters => parameters)))
76
+
77
+ header_params_str = parameters.sort.map { |k,v| "#{k}=\"#{escape(v)}\"" }.join(', ')
78
+
79
+ realm = "realm=\"#{options[:realm]}\", " if options[:realm]
80
+ "OAuth #{realm}#{header_params_str}"
81
+ end
82
+
83
+ def parameters
84
+ OAuth::RequestProxy.proxy(@request).parameters
85
+ end
86
+
87
+ def parameters_with_oauth
88
+ oauth_parameters.merge(parameters)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,127 @@
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
+ # * http - Configured Net::HTTP instance
16
+ # * consumer - OAuth::Consumer instance
17
+ # * token - OAuth::Token instance
18
+ # * options - Request-specific options (e.g. +request_uri+, +consumer+, +token+, +scheme+,
19
+ # +signature_method+, +nonce+, +timestamp+)
20
+ #
21
+ # This method also modifies the <tt>User-Agent</tt> header to add the OAuth gem version.
22
+ #
23
+ # See Also: {OAuth core spec version 1.0, section 5.4.1}[http://oauth.net/core/1.0#rfc.section.5.4.1],
24
+ # {OAuth Request Body Hash 1.0 Draft 4}[http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html]
25
+ def oauth!(http, consumer = nil, token = nil, options = {})
26
+ helper_options = oauth_helper_options(http, consumer, token, options)
27
+ @oauth_helper = OAuth::Client::Helper.new(self, helper_options)
28
+ @oauth_helper.amend_user_agent_header(self)
29
+ @oauth_helper.hash_body if oauth_body_hash_required?
30
+ self.send("set_oauth_#{helper_options[:scheme]}")
31
+ end
32
+
33
+ # Create a string suitable for signing for an HTTP request. This process involves parameter
34
+ # normalization as specified in the OAuth specification. The exact normalization also depends
35
+ # on the <tt>options[:scheme]</tt> being used so this must match what will be used for the request
36
+ # itself. The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
37
+ # header.
38
+ #
39
+ # * http - Configured Net::HTTP instance
40
+ # * consumer - OAuth::Consumer instance
41
+ # * token - OAuth::Token instance
42
+ # * options - Request-specific options (e.g. +request_uri+, +consumer+, +token+, +scheme+,
43
+ # +signature_method+, +nonce+, +timestamp+)
44
+ #
45
+ # See Also: {OAuth core spec version 1.0, section 9.1.1}[http://oauth.net/core/1.0#rfc.section.9.1.1],
46
+ # {OAuth Request Body Hash 1.0 Draft 4}[http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html]
47
+ def signature_base_string(http, consumer = nil, token = nil, options = {})
48
+ helper_options = oauth_helper_options(http, consumer, token, options)
49
+ oauth_helper = OAuth::Client::Helper.new(self, helper_options)
50
+ oauth_helper.hash_body if oauth_body_hash_required?
51
+ oauth_helper.signature_base_string
52
+ end
53
+
54
+ private
55
+
56
+ def oauth_helper_options(http, consumer, token, options)
57
+ { :request_uri => oauth_full_request_uri(http,options),
58
+ :consumer => consumer,
59
+ :token => token,
60
+ :scheme => 'header',
61
+ :signature_method => nil,
62
+ :nonce => nil,
63
+ :timestamp => nil }.merge(options)
64
+ end
65
+
66
+ def oauth_full_request_uri(http,options)
67
+ uri = URI.parse(self.path)
68
+ uri.host = http.address
69
+ uri.port = http.port
70
+
71
+ if options[:request_endpoint] and options[:site]
72
+ hostval = options[:site]
73
+ if hostval.include?("http://")
74
+ hostval["http://"] = ""
75
+ end
76
+ if hostval.include?("https://")
77
+ hostval["https://"] = ""
78
+ end
79
+ uri.host = hostval
80
+ uri.port = 80
81
+ end
82
+
83
+ if http.respond_to?(:use_ssl?) && http.use_ssl?
84
+ uri.scheme = "https"
85
+ else
86
+ uri.scheme = "http"
87
+ end
88
+
89
+
90
+ uri.to_s
91
+ end
92
+
93
+ def oauth_body_hash_required?
94
+ request_body_permitted? && content_type != "application/x-www-form-urlencoded"
95
+ end
96
+
97
+ def set_oauth_header
98
+ self['Authorization'] = @oauth_helper.header
99
+ end
100
+
101
+ # FIXME: if you're using a POST body and query string parameters, this method
102
+ # will move query string parameters into the body unexpectedly. This may
103
+ # cause problems with non-x-www-form-urlencoded bodies submitted to URLs
104
+ # containing query string params. If duplicate parameters are present in both
105
+ # places, all instances should be included when calculating the signature
106
+ # base string.
107
+
108
+ def set_oauth_body
109
+ self.set_form_data(@oauth_helper.stringify_keys(@oauth_helper.parameters_with_oauth))
110
+ params_with_sig = @oauth_helper.parameters.merge(:oauth_signature => @oauth_helper.signature)
111
+ self.set_form_data(@oauth_helper.stringify_keys(params_with_sig))
112
+ end
113
+
114
+ def set_oauth_query_string
115
+ oauth_params_str = @oauth_helper.oauth_parameters.map { |k,v| [escape(k), escape(v)] * "=" }.join("&")
116
+ uri = URI.parse(path)
117
+ if uri.query.to_s == ""
118
+ uri.query = oauth_params_str
119
+ else
120
+ uri.query = uri.query + "&" + oauth_params_str
121
+ end
122
+
123
+ @path = uri.to_s
124
+
125
+ @path << "&oauth_signature=#{escape(oauth_helper.signature)}"
126
+ end
127
+ end
@@ -0,0 +1,383 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'oauth/oauth'
4
+ require 'oauth/client/net_http'
5
+ require 'oauth/errors'
6
+ require 'cgi'
7
+
8
+ module OAuth
9
+ class Consumer
10
+ # determine the certificate authority path to verify SSL certs
11
+ CA_FILES = %w(/etc/ssl/certs/ca-certificates.crt /usr/share/curl/curl-ca-bundle.crt)
12
+ CA_FILES.each do |ca_file|
13
+ if File.exists?(ca_file)
14
+ CA_FILE = ca_file
15
+ break
16
+ end
17
+ end
18
+ CA_FILE = nil unless defined?(CA_FILE)
19
+
20
+ @@default_options = {
21
+ # Signature method used by server. Defaults to HMAC-SHA1
22
+ :signature_method => 'HMAC-SHA1',
23
+
24
+ # default paths on site. These are the same as the defaults set up by the generators
25
+ :request_token_path => '/oauth/request_token',
26
+ :authorize_path => '/oauth/authorize',
27
+ :access_token_path => '/oauth/access_token',
28
+
29
+ :proxy => nil,
30
+ # How do we send the oauth values to the server see
31
+ # http://oauth.net/core/1.0/#consumer_req_param for more info
32
+ #
33
+ # Possible values:
34
+ #
35
+ # :header - via the Authorize header (Default) ( option 1. in spec)
36
+ # :body - url form encoded in body of POST request ( option 2. in spec)
37
+ # :query_string - via the query part of the url ( option 3. in spec)
38
+ :scheme => :header,
39
+
40
+ # Default http method used for OAuth Token Requests (defaults to :post)
41
+ :http_method => :post,
42
+
43
+ # Add a custom ca_file for consumer
44
+ # :ca_file => '/etc/certs.pem'
45
+
46
+ # Add a custom ca_file for consumer
47
+ # :ca_file => '/etc/certs.pem'
48
+
49
+ :oauth_version => "1.0"
50
+ }
51
+
52
+ attr_accessor :options, :key, :secret
53
+ attr_writer :site, :http
54
+
55
+ # Create a new consumer instance by passing it a configuration hash:
56
+ #
57
+ # @consumer = OAuth::Consumer.new(key, secret, {
58
+ # :site => "http://term.ie",
59
+ # :scheme => :header,
60
+ # :http_method => :post,
61
+ # :request_token_path => "/oauth/example/request_token.php",
62
+ # :access_token_path => "/oauth/example/access_token.php",
63
+ # :authorize_path => "/oauth/example/authorize.php"
64
+ # })
65
+ #
66
+ # Start the process by requesting a token
67
+ #
68
+ # @request_token = @consumer.get_request_token
69
+ # session[:request_token] = @request_token
70
+ # redirect_to @request_token.authorize_url
71
+ #
72
+ # When user returns create an access_token
73
+ #
74
+ # @access_token = @request_token.get_access_token
75
+ # @photos=@access_token.get('/photos.xml')
76
+ #
77
+ def initialize(consumer_key, consumer_secret, options = {})
78
+ @key = consumer_key
79
+ @secret = consumer_secret
80
+
81
+ # ensure that keys are symbols
82
+ @options = @@default_options.merge(options.inject({}) do |opts, (key, value)|
83
+ opts[key.to_sym] = value
84
+ opts
85
+ end)
86
+ end
87
+
88
+ # The default http method
89
+ def http_method
90
+ @http_method ||= @options[:http_method] || :post
91
+ end
92
+
93
+ # The HTTP object for the site. The HTTP Object is what you get when you do Net::HTTP.new
94
+ def http
95
+ @http ||= create_http
96
+ end
97
+
98
+ # Contains the root URI for this site
99
+ def uri(custom_uri = nil)
100
+ if custom_uri
101
+ @uri = custom_uri
102
+ @http = create_http # yike, oh well. less intrusive this way
103
+ else # if no custom passed, we use existing, which, if unset, is set to site uri
104
+ @uri ||= URI.parse(site)
105
+ end
106
+ end
107
+
108
+ def get_access_token(request_token, request_options = {}, *arguments, &block)
109
+ response = token_request(http_method, (access_token_url? ? access_token_url : access_token_path), request_token, request_options, *arguments, &block)
110
+ OAuth::AccessToken.from_hash(self, response)
111
+ end
112
+
113
+ # Makes a request to the service for a new OAuth::RequestToken
114
+ #
115
+ # @request_token = @consumer.get_request_token
116
+ #
117
+ # To include OAuth parameters:
118
+ #
119
+ # @request_token = @consumer.get_request_token \
120
+ # :oauth_callback => "http://example.com/cb"
121
+ #
122
+ # To include application-specific parameters:
123
+ #
124
+ # @request_token = @consumer.get_request_token({}, :foo => "bar")
125
+ #
126
+ # TODO oauth_callback should be a mandatory parameter
127
+ def get_request_token(request_options = {}, *arguments, &block)
128
+ # if oauth_callback wasn't provided, it is assumed that oauth_verifiers
129
+ # will be exchanged out of band
130
+ request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND unless request_options[:exclude_callback]
131
+
132
+ if block_given?
133
+ response = token_request(http_method,
134
+ (request_token_url? ? request_token_url : request_token_path),
135
+ nil,
136
+ request_options,
137
+ *arguments, &block)
138
+ else
139
+ response = token_request(http_method, (request_token_url? ? request_token_url : request_token_path), nil, request_options, *arguments)
140
+ end
141
+ OAuth::RequestToken.from_hash(self, response)
142
+ end
143
+
144
+ # Creates, signs and performs an http request.
145
+ # It's recommended to use the OAuth::Token classes to set this up correctly.
146
+ # request_options take precedence over consumer-wide options when signing
147
+ # a request.
148
+ # arguments are POST and PUT bodies (a Hash, string-encoded parameters, or
149
+ # absent), followed by additional HTTP headers.
150
+ #
151
+ # @consumer.request(:get, '/people', @token, { :scheme => :query_string })
152
+ # @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
153
+ #
154
+ def request(http_method, path, token = nil, request_options = {}, *arguments)
155
+ if path !~ /^\//
156
+ @http = create_http(path)
157
+ _uri = URI.parse(path)
158
+ path = "#{_uri.path}#{_uri.query ? "?#{_uri.query}" : ""}"
159
+ end
160
+
161
+ # override the request with your own, this is useful for file uploads which Net::HTTP does not do
162
+ req = create_signed_request(http_method, path, token, request_options, *arguments)
163
+ return nil if block_given? and yield(req) == :done
164
+ rsp = http.request(req)
165
+ # check for an error reported by the Problem Reporting extension
166
+ # (http://wiki.oauth.net/ProblemReporting)
167
+ # note: a 200 may actually be an error; check for an oauth_problem key to be sure
168
+ if !(headers = rsp.to_hash["www-authenticate"]).nil? &&
169
+ (h = headers.select { |hdr| hdr =~ /^OAuth / }).any? &&
170
+ h.first =~ /oauth_problem/
171
+
172
+ # puts "Header: #{h.first}"
173
+
174
+ # TODO doesn't handle broken responses from api.login.yahoo.com
175
+ # remove debug code when done
176
+ params = OAuth::Helper.parse_header(h.first)
177
+
178
+ # puts "Params: #{params.inspect}"
179
+ # puts "Body: #{rsp.body}"
180
+
181
+ raise OAuth::Problem.new(params.delete("oauth_problem"), rsp, params)
182
+ end
183
+
184
+ rsp
185
+ end
186
+
187
+ # Creates and signs an http request.
188
+ # It's recommended to use the Token classes to set this up correctly
189
+ def create_signed_request(http_method, path, token = nil, request_options = {}, *arguments)
190
+ request = create_http_request(http_method, path, *arguments)
191
+ sign!(request, token, request_options)
192
+ request
193
+ end
194
+
195
+ # Creates a request and parses the result as url_encoded. This is used internally for the RequestToken and AccessToken requests.
196
+ def token_request(http_method, path, token = nil, request_options = {}, *arguments)
197
+ response = request(http_method, path, token, request_options, *arguments)
198
+ case response.code.to_i
199
+
200
+ when (200..299)
201
+ if block_given?
202
+ yield response.body
203
+ else
204
+ # symbolize keys
205
+ # TODO this could be considered unexpected behavior; symbols or not?
206
+ # TODO this also drops subsequent values from multi-valued keys
207
+ CGI.parse(response.body).inject({}) do |h,(k,v)|
208
+ h[k.strip.to_sym] = v.first
209
+ h[k.strip] = v.first
210
+ h
211
+ end
212
+ end
213
+ when (300..399)
214
+ # this is a redirect
215
+ response.error!
216
+ when (400..499)
217
+ raise OAuth::Unauthorized, response
218
+ else
219
+ response.error!
220
+ end
221
+ end
222
+
223
+ # Sign the Request object. Use this if you have an externally generated http request object you want to sign.
224
+ def sign!(request, token = nil, request_options = {})
225
+ request.oauth!(http, self, token, options.merge(request_options))
226
+ end
227
+
228
+ # Return the signature_base_string
229
+ def signature_base_string(request, token = nil, request_options = {})
230
+ request.signature_base_string(http, self, token, options.merge(request_options))
231
+ end
232
+
233
+ def site
234
+ @options[:site].to_s
235
+ end
236
+
237
+ def request_endpoint
238
+ return nil if @options[:request_endpoint].nil?
239
+ @options[:request_endpoint].to_s
240
+ end
241
+
242
+ def scheme
243
+ @options[:scheme]
244
+ end
245
+
246
+ def request_token_path
247
+ @options[:request_token_path]
248
+ end
249
+
250
+ def authorize_path
251
+ @options[:authorize_path]
252
+ end
253
+
254
+ def access_token_path
255
+ @options[:access_token_path]
256
+ end
257
+
258
+ # TODO this is ugly, rewrite
259
+ def request_token_url
260
+ @options[:request_token_url] || site + request_token_path
261
+ end
262
+
263
+ def request_token_url?
264
+ @options.has_key?(:request_token_url)
265
+ end
266
+
267
+ def authorize_url
268
+ @options[:authorize_url] || site + authorize_path
269
+ end
270
+
271
+ def authorize_url?
272
+ @options.has_key?(:authorize_url)
273
+ end
274
+
275
+ def access_token_url
276
+ @options[:access_token_url] || site + access_token_path
277
+ end
278
+
279
+ def access_token_url?
280
+ @options.has_key?(:access_token_url)
281
+ end
282
+
283
+ def proxy
284
+ @options[:proxy]
285
+ end
286
+
287
+ protected
288
+
289
+ # Instantiates the http object
290
+ def create_http(_url = nil)
291
+
292
+
293
+ if !request_endpoint.nil?
294
+ _url = request_endpoint
295
+ end
296
+
297
+
298
+ if _url.nil? || _url[0] =~ /^\//
299
+ our_uri = URI.parse(site)
300
+ else
301
+ our_uri = URI.parse(_url)
302
+ end
303
+
304
+
305
+ if proxy.nil?
306
+ http_object = Net::HTTP.new(our_uri.host, our_uri.port)
307
+ else
308
+ proxy_uri = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
309
+ http_object = Net::HTTP.new(our_uri.host, our_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
310
+ end
311
+
312
+ http_object.use_ssl = (our_uri.scheme == 'https')
313
+
314
+ if @options[:ca_file] || CA_FILE
315
+ http_object.ca_file = @options[:ca_file] || CA_FILE
316
+ http_object.verify_mode = OpenSSL::SSL::VERIFY_PEER
317
+ http_object.verify_depth = 5
318
+ else
319
+ http_object.verify_mode = OpenSSL::SSL::VERIFY_NONE
320
+ end
321
+ http_object
322
+ end
323
+
324
+ # create the http request object for a given http_method and path
325
+ def create_http_request(http_method, path, *arguments)
326
+ http_method = http_method.to_sym
327
+
328
+ if [:post, :put].include?(http_method)
329
+ data = arguments.shift
330
+ end
331
+
332
+ headers = arguments.first.is_a?(Hash) ? arguments.shift : {}
333
+
334
+ case http_method
335
+ when :post
336
+ request = Net::HTTP::Post.new(path,headers)
337
+ request["Content-Length"] = 0 # Default to 0
338
+ when :put
339
+ request = Net::HTTP::Put.new(path,headers)
340
+ request["Content-Length"] = 0 # Default to 0
341
+ when :get
342
+ request = Net::HTTP::Get.new(path,headers)
343
+ when :delete
344
+ request = Net::HTTP::Delete.new(path,headers)
345
+ when :head
346
+ request = Net::HTTP::Head.new(path,headers)
347
+ else
348
+ raise ArgumentError, "Don't know how to handle http_method: :#{http_method.to_s}"
349
+ end
350
+
351
+ if data.is_a?(Hash)
352
+ form_data = {}
353
+ data.each {|k,v| form_data[k.to_s] = v if !v.nil?}
354
+ request.set_form_data(form_data)
355
+ elsif data
356
+ if data.respond_to?(:read)
357
+ request.body_stream = data
358
+ if data.respond_to?(:length)
359
+ request["Content-Length"] = data.length
360
+ elsif data.respond_to?(:stat) && data.stat.respond_to?(:size)
361
+ request["Content-Length"] = data.stat.size
362
+ else
363
+ raise ArgumentError, "Don't know how to send a body_stream that doesn't respond to .length or .stat.size"
364
+ end
365
+ else
366
+ request.body = data.to_s
367
+ request["Content-Length"] = request.body.length
368
+ end
369
+ end
370
+
371
+ request
372
+ end
373
+
374
+ def marshal_dump(*args)
375
+ {:key => @key, :secret => @secret, :options => @options}
376
+ end
377
+
378
+ def marshal_load(data)
379
+ initialize(data[:key], data[:secret], data[:options])
380
+ end
381
+
382
+ end
383
+ end