module Google::Auth::ExternalAccount::BaseCredentials

Authenticates requests using External Account credentials, such as those provided by the AWS provider or OIDC provider like Azure, etc.

Constants

EXTERNAL_ACCOUNT_JSON_TYPE

External account JSON type identifier.

IAM_SCOPE

Default IAM_SCOPE

STS_GRANT_TYPE

The token exchange grant_type used for exchanging credentials.

STS_REQUESTED_TOKEN_TYPE

The token exchange requested_token_type. This is always an access_token.

Attributes

access_token[RW]
expires_at[R]
universe_domain[RW]

Public Instance Methods

expires_at=(new_expires_at) click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 52
def expires_at= new_expires_at
  @expires_at = normalize_timestamp new_expires_at
end
expires_within?(seconds) click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 47
def expires_within? seconds
  # This method is needed for BaseClient
  @expires_at && @expires_at - Time.now.utc < seconds
end
fetch_access_token!(_options = {}) click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 56
def fetch_access_token! _options = {}
  # This method is needed for BaseClient
  response = exchange_token

  if @service_account_impersonation_url
    impersonated_response = get_impersonated_access_token response["access_token"]
    self.expires_at = impersonated_response["expireTime"]
    self.access_token = impersonated_response["accessToken"]
  else
    # Extract the expiration time in seconds from the response and calculate the actual expiration time
    # and then save that to the expiry variable.
    self.expires_at = Time.now.utc + response["expires_in"].to_i
    self.access_token = response["access_token"]
  end

  notify_refresh_listeners
end
is_workforce_pool?() click to toggle source

Returns whether the credentials represent a workforce pool (True) or workload (False) based on the credentials’ audience.

@return [bool]

true if the credentials represent a workforce pool.
false if they represent a workload.
# File lib/googleauth/external_account/base_credentials.rb, line 88
def is_workforce_pool?
  %r{/iam\.googleapis\.com/locations/[^/]+/workforcePools/}.match?(@audience || "")
end
retrieve_subject_token!() click to toggle source

Retrieves the subject token using the credential_source object. @return [string]

The retrieved subject token.
# File lib/googleauth/external_account/base_credentials.rb, line 78
def retrieve_subject_token!
  raise NoMethodError, "retrieve_subject_token! not implemented"
end

Private Instance Methods

base_setup(options) click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 99
def base_setup options
  self.default_connection = options[:connection]

  @audience = options[:audience]
  @scope = options[:scope] || IAM_SCOPE
  @subject_token_type = options[:subject_token_type]
  @token_url = options[:token_url]
  @token_info_url = options[:token_info_url]
  @service_account_impersonation_url = options[:service_account_impersonation_url]
  @service_account_impersonation_options = options[:service_account_impersonation_options] || {}
  @client_id = options[:client_id]
  @client_secret = options[:client_secret]
  @quota_project_id = options[:quota_project_id]
  @project_id = nil
  @workforce_pool_user_project = options[:workforce_pool_user_project]
  @universe_domain = options[:universe_domain] || "googleapis.com"

  @expires_at = nil
  @access_token = nil

  @sts_client = Google::Auth::OAuth2::STSClient.new(
    token_exchange_endpoint: @token_url,
    connection: default_connection
  )
  return unless @workforce_pool_user_project && !is_workforce_pool?
  raise "workforce_pool_user_project should not be set for non-workforce pool credentials."
end
exchange_token() click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 127
def exchange_token
  additional_options = nil
  if @client_id.nil? && @workforce_pool_user_project
    additional_options = { userProject: @workforce_pool_user_project }
  end
  @sts_client.exchange_token(
    audience: @audience,
    grant_type: STS_GRANT_TYPE,
    subject_token: retrieve_subject_token!,
    subject_token_type: @subject_token_type,
    scopes: @service_account_impersonation_url ? IAM_SCOPE : @scope,
    requested_token_type: STS_REQUESTED_TOKEN_TYPE,
    additional_options: additional_options
  )
end
get_impersonated_access_token(token, _options = {}) click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 143
def get_impersonated_access_token token, _options = {}
  response = connection.post @service_account_impersonation_url do |req|
    req.headers["Authorization"] = "Bearer #{token}"
    req.headers["Content-Type"] = "application/json"
    req.body = MultiJson.dump({ scope: @scope })
  end

  if response.status != 200
    raise "Service account impersonation failed with status #{response.status}"
  end

  MultiJson.load response.body
end
token_type() click to toggle source
# File lib/googleauth/external_account/base_credentials.rb, line 94
def token_type
  # This method is needed for BaseClient
  :access_token
end