lib/oauth2/client.rb in panjiva-oauth2-0.4.1 vs lib/oauth2/client.rb in panjiva-oauth2-0.5.0
- old
+ new
@@ -1,105 +1,146 @@
require 'faraday'
module OAuth2
+ # The OAuth2::Client class
class Client
- attr_accessor :id, :secret, :site, :connection, :options, :raise_errors, :token_method
- attr_writer :json
+ attr_reader :id, :secret
+ attr_accessor :site, :connection, :options
# Instantiate a new OAuth 2.0 client using the
- # client ID and client secret registered to your
+ # Client ID and Client Secret registered to your
# application.
#
- # Options:
+ # @param [String] client_id the client_id value
+ # @param [String] client_secret the client_secret value
+ # @param [Hash] opts the options to create the client with
+ # @option opts [String] :site the OAuth2 provider site host
+ # @option opts [String] :authorize_url ('/oauth/authorize') absolute or relative URL path to the Authorization endpoint
+ # @option opts [String] :token_url ('/oauth/token') absolute or relative URL path to the Token endpoint
+ # @option opts [Symbol] :token_method (:post) HTTP method to use to request token (:get or :post)
+ # @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
+ # @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
+ # @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
+ # on responses with 400+ status codes
+ # @yield [builder] The Faraday connection builder
+ def initialize(client_id, client_secret, opts={}, &block)
+ @id = client_id
+ @secret = client_secret
+ @site = opts.delete(:site)
+ ssl = opts.delete(:ssl)
+ @options = {:authorize_url => '/oauth/authorize',
+ :token_url => '/oauth/token',
+ :token_method => :post,
+ :connection_opts => {},
+ :connection_build => block,
+ :max_redirects => 5,
+ :raise_errors => true}.merge(opts)
+ @options[:connection_opts][:ssl] = ssl if ssl
+ end
+
+ # Set the site host
#
- # <tt>:site</tt> :: Specify a base URL for your OAuth 2.0 client.
- # <tt>:authorize_path</tt> :: Specify the path to the authorization endpoint.
- # <tt>:authorize_url</tt> :: Specify a full URL of the authorization endpoint.
- # <tt>:access_token_path</tt> :: Specify the path to the access token endpoint.
- # <tt>:access_token_method</tt> :: Specify the method to use for token endpoints, can be :get or :post
- # (note: for Facebook this should be :get and for Google this should be :post)
- # <tt>:access_token_url</tt> :: Specify the full URL of the access token endpoint.
- # <tt>:parse_json</tt> :: If true, <tt>application/json</tt> responses will be automatically parsed.
- # <tt>:ssl</tt> :: Specify SSL options for the connection.
- # <tt>:adapter</tt> :: The name of the Faraday::Adapter::* class to use, e.g. :net_http. To pass arguments
- # to the adapter pass an array here, e.g. [:action_dispatch, my_test_session]
- # <tt>:raise_errors</tt> :: Default true. When false it will then return the error status and response instead of raising an exception.
- def initialize(client_id, client_secret, opts={})
- self.options = opts.dup
- self.token_method = self.options.delete(:access_token_method) || :post
- adapter = self.options.delete(:adapter)
- ssl_opts = self.options.delete(:ssl) || {}
- connection_opts = ssl_opts ? {:ssl => ssl_opts} : {}
- self.id = client_id
- self.secret = client_secret
- self.site = self.options.delete(:site) if self.options[:site]
- self.connection = Faraday::Connection.new(site, connection_opts)
- self.json = self.options.delete(:parse_json)
- self.raise_errors = !(self.options.delete(:raise_errors) == false)
+ # @param [String] the OAuth2 provider site host
+ def site=(value)
+ @connection = nil
+ @site = value
+ end
- if adapter && adapter != :test
- connection.build do |b|
- b.adapter(*[adapter].flatten)
- end
+ # The Faraday connection object
+ def connection
+ @connection ||= begin
+ conn = Faraday.new(site, options[:connection_opts])
+ conn.build do |b|
+ options[:connection_build].call(b)
+ end if options[:connection_build]
+ conn
end
end
+ # The authorize endpoint URL of the OAuth2 provider
+ #
+ # @param [Hash] params additional query parameters
def authorize_url(params=nil)
- path = options[:authorize_url] || options[:authorize_path] || "/oauth/authorize"
- connection.build_url(path, params).to_s
+ connection.build_url(options[:authorize_url], params).to_s
end
- def access_token_url(params=nil)
- path = options[:access_token_url] || options[:access_token_path] || "/oauth/access_token"
- connection.build_url(path, params).to_s
+ # The token endpoint URL of the OAuth2 provider
+ #
+ # @param [Hash] params additional query parameters
+ def token_url(params=nil)
+ connection.build_url(options[:token_url], params).to_s
end
# Makes a request relative to the specified site root.
- def request(verb, url, params={}, headers={})
- if (verb == :get) || (verb == :delete)
- resp = connection.run_request(verb, url, nil, headers) do |req|
- req.params.update(params)
- end
- else
- resp = connection.run_request(verb, url, params, headers)
+ #
+ # @param [Symbol] verb one of :get, :post, :put, :delete
+ # @param [String] url URL path of request
+ # @param [Hash] opts the options to make the request with
+ # @option opts [Hash] :params additional query parameters for the URL of the request
+ # @option opts [Hash, String] :body the body of the request
+ # @option opts [Hash] :headers http request headers
+ # @option opts [Boolean] :raise_errors whether or not to raise an OAuth2::Error on 400+ status
+ # code response for this request. Will default to client option
+ # @option opts [Symbol] :parse @see Response::initialize
+ # @yield [req] The Faraday request
+ def request(verb, url, opts={})
+ url = self.connection.build_url(url, opts[:params]).to_s
+
+ response = connection.run_request(verb, url, opts[:body], opts[:headers]) do |req|
+ yield(req) if block_given?
end
+ response = Response.new(response, :parse => opts[:parse])
- if raise_errors
- case resp.status
- when 200...299
- return response_for(resp)
- when 302
- return request(verb, resp.headers['location'], params, headers)
- when 401
- e = OAuth2::AccessDenied.new("Received HTTP 401 during request.")
- e.response = resp
- raise e
- when 409
- e = OAuth2::Conflict.new("Received HTTP 409 during request.")
- e.response = resp
- raise e
- else
- e = OAuth2::HTTPError.new("Received HTTP #{resp.status} during request.")
- e.response = resp
- raise e
+ case response.status
+ when 200..299
+ response
+ when 300..399
+ opts[:redirect_count] ||= 0
+ opts[:redirect_count] += 1
+ return response if opts[:redirect_count] > options[:max_redirects]
+ if response.status == 303
+ verb = :get
+ opts.delete(:body)
end
+ request(verb, response.headers['location'], opts)
+ when 400..599
+ e = Error.new(response)
+ raise e if opts[:raise_errors] || options[:raise_errors]
+ response.error = e
+ response
else
- response_for resp
+ raise Error.new(response), "Unhandled status code value of #{response.status}"
end
end
- def json?; !!@json end
-
- def web_server; OAuth2::Strategy::WebServer.new(self) end
- def password; OAuth2::Strategy::Password.new(self) end
-
- private
-
- def response_for(resp)
- if json?
- return ResponseObject.from(resp)
+ # Initializes an AccessToken by making a request to the token endpoint
+ #
+ # @param [Hash] params a Hash of params for the token endpoint
+ # @return [AccessToken] the initalized AccessToken
+ def get_token(params)
+ opts = {:raise_errors => true, :parse => params.delete(:parse)}
+ if options[:token_method] == :post
+ opts[:body] = params
+ opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
else
- return ResponseString.new(resp)
+ opts[:params] = params
end
+ response = request(options[:token_method], token_url, opts)
+ raise Error.new(response) unless response.parsed.is_a?(Hash) && response.parsed['access_token']
+ AccessToken.from_hash(self, response.parsed)
+ end
+
+ # The Authorization Code strategy
+ #
+ # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
+ def auth_code
+ @auth_code ||= OAuth2::Strategy::AuthCode.new(self)
+ end
+
+ # The Resource Owner Password Credentials strategy
+ #
+ # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.3
+ def password
+ @password ||= OAuth2::Strategy::Password.new(self)
end
end
end