lib/googleauth/credentials.rb in googleauth-0.11.0 vs lib/googleauth/credentials.rb in googleauth-0.12.0
- old
+ new
@@ -45,10 +45,12 @@
##
# The default target audience ID to be used when none is provided during initialization.
AUDIENCE = "https://oauth2.googleapis.com/token".freeze
+ @audience = @scope = @target_audience = @env_vars = @paths = nil
+
##
# The default token credential URI to be used when none is provided during initialization.
# The URI is the authorization server's HTTP endpoint capable of issuing tokens and
# refreshing expired tokens.
#
@@ -95,33 +97,66 @@
##
# The default scope to be used when none is provided during initialization.
# A scope is an access range defined by the authorization server.
# The scope can be a single value or a list of values.
#
+ # Either {#scope} or {#target_audience}, but not both, should be non-nil.
+ # If {#scope} is set, this credential will produce access tokens.
+ # If {#target_audience} is set, this credential will produce ID tokens.
+ #
# @return [String, Array<String>]
#
def self.scope
return @scope unless @scope.nil?
- tmp_scope = []
- # Pull in values is the SCOPE constant exists.
- tmp_scope << const_get(:SCOPE) if const_defined? :SCOPE
- tmp_scope.flatten.uniq
+ Array(const_get(:SCOPE)).flatten.uniq if const_defined? :SCOPE
end
##
# Sets the default scope to be used when none is provided during initialization.
#
+ # Either {#scope} or {#target_audience}, but not both, should be non-nil.
+ # If {#scope} is set, this credential will produce access tokens.
+ # If {#target_audience} is set, this credential will produce ID tokens.
+ #
# @param [String, Array<String>] new_scope
# @return [String, Array<String>]
#
def self.scope= new_scope
new_scope = Array new_scope unless new_scope.nil?
@scope = new_scope
end
##
+ # The default final target audience for ID tokens, to be used when none
+ # is provided during initialization.
+ #
+ # Either {#scope} or {#target_audience}, but not both, should be non-nil.
+ # If {#scope} is set, this credential will produce access tokens.
+ # If {#target_audience} is set, this credential will produce ID tokens.
+ #
+ # @return [String]
+ #
+ def self.target_audience
+ @target_audience
+ end
+
+ ##
+ # Sets the default final target audience for ID tokens, to be used when none
+ # is provided during initialization.
+ #
+ # Either {#scope} or {#target_audience}, but not both, should be non-nil.
+ # If {#scope} is set, this credential will produce access tokens.
+ # If {#target_audience} is set, this credential will produce ID tokens.
+ #
+ # @param [String] new_target_audience
+ #
+ def self.target_audience= new_target_audience
+ @target_audience = new_target_audience
+ end
+
+ ##
# The environment variables to search for credentials. Values can either be a file path to the
# credentials file, or the JSON contents of the credentials file.
#
# @return [Array<String>]
#
@@ -183,10 +218,17 @@
#
# @return [String]
#
attr_reader :project_id
+ ##
+ # Identifier for a separate project used for billing/quota, if any.
+ #
+ # @return [String,nil]
+ #
+ attr_reader :quota_project_id
+
# @private Delegate client methods to the client object.
extend Forwardable
##
# @!attribute [r] token_credential_uri
@@ -199,10 +241,13 @@
#
# @!attribute [r] scope
# @return [String, Array<String>] The scope for this client. A scope is an access range
# defined by the authorization server. The scope can be a single value or a list of values.
#
+ # @!attribute [r] target_audience
+ # @return [String] The final target audience for ID tokens returned by this credential.
+ #
# @!attribute [r] issuer
# @return [String] The issuer ID associated with this client.
#
# @!attribute [r] signing_key
# @return [String, OpenSSL::PKey] The signing key associated with this client.
@@ -211,14 +256,12 @@
# @return [Proc] Returns a reference to the {Signet::OAuth2::Client#apply} method,
# suitable for passing as a closure.
#
def_delegators :@client,
:token_credential_uri, :audience,
- :scope, :issuer, :signing_key, :updater_proc
+ :scope, :issuer, :signing_key, :updater_proc, :target_audience
- # rubocop:disable Metrics/AbcSize
-
##
# Creates a new Credentials instance with the provided auth credentials, and with the default
# values configured on the class.
#
# @param [String, Hash, Signet::OAuth2::Client] keyfile
@@ -234,36 +277,27 @@
# * +"project_id"+ (and optionally +"project"+) - the project identifier for the client
# * +:connection_builder+ - the connection builder to use for the client
# * +:default_connection+ - the default connection to use for the client
#
def initialize keyfile, options = {}
- scope = options[:scope]
verify_keyfile_provided! keyfile
@project_id = options["project_id"] || options["project"]
+ @quota_project_id = options["quota_project_id"]
if keyfile.is_a? Signet::OAuth2::Client
- @client = keyfile
- @project_id ||= keyfile.project_id if keyfile.respond_to? :project_id
+ update_from_signet keyfile
elsif keyfile.is_a? Hash
- hash = stringify_hash_keys keyfile
- hash["scope"] ||= scope
- @client = init_client hash, options
- @project_id ||= (hash["project_id"] || hash["project"])
+ update_from_hash keyfile, options
else
- verify_keyfile_exists! keyfile
- json = JSON.parse ::File.read(keyfile)
- json["scope"] ||= scope
- @project_id ||= (json["project_id"] || json["project"])
- @client = init_client json, options
+ update_from_filepath keyfile, options
end
CredentialsLoader.warn_if_cloud_sdk_credentials @client.client_id
@project_id ||= CredentialsLoader.load_gcloud_project_id
@client.fetch_access_token!
@env_vars = nil
@paths = nil
@scope = nil
end
- # rubocop:enable Metrics/AbcSize
##
# Creates a new Credentials instance with auth credentials acquired by searching the
# environment variables and paths configured on the class, and with the default values
# configured on the class.
@@ -321,11 +355,12 @@
##
# @private Lookup Credentials using Google::Auth.get_application_default.
def self.from_application_default options
scope = options[:scope] || self.scope
- client = Google::Auth.get_application_default scope
+ auth_opts = { target_audience: options[:target_audience] || target_audience }
+ client = Google::Auth.get_application_default scope, auth_opts
new client, options
end
private_class_method :from_env_vars,
:from_default_paths,
@@ -360,16 +395,48 @@
def client_options options
# Keyfile options have higher priority over constructor defaults
options["token_credential_uri"] ||= self.class.token_credential_uri
options["audience"] ||= self.class.audience
options["scope"] ||= self.class.scope
+ options["target_audience"] ||= self.class.target_audience
+ if !Array(options["scope"]).empty? && options["target_audience"]
+ raise ArgumentError, "Cannot specify both scope and target_audience"
+ end
+
+ needs_scope = options["target_audience"].nil?
# client options for initializing signet client
{ token_credential_uri: options["token_credential_uri"],
audience: options["audience"],
- scope: Array(options["scope"]),
+ scope: (needs_scope ? Array(options["scope"]) : nil),
+ target_audience: options["target_audience"],
issuer: options["client_email"],
signing_key: OpenSSL::PKey::RSA.new(options["private_key"]) }
+ end
+
+ def update_from_signet client
+ @project_id ||= client.project_id if client.respond_to? :project_id
+ @quota_project_id ||= client.quota_project_id if client.respond_to? :quota_project_id
+ @client = client
+ end
+
+ def update_from_hash hash, options
+ hash = stringify_hash_keys hash
+ hash["scope"] ||= options[:scope]
+ hash["target_audience"] ||= options[:target_audience]
+ @project_id ||= (hash["project_id"] || hash["project"])
+ @quota_project_id ||= hash["quota_project_id"]
+ @client = init_client hash, options
+ end
+
+ def update_from_filepath path, options
+ verify_keyfile_exists! path
+ json = JSON.parse ::File.read(path)
+ json["scope"] ||= options[:scope]
+ json["target_audience"] ||= options[:target_audience]
+ @project_id ||= (json["project_id"] || json["project"])
+ @quota_project_id ||= json["quota_project_id"]
+ @client = init_client json, options
end
end
end
end