class OAuth::Consumer

Consumer credentials and request configuration for OAuth 1.0 / 1.0a flows.

Includes {OAuth::AUTH_SANITIZER::FilteredAttributes} so inspect output redacts the consumer secret while leaving non-sensitive configuration visible.

Constants

CA_FILE
CA_FILES

Attributes

http[W]
key[RW]
options[RW]
secret[RW]
site[W]

Public Class Methods

new(consumer_key, consumer_secret, options = {}) click to toggle source

Create a new consumer instance by passing it a configuration hash:

@consumer = OAuth::Consumer.new(key, secret, {
  :site               => "http://term.ie",
  :scheme             => :header,
  :http_method        => :post,
  :request_token_path => "/oauth/example/request_token.php",
  :access_token_path  => "/oauth/example/access_token.php",
  :authorize_path     => "/oauth/example/authorize.php",
  :body_hash_enabled  => false
 })

Start the process by requesting a token

@request_token = @consumer.get_request_token
session[:request_token] = @request_token
redirect_to @request_token.authorize_url

When user returns create an access_token

@access_token = @request_token.get_access_token
@photos=@access_token.get('/photos.xml')
    # File lib/oauth/consumer.rb
128 def initialize(consumer_key, consumer_secret, options = {})
129   @key = consumer_key
130   @secret = consumer_secret
131 
132   # ensure that keys are symbols
133   snaky_options = SnakyHash::SymbolKeyed.new(options)
134   @options = @@default_options.merge(snaky_options)
135 end

Public Instance Methods

access_token_path() click to toggle source
    # File lib/oauth/consumer.rb
423 def access_token_path
424   @options[:access_token_path]
425 end
access_token_url() click to toggle source
    # File lib/oauth/consumer.rb
452 def access_token_url
453   @options[:access_token_url] || (site + access_token_path)
454 end
access_token_url?() click to toggle source
    # File lib/oauth/consumer.rb
456 def access_token_url?
457   @options.key?(:access_token_url)
458 end
authenticate_path() click to toggle source
    # File lib/oauth/consumer.rb
415 def authenticate_path
416   @options[:authenticate_path]
417 end
authenticate_url() click to toggle source
    # File lib/oauth/consumer.rb
436 def authenticate_url
437   @options[:authenticate_url] || (site + authenticate_path)
438 end
authenticate_url?() click to toggle source
    # File lib/oauth/consumer.rb
440 def authenticate_url?
441   @options.key?(:authenticate_url)
442 end
authorize_path() click to toggle source
    # File lib/oauth/consumer.rb
419 def authorize_path
420   @options[:authorize_path]
421 end
authorize_url() click to toggle source
    # File lib/oauth/consumer.rb
444 def authorize_url
445   @options[:authorize_url] || (site + authorize_path)
446 end
authorize_url?() click to toggle source
    # File lib/oauth/consumer.rb
448 def authorize_url?
449   @options.key?(:authorize_url)
450 end
create_signed_request(http_method, path, token = nil, request_options = {}, *arguments) click to toggle source

Creates and signs an http request. It's recommended to use the Token classes to set this up correctly

    # File lib/oauth/consumer.rb
296 def create_signed_request(http_method, path, token = nil, request_options = {}, *arguments)
297   request = create_http_request(http_method, path, *arguments)
298   sign!(request, token, request_options)
299   request
300 end
debug_output() click to toggle source
    # File lib/oauth/consumer.rb
142 def debug_output
143   @debug_output ||= case @options[:debug_output]
144   when nil, false
145   when true
146     $stdout
147   else
148     @options[:debug_output]
149   end
150 end
get_access_token(request_token, request_options = {}, *arguments, &block) click to toggle source

Exchanges a verified Request Token for an Access Token.

OAuth 1.0 vs 1.0a:

  • 1.0a requires including oauth_verifier (as returned by the Provider after user authorization) when performing this exchange in a 3‑legged flow.

  • 1.0 flows did not include oauth_verifier.

Usage (3‑legged):

access_token = request_token.get_access_token(oauth_verifier: params[:oauth_verifier])

@param request_token [OAuth::RequestToken] The authorized request token @param request_options [Hash] OAuth or request options (include :oauth_verifier for 1.0a) @param arguments [Array] Optional POST body and headers @yield [response_body] If a block is given, yields the raw response body. @return [OAuth::AccessToken]

    # File lib/oauth/consumer.rb
182 def get_access_token(request_token, request_options = {}, *arguments, &block)
183   response = token_request(
184     http_method,
185     (access_token_url? ? access_token_url : access_token_path),
186     request_token,
187     request_options,
188     *arguments,
189     &block
190   )
191   OAuth::AccessToken.from_hash(self, response)
192 end
get_request_token(request_options = {}, *arguments, &block) click to toggle source

Makes a request to the service for a new OAuth::RequestToken

Example:

@request_token = @consumer.get_request_token

To include OAuth parameters:

@request_token = @consumer.get_request_token(
  oauth_callback: "http://example.com/cb"
)

To include application-specific parameters:

@request_token = @consumer.get_request_token({}, foo: "bar")

OAuth 1.0 vs 1.0a:

  • In 1.0a, the Consumer SHOULD send oauth_callback when obtaining a request token (or explicitly use OUT_OF_BAND) and the Provider MUST include oauth_callback_confirmed=true in the response.

  • This library defaults oauth_callback to OUT_OF_BAND (“oob”) when not provided, which works for both 1.0 and 1.0a, and mirrors common provider behavior.

  • The oauth_callback_confirmed response is parsed by the token classes; it is not part of the signature base string and thus is not signed.

TODO: In a future major release, oauth_callback may be made mandatory unless

request_options[:exclude_callback] is set, to reflect 1.0a guidance.

@param request_options [Hash] OAuth options for the request. Notably

:oauth_callback can be set to a URL, or OAuth::OUT_OF_BAND ("oob").

@param arguments [Array] Optional POST body and headers @yield [response_body] If a block is given, yields the raw response body. @return [OAuth::RequestToken]

    # File lib/oauth/consumer.rb
224 def get_request_token(request_options = {}, *arguments, &block)
225   # if oauth_callback wasn't provided, it is assumed that oauth_verifiers
226   # will be exchanged out of band
227   request_options[:oauth_callback] ||= OAuth::OUT_OF_BAND unless request_options[:exclude_callback]
228 
229   response = if block
230     token_request(
231       http_method,
232       (request_token_url? ? request_token_url : request_token_path),
233       nil,
234       request_options,
235       *arguments,
236       &block
237     )
238   else
239     token_request(
240       http_method,
241       (request_token_url? ? request_token_url : request_token_path),
242       nil,
243       request_options,
244       *arguments
245     )
246   end
247   OAuth::RequestToken.from_hash(self, response)
248 end
http() click to toggle source

The HTTP object for the site. The HTTP Object is what you get when you do Net::HTTP.new

    # File lib/oauth/consumer.rb
153 def http
154   @http ||= create_http
155 end
http_method() click to toggle source

The default http method

    # File lib/oauth/consumer.rb
138 def http_method
139   @http_method ||= @options[:http_method] || :post
140 end
proxy() click to toggle source
    # File lib/oauth/consumer.rb
460 def proxy
461   @options[:proxy]
462 end
request(http_method, path, token = nil, request_options = {}, *arguments) { |req| ... } click to toggle source

Creates, signs and performs an http request. It's recommended to use the OAuth::Token classes to set this up correctly. request_options take precedence over consumer-wide options when signing

a request.

arguments are POST and PUT bodies (a Hash, string-encoded parameters, or

absent), followed by additional HTTP headers.

@consumer.request(:get,  '/people', @token, { :scheme => :query_string })
@consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
    # File lib/oauth/consumer.rb
260 def request(http_method, path, token = nil, request_options = {}, *arguments)
261   unless %r{^/} =~ path
262     @http = create_http(path)
263     uri = URI.parse(path)
264     path = "#{uri.path}#{"?#{uri.query}" if uri.query}"
265   end
266 
267   # override the request with your own, this is useful for file uploads which Net::HTTP does not do
268   req = create_signed_request(http_method, path, token, request_options, *arguments)
269   return if block_given? && (yield(req) == :done)
270 
271   rsp = http.request(req)
272   # check for an error reported by the Problem Reporting extension
273   # (https://wiki.oauth.net/ProblemReporting)
274   # note: a 200 may actually be an error; check for an oauth_problem key to be sure
275   if !(headers = rsp.to_hash["www-authenticate"]).nil? &&
276       (h = headers.grep(/^OAuth /)).any? &&
277       h.first.include?("oauth_problem")
278 
279     # puts "Header: #{h.first}"
280 
281     # TODO: doesn't handle broken responses from api.login.yahoo.com
282     # remove debug code when done
283     params = OAuth::Helper.parse_header(h.first)
284 
285     # puts "Params: #{params.inspect}"
286     # puts "Body: #{rsp.body}"
287 
288     raise OAuth::Problem.new(params.delete("oauth_problem"), rsp, params)
289   end
290 
291   rsp
292 end
request_endpoint() click to toggle source
    # File lib/oauth/consumer.rb
401 def request_endpoint
402   return if @options[:request_endpoint].nil?
403 
404   @options[:request_endpoint].to_s
405 end
request_token_path() click to toggle source
    # File lib/oauth/consumer.rb
411 def request_token_path
412   @options[:request_token_path]
413 end
request_token_url() click to toggle source

TODO: this is ugly, rewrite

    # File lib/oauth/consumer.rb
428 def request_token_url
429   @options[:request_token_url] || (site + request_token_path)
430 end
request_token_url?() click to toggle source
    # File lib/oauth/consumer.rb
432 def request_token_url?
433   @options.key?(:request_token_url)
434 end
scheme() click to toggle source
    # File lib/oauth/consumer.rb
407 def scheme
408   @options[:scheme]
409 end
sign!(request, token = nil, request_options = {}) click to toggle source

Sign the Request object. Use this if you have an externally generated http request object you want to sign.

    # File lib/oauth/consumer.rb
388 def sign!(request, token = nil, request_options = {})
389   request.oauth!(http, self, token, options.merge(request_options))
390 end
signature_base_string(request, token = nil, request_options = {}) click to toggle source

Return the signature_base_string

    # File lib/oauth/consumer.rb
393 def signature_base_string(request, token = nil, request_options = {})
394   request.signature_base_string(http, self, token, options.merge(request_options))
395 end
site() click to toggle source
    # File lib/oauth/consumer.rb
397 def site
398   @options[:site].to_s
399 end
token_request(http_method, path, token = nil, request_options = {}, *arguments, &block) click to toggle source

Creates a request and parses the result as url_encoded. This is used internally for the RequestToken and AccessToken requests.

    # File lib/oauth/consumer.rb
303 def token_request(http_method, path, token = nil, request_options = {}, *arguments, &block)
304   response = request(http_method, path, token, token_request_options(request_options), *arguments)
305   case response.code.to_i
306 
307   when (200..299)
308     if block
309       block.call(response.body)
310     else
311       # symbolize keys
312       # TODO this could be considered unexpected behavior; symbols or not?
313       # TODO this also drops subsequent values from multi-valued keys
314       CGI.parse(response.body).each_with_object({}) do |(k, v), h|
315         h[k.strip.to_sym] = v.first
316         h[k.strip] = v.first
317       end
318     end
319   when (300..399)
320     current_uri = token_request_uri(path)
321     redirected_uri = token_request_redirect_uri(current_uri, response)
322     response.error! unless redirected_uri
323 
324     redirect_count = request_options[:token_request_redirect_count].to_i + 1
325     response.error! if redirect_count > token_request_max_redirects(request_options)
326     response.error! if token_request_cross_origin?(current_uri, redirected_uri) &&
327       !token_request_cross_origin_redirects?(request_options)
328 
329     redirect_options = request_options.merge(token_request_redirect_count: redirect_count)
330     token_request(http_method, token_request_redirect_path(current_uri, redirected_uri), token, redirect_options, *arguments, &block)
331   when (400..499)
332     raise OAuth::Unauthorized, response
333   else
334     response.error!
335   end
336 end
token_request_cross_origin?(current_uri, redirected_uri) click to toggle source
    # File lib/oauth/consumer.rb
374 def token_request_cross_origin?(current_uri, redirected_uri)
375   current_uri.scheme.to_s.downcase != redirected_uri.scheme.to_s.downcase ||
376     current_uri.host.to_s.downcase != redirected_uri.host.to_s.downcase ||
377     token_request_effective_port(current_uri) != token_request_effective_port(redirected_uri)
378 end
token_request_cross_origin_redirects?(request_options) click to toggle source
    # File lib/oauth/consumer.rb
370 def token_request_cross_origin_redirects?(request_options)
371   request_options.fetch(:token_request_cross_origin_redirects, options[:token_request_cross_origin_redirects])
372 end
token_request_effective_port(uri) click to toggle source
    # File lib/oauth/consumer.rb
380 def token_request_effective_port(uri)
381   return uri.port if uri.port
382   return 443 if uri.scheme == "https"
383 
384   80 if uri.scheme == "http"
385 end
token_request_max_redirects(request_options) click to toggle source
    # File lib/oauth/consumer.rb
366 def token_request_max_redirects(request_options)
367   request_options[:token_request_max_redirects] || options[:token_request_max_redirects]
368 end
token_request_options(request_options) click to toggle source
    # File lib/oauth/consumer.rb
338 def token_request_options(request_options)
339   request_options.merge(token_request: true).tap do |options|
340     options.delete(:token_request_redirect_count)
341     options.delete(:token_request_max_redirects)
342     options.delete(:token_request_cross_origin_redirects)
343   end
344 end
token_request_redirect_path(current_uri, redirected_uri) click to toggle source
    # File lib/oauth/consumer.rb
360 def token_request_redirect_path(current_uri, redirected_uri)
361   return redirected_uri.to_s if token_request_cross_origin?(current_uri, redirected_uri)
362 
363   redirected_uri.request_uri
364 end
token_request_redirect_uri(current_uri, response) click to toggle source
    # File lib/oauth/consumer.rb
353 def token_request_redirect_uri(current_uri, response)
354   location = response["location"]
355   return if location.nil? || location.to_s.empty?
356 
357   current_uri.merge(location)
358 end
token_request_uri(path) click to toggle source
    # File lib/oauth/consumer.rb
346 def token_request_uri(path)
347   uri = URI.parse(path)
348   return uri if uri.absolute?
349 
350   URI.parse(site).merge(path)
351 end
uri(custom_uri = nil) click to toggle source

Contains the root URI for this site

    # File lib/oauth/consumer.rb
158 def uri(custom_uri = nil)
159   if custom_uri
160     @uri = custom_uri
161     @http = create_http # yike, oh well. less intrusive this way
162   else # if no custom passed, we use existing, which, if unset, is set to site uri
163     @uri ||= URI.parse(site)
164   end
165 end

Protected Instance Methods

create_http(url = nil) click to toggle source

Instantiates the http object

    # File lib/oauth/consumer.rb
467 def create_http(url = nil)
468   url = request_endpoint unless request_endpoint.nil?
469 
470   our_uri = if url.nil? || url[0] =~ %r{^/}
471     URI.parse(site)
472   else
473     your_uri = URI.parse(url)
474     if your_uri.host.nil?
475       # If the _url is a path, missing the leading slash, then it won't have a host,
476       # and our_uri *must* have a host, so we parse site instead.
477       URI.parse(site)
478     else
479       your_uri
480     end
481   end
482 
483   if proxy.nil?
484     http_object = Net::HTTP.new(our_uri.host, our_uri.port)
485   else
486     proxy_uri = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
487     http_object = Net::HTTP.new(
488       our_uri.host,
489       our_uri.port,
490       proxy_uri.host,
491       proxy_uri.port,
492       proxy_uri.user,
493       proxy_uri.password
494     )
495   end
496 
497   http_object.use_ssl = (our_uri.scheme == "https")
498 
499   if @options[:no_verify]
500     http_object.verify_mode = OpenSSL::SSL::VERIFY_NONE
501   else
502     ca_file = @options[:ca_file] || CA_FILE
503     http_object.ca_file = ca_file if ca_file
504     http_object.verify_mode = OpenSSL::SSL::VERIFY_PEER
505     http_object.verify_depth = 5
506   end
507 
508   http_object.read_timeout = http_object.open_timeout = @options[:timeout] || 60
509   http_object.open_timeout = @options[:open_timeout] if @options[:open_timeout]
510   http_object.ssl_version = @options[:ssl_version] if @options[:ssl_version]
511   http_object.cert = @options[:ssl_client_cert] if @options[:ssl_client_cert]
512   http_object.key = @options[:ssl_client_key] if @options[:ssl_client_key]
513   http_object.set_debug_output(debug_output) if debug_output
514 
515   http_object
516 end
create_http_request(http_method, path, *arguments) click to toggle source

create the http request object for a given http_method and path

    # File lib/oauth/consumer.rb
519 def create_http_request(http_method, path, *arguments)
520   http_method = http_method.to_sym
521 
522   data = arguments.shift if %i[post put patch].include?(http_method)
523 
524   # if the base site contains a path, add it now
525   # only add if the site host matches the current http object's host
526   # (in case we've specified a full url for token requests)
527   uri = URI.parse(site)
528   path = uri.path + path if uri.path && uri.path != "/" && uri.host == http.address
529 
530   headers = arguments.first.is_a?(Hash) ? arguments.shift : {}
531 
532   case http_method
533   when :post
534     request = Net::HTTP::Post.new(path, headers)
535     request["Content-Length"] = "0" # Default to 0
536   when :put
537     request = Net::HTTP::Put.new(path, headers)
538     request["Content-Length"] = "0" # Default to 0
539   when :patch
540     request = Net::HTTP::Patch.new(path, headers)
541     request["Content-Length"] = "0" # Default to 0
542   when :get
543     request = Net::HTTP::Get.new(path, headers)
544   when :delete
545     request = Net::HTTP::Delete.new(path, headers)
546   when :head
547     request = Net::HTTP::Head.new(path, headers)
548   else
549     raise ArgumentError, "Don't know how to handle http_method: :#{http_method}"
550   end
551 
552   if data.is_a?(Hash)
553     request.body = OAuth::Helper.normalize(data)
554     request.content_type = "application/x-www-form-urlencoded"
555   elsif data
556     if data.respond_to?(:read)
557       request.body_stream = data
558       if data.respond_to?(:length)
559         request["Content-Length"] = data.length.to_s
560       elsif data.respond_to?(:stat) && data.stat.respond_to?(:size)
561         request["Content-Length"] = data.stat.size.to_s
562       else
563         raise ArgumentError, "Don't know how to send a body_stream that doesn't respond to .length or .stat.size"
564       end
565     else
566       request.body = data.to_s
567       request["Content-Length"] = request.body.length.to_s
568     end
569   end
570 
571   request
572 end
marshal_dump(*_args) click to toggle source
    # File lib/oauth/consumer.rb
574 def marshal_dump(*_args)
575   {key: @key, secret: @secret, options: @options}
576 end
marshal_load(data) click to toggle source
    # File lib/oauth/consumer.rb
578 def marshal_load(data)
579   initialize(data[:key], data[:secret], data[:options])
580 end