# This class manages APIs communication.
class APIClient
include Google::APIClient::Logging
-
+
##
# Creates a new Google API client.
#
# <li><code>:two_legged_oauth_1</code></li>
# <li><code>:oauth_1</code></li>
# <li><code>:oauth_2</code></li>
+ # <li><code>:google_app_default</code></li>
# </ul>
# @option options [Boolean] :auto_refresh_token (true)
# The setting that controls whether or not the api client attempts to
- # refresh authorization when a 401 is hit in #execute. If the token does
+ # refresh authorization when a 401 is hit in #execute. If the token does
# not support it, this option is ignored.
# @option options [String] :application_name
# The name of the application using the client.
+ # @option options [String | Array | nil] :scope
+ # The scope(s) used when using google application default credentials
# @option options [String] :application_version
# The version number of the application using the client.
# @option options [String] :user_agent
# Pass through of options to set on the Faraday connection
def initialize(options={})
logger.debug { "#{self.class} - Initializing client with options #{options}" }
-
+
# Normalize key to String to allow indifferent access.
options = options.inject({}) do |accu, (key, value)|
accu[key.to_sym] = value
# default authentication mechanisms.
self.authorization =
options.key?(:authorization) ? options[:authorization] : :oauth_2
+ if !options['scope'].nil? and self.authorization.respond_to?(:scope=)
+ self.authorization.scope = options['scope']
+ end
self.auto_refresh_token = options.fetch(:auto_refresh_token) { true }
self.key = options[:key]
self.user_ip = options[:user_ip]
:client_credential_secret => nil,
:two_legged => true
)
+ when :google_app_default
+ require 'googleauth'
+ new_authorization = Google::Auth.get_application_default
+
when :oauth_2
require 'signet/oauth_2/client'
# NOTE: Do not rely on this default value, as it may change
##
# The setting that controls whether or not the api client attempts to
- # refresh authorization when a 401 is hit in #execute.
+ # refresh authorization when a 401 is hit in #execute.
#
# @return [Boolean]
attr_accessor :auto_refresh_token
##
# Number of times to retry on recoverable errors
- #
+ #
# @return [FixNum]
# Number of retries
attr_accessor :retries
# Verifies an ID token against a server certificate. Used to ensure that
# an ID token supplied by an untrusted client-side mechanism is valid.
# Raises an error if the token is invalid or missing.
- #
+ #
# @deprecated Use the google-id-token gem for verifying JWTs
def verify_id_token!
require 'jwt'
else
check_cached_certs = lambda do
valid = false
- for key, cert in @certificates
+ for _key, cert in @certificates
begin
self.authorization.decoded_id_token(cert.public_key)
valid = true
# - (TrueClass, FalseClass) :authenticated (default: true) -
# `true` if the request must be signed or somehow
# authenticated, `false` otherwise.
- # - (TrueClass, FalseClass) :gzip (default: true) -
+ # - (TrueClass, FalseClass) :gzip (default: true) -
# `true` if gzip enabled, `false` otherwise.
# - (FixNum) :retries -
# # of times to retry on recoverable errors
options.update(params.shift) if params.size > 0
request = self.generate_request(options)
end
-
+
request.headers['User-Agent'] ||= '' + self.user_agent unless self.user_agent.nil?
request.headers['Accept-Encoding'] ||= 'gzip' unless options[:gzip] == false
request.headers['Content-Type'] ||= ''
connection = options[:connection] || self.connection
request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
-
+
tries = 1 + (options[:retries] || self.retries)
attempt = 0
- Retriable.retriable :tries => tries,
+ Retriable.retriable :tries => tries,
:on => [TransmissionError],
:on_retry => client_error_handler,
:interval => lambda {|attempts| (2 ** attempts) + rand} do
# This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
# auth to be re-attempted without having to retry all sorts of other failures like
# NotFound, etc
- Retriable.retriable :tries => ((expired_auth_retry || tries > 1) && attempt == 1) ? 2 : 1,
+ Retriable.retriable :tries => ((expired_auth_retry || tries > 1) && attempt == 1) ? 2 : 1,
:on => [AuthorizationError],
:on_retry => authorization_error_handler(request.authorization) do
result = request.send(connection, true)
end
return Addressable::Template.new(@base_uri + template).expand(mapping)
end
-
+
##
# Returns on proc for special processing of retries for authorization errors
# OAuth 2 credentials
# @return [Proc]
def authorization_error_handler(authorization)
- can_refresh = authorization.respond_to?(:refresh_token) && auto_refresh_token
+ can_refresh = authorization.respond_to?(:refresh_token) && auto_refresh_token
Proc.new do |exception, tries|
next unless exception.kind_of?(AuthorizationError)
if can_refresh