Class: Google::Auth::ServiceAccountCredentials

Inherits:
Signet::OAuth2::Client show all
Extended by:
CredentialsLoader, JsonKeyReader
Defined in:
lib/googleauth/service_account.rb

Overview

Authenticates requests using Google's Service Account credentials via an OAuth access token.

This class allows authorizing requests for service accounts directly from credentials from a json key file downloaded from the developer console (via 'Generate new Json Key').

cf Application Default Credentials

Constant Summary collapse

TOKEN_CRED_URI =
"https://www.googleapis.com/oauth2/v4/token".freeze

Constants included from CredentialsLoader

CredentialsLoader::ACCOUNT_TYPE_VAR, CredentialsLoader::AWS_ACCESS_KEY_ID_VAR, CredentialsLoader::AWS_DEFAULT_REGION_VAR, CredentialsLoader::AWS_REGION_VAR, CredentialsLoader::AWS_SECRET_ACCESS_KEY_VAR, CredentialsLoader::AWS_SESSION_TOKEN_VAR, CredentialsLoader::CLIENT_EMAIL_VAR, CredentialsLoader::CLIENT_ID_VAR, CredentialsLoader::CLIENT_SECRET_VAR, CredentialsLoader::CLOUD_SDK_CLIENT_ID, CredentialsLoader::CREDENTIALS_FILE_NAME, CredentialsLoader::ENV_VAR, CredentialsLoader::GCLOUD_CONFIG_COMMAND, CredentialsLoader::GCLOUD_POSIX_COMMAND, CredentialsLoader::GCLOUD_WINDOWS_COMMAND, CredentialsLoader::NOT_FOUND_ERROR, CredentialsLoader::PRIVATE_KEY_VAR, CredentialsLoader::PROJECT_ID_VAR, CredentialsLoader::REFRESH_TOKEN_VAR, CredentialsLoader::SYSTEM_DEFAULT_ERROR, CredentialsLoader::WELL_KNOWN_ERROR, CredentialsLoader::WELL_KNOWN_PATH

Constants included from BaseClient

BaseClient::AUTH_METADATA_KEY

Instance Attribute Summary collapse

Attributes inherited from Signet::OAuth2::Client

#universe_domain

Attributes included from BaseClient

#logger

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CredentialsLoader

authorized_user_env_vars?, from_env, from_system_default_path, from_well_known_path, interpret_options, load_gcloud_project_id, make_creds, service_account_env_vars?

Methods included from JsonKeyReader

read_json_key

Methods inherited from Signet::OAuth2::Client

#build_default_connection, #configure_connection, #fetch_access_token!, #generate_access_token_request, #googleauth_orig_generate_access_token_request, #orig_fetch_access_token!, #retry_with_error, #token_type, #update_signet_base, #update_token!, #update_token_signet_base

Methods included from BaseClient

#apply, #expires_within?, #notify_refresh_listeners, #on_refresh, #updater_proc

Constructor Details

#initialize(options = {}) ⇒ ServiceAccountCredentials

Returns a new instance of ServiceAccountCredentials.



163
164
165
166
167
168
# File 'lib/googleauth/service_account.rb', line 163

def initialize options = {}
  @project_id = options[:project_id]
  @quota_project_id = options[:quota_project_id]
  @enable_self_signed_jwt = options[:enable_self_signed_jwt] ? true : false
  super options
end

Instance Attribute Details

#project_idObject (readonly)

Returns the value of attribute project_id.



41
42
43
# File 'lib/googleauth/service_account.rb', line 41

def project_id
  @project_id
end

#quota_project_idObject (readonly)

Returns the value of attribute quota_project_id.



42
43
44
# File 'lib/googleauth/service_account.rb', line 42

def quota_project_id
  @quota_project_id
end

Class Method Details

.make_creds(options = {}) ⇒ Object

Creates a ServiceAccountCredentials.

Parameters:

  • json_key_io (IO, nil)

    Optional. An IO object containing the JSON key

  • scope (String, Array<String>, nil)

    Optional. The scope(s) to access

  • enable_self_signed_jwt (Boolean, nil)

    Optional. Whether to use self-signed JWTs

  • target_audience (String, nil)

    Optional. The target audience for ID token requests

  • audience (String, nil)

    Optional. Custom token endpoint audience URI

  • token_credential_uri (String, nil)

    Optional. Custom token credential URI

  • default_connection (Faraday::Connection, nil)

    Optional. The connection object to use

  • connection_builder (Proc, nil)

    Optional. A Proc that returns a Faraday connection

Raises:

  • (ArgumentError)

    If both scope and target_audience are specified

  • (InitializationError)

    If json_key_io is not an IO object, or if required credential fields (private_key or client_email) are missing



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/googleauth/service_account.rb', line 82

def self.make_creds options = {} # rubocop:disable Metrics/MethodLength
  validate_make_creds_options options

  json_key_io, scope, enable_self_signed_jwt, target_audience, audience, token_credential_uri =
    options.values_at :json_key_io, :scope, :enable_self_signed_jwt, :target_audience,
                      :audience, :token_credential_uri
  raise ArgumentError, "Cannot specify both scope and target_audience" if scope && target_audience

  private_key, client_email, project_id, quota_project_id, universe_domain =
    if json_key_io
      unless json_key_io.respond_to? :read
        raise InitializationError, "Expected an IO object for json_key_io"
      end
      json_key = JSON.parse json_key_io.read
      if json_key.key? "type"
        json_key_io.rewind
      else # Defaults to class credential 'type' if missing.
        json_key["type"] = CREDENTIAL_TYPE_NAME
        json_key_io = StringIO.new JSON.generate(json_key)
      end
      CredentialsLoader.load_and_verify_json_key_type json_key_io, CREDENTIAL_TYPE_NAME
      read_json_key json_key_io
    else
      creds_from_env
    end

  raise InitializationError, "Missing required field: private_key" unless private_key
  raise InitializationError, "Missing required field: client_email" unless client_email

  project_id ||= CredentialsLoader.load_gcloud_project_id

  new(token_credential_uri:   token_credential_uri || TOKEN_CRED_URI,
      audience:               audience || TOKEN_CRED_URI,
      scope:                  scope,
      enable_self_signed_jwt: enable_self_signed_jwt,
      target_audience:        target_audience,
      issuer:                 client_email,
      signing_key:            OpenSSL::PKey::RSA.new(private_key),
      project_id:             project_id,
      quota_project_id:       quota_project_id,
      universe_domain:        universe_domain || "googleapis.com")
    .configure_connection(options)
end

.unescape(str) ⇒ String?

Handles certain escape sequences that sometimes appear in input. Specifically, interprets the "\n" sequence for newline, and removes enclosing quotes.

Parameters:

  • str (String)

    The string to unescape

Returns:

  • (String, nil)

    The unescaped string, or nil if input is nil



156
157
158
159
160
161
# File 'lib/googleauth/service_account.rb', line 156

def self.unescape str
  return nil unless str
  str = str.gsub '\n', "\n"
  str = str[1..-2] if str.start_with?('"') && str.end_with?('"')
  str
end

Instance Method Details

#apply!(a_hash, opts = {}) ⇒ Object

Extends the base class to use a transient ServiceAccountJwtHeaderCredentials for certain cases.



172
173
174
175
176
177
178
# File 'lib/googleauth/service_account.rb', line 172

def apply! a_hash, opts = {}
  if enable_self_signed_jwt?
    apply_self_signed_jwt! a_hash
  else
    super
  end
end

#duplicate(options = {}) ⇒ Object

Creates a duplicate of these credentials without the Signet::OAuth2::Client-specific transient state (e.g. cached tokens)

Parameters:

  • options (Hash) (defaults to: {})

    Overrides for the credentials parameters. The following keys are recognized in addition to keys in the Signet::OAuth2::Client

    • :enable_self_signed_jwt Whether the self-signed JWT should be used for the authentication
    • project_id the project id to use during the authentication
    • quota_project_id the quota project id to use during the authentication


138
139
140
141
142
143
144
145
146
147
148
# File 'lib/googleauth/service_account.rb', line 138

def duplicate options = {}
  options = deep_hash_normalize options
  super(
    {
      enable_self_signed_jwt: @enable_self_signed_jwt,
      project_id: project_id,
      quota_project_id: quota_project_id,
      logger: logger
    }.merge(options)
  )
end

#enable_self_signed_jwt?Boolean

Returns:

  • (Boolean)


61
62
63
64
65
66
67
# File 'lib/googleauth/service_account.rb', line 61

def enable_self_signed_jwt?
  # Use a self-singed JWT if there's no information that can be used to
  # obtain an OAuth token, OR if there are scopes but also an assertion
  # that they are default scopes that shouldn't be used to fetch a token,
  # OR we are not in the default universe and thus OAuth isn't supported.
  target_audience.nil? && (scope.nil? || @enable_self_signed_jwt || universe_domain != "googleapis.com")
end

#needs_access_token?Boolean

Modifies this logic so it also requires self-signed-jwt to be disabled

Returns:

  • (Boolean)


181
182
183
# File 'lib/googleauth/service_account.rb', line 181

def needs_access_token?
  super && !enable_self_signed_jwt?
end

#update!(options = {}) ⇒ Google::Auth::ServiceAccountCredentials

Destructively updates these credentials

This method is called by Signet::OAuth2::Client's constructor

Parameters:

  • options (Hash) (defaults to: {})

    Overrides for the credentials parameters. The following keys are recognized in addition to keys in the Signet::OAuth2::Client

    • :enable_self_signed_jwt Whether the self-signed JWT should be used for the authentication
    • project_id the project id to use during the authentication
    • quota_project_id the quota project id to use during the authentication

Returns:



198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/googleauth/service_account.rb', line 198

def update! options = {}
  # Normalize all keys to symbols to allow indifferent access.
  options = deep_hash_normalize options

  @enable_self_signed_jwt = options[:enable_self_signed_jwt] ? true : false
  @project_id = options[:project_id] if options.key? :project_id
  @quota_project_id = options[:quota_project_id] if options.key? :quota_project_id

  super(options)

  self
end