googleauth 1.12.2 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +10 -1
- data/lib/googleauth/api_key.rb +155 -0
- data/lib/googleauth/bearer_token.rb +148 -0
- data/lib/googleauth/compute_engine.rb +40 -1
- data/lib/googleauth/credentials.rb +107 -25
- data/lib/googleauth/credentials_loader.rb +2 -2
- data/lib/googleauth/default_credentials.rb +13 -2
- data/lib/googleauth/helpers/connection.rb +7 -1
- data/lib/googleauth/impersonated_service_account.rb +282 -0
- data/lib/googleauth/service_account.rb +55 -113
- data/lib/googleauth/service_account_jwt_header.rb +180 -0
- data/lib/googleauth/signet.rb +52 -0
- data/lib/googleauth/user_refresh.rb +43 -0
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth.rb +7 -0
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e2eef22c1062f2fd2216760e90a1af9ece1b99838bccea486a7b4ce43be9734
|
4
|
+
data.tar.gz: 1e60ef4856de1e4f7a3d423f3953e5e39f86c7002216ad2d98ee46ec88aaaf25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5a87f962d04eb59c9ae083a4d3c46fd54ef4d4c53f0571b3952f6d1a9d30e3af89fb2c50e04b118e301097850c9985c713968dc29c62c5d388d0d8a4c3d306d
|
7
|
+
data.tar.gz: fae67434766ed2d4bb67e2c7ba2784a9397843110c28d96368d368b1dd30229a1ea83c5ee05e70a712446781e67ca84149fbaa72dd4239eb349d6943ff42b9b3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 1.14.0 (2025-03-14)
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* add API key credentials ([#520](https://github.com/googleapis/google-auth-library-ruby/issues/520))
|
8
|
+
* Add Bearer token credentials
|
9
|
+
* add BearerToken credentials ([#522](https://github.com/googleapis/google-auth-library-ruby/issues/522))
|
10
|
+
* Update minimum Ruby version to 3.0 ([#527](https://github.com/googleapis/google-auth-library-ruby/issues/527))
|
11
|
+
#### Bug Fixes
|
12
|
+
|
13
|
+
* Eliminated the "attribute accessor as module_function" warning ([#519](https://github.com/googleapis/google-auth-library-ruby/issues/519))
|
14
|
+
* Get the project_id from gcloud ([#479](https://github.com/googleapis/google-auth-library-ruby/issues/479))
|
15
|
+
* logger configuration in service account JWT header ([#525](https://github.com/googleapis/google-auth-library-ruby/issues/525))
|
16
|
+
|
17
|
+
### 1.13.1 (2025-01-24)
|
18
|
+
|
19
|
+
#### Bug Fixes
|
20
|
+
|
21
|
+
* Signet client subclasses no longer make the update! method private ([#516](https://github.com/googleapis/google-auth-library-ruby/issues/516))
|
22
|
+
|
23
|
+
### 1.13.0 (2025-01-22)
|
24
|
+
|
25
|
+
#### Features
|
26
|
+
|
27
|
+
* create impersonated service credentials ([#499](https://github.com/googleapis/google-auth-library-ruby/issues/499))
|
28
|
+
#### Documentation
|
29
|
+
|
30
|
+
* Include note about validating externally-provided credentials ([#512](https://github.com/googleapis/google-auth-library-ruby/issues/512))
|
31
|
+
|
3
32
|
### 1.12.2 (2024-12-19)
|
4
33
|
|
5
34
|
#### Bug Fixes
|
data/README.md
CHANGED
@@ -64,6 +64,15 @@ well as a web variant tailored toward Rack-based applications.
|
|
64
64
|
The authorizers are intended for authorization use cases. For sign-on,
|
65
65
|
see [Google Identity Platform](https://developers.google.com/identity/)
|
66
66
|
|
67
|
+
## Important notes
|
68
|
+
|
69
|
+
If you accept a credential configuration (credential JSON/File/Stream) from an
|
70
|
+
external source for authentication to Google Cloud, you must validate it before
|
71
|
+
providing it to any Google API or library. Providing an unvalidated credential
|
72
|
+
configuration to Google APIs can compromise the security of your systems and data.
|
73
|
+
For more information, refer to [Validate credential configurations from external
|
74
|
+
sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
|
75
|
+
|
67
76
|
### Example (Web)
|
68
77
|
|
69
78
|
```ruby
|
@@ -256,7 +265,7 @@ Custom storage implementations can also be used. See
|
|
256
265
|
|
257
266
|
## Supported Ruby Versions
|
258
267
|
|
259
|
-
This library is supported on Ruby
|
268
|
+
This library is supported on Ruby 3.0+.
|
260
269
|
|
261
270
|
Google provides official support for Ruby versions that are actively supported
|
262
271
|
by Ruby Core—that is, Ruby versions that are either in normal maintenance or
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# Copyright 2025 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "googleauth/base_client"
|
16
|
+
require "googleauth/credentials_loader"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Auth
|
20
|
+
##
|
21
|
+
# Implementation of Google API Key authentication.
|
22
|
+
#
|
23
|
+
# API Keys are text strings. They don't have an associated JSON file.
|
24
|
+
#
|
25
|
+
# The end-user is managing their API Keys directly, not via
|
26
|
+
# an authentication library.
|
27
|
+
#
|
28
|
+
# API Keys provide project information for an API request.
|
29
|
+
# API Keys don't reference an IAM principal, they do not expire,
|
30
|
+
# and cannot be refreshed.
|
31
|
+
#
|
32
|
+
class APIKeyCredentials
|
33
|
+
include Google::Auth::BaseClient
|
34
|
+
|
35
|
+
# @private Authorization header key
|
36
|
+
API_KEY_HEADER = "x-goog-api-key".freeze
|
37
|
+
|
38
|
+
# @private Environment variable containing API key
|
39
|
+
API_KEY_VAR = "GOOGLE_API_KEY".freeze
|
40
|
+
|
41
|
+
# @return [String] The API key
|
42
|
+
attr_reader :api_key
|
43
|
+
|
44
|
+
# @return [String] The universe domain of the universe
|
45
|
+
# this API key is for
|
46
|
+
attr_accessor :universe_domain
|
47
|
+
|
48
|
+
class << self
|
49
|
+
# Creates an APIKeyCredentials from the environment.
|
50
|
+
# Checks the ENV['GOOGLE_API_KEY'] variable.
|
51
|
+
#
|
52
|
+
# @param [String] _scope
|
53
|
+
# The scope to use for OAuth. Not used by API key auth.
|
54
|
+
# @param [Hash] options
|
55
|
+
# The options to pass to the credentials instance
|
56
|
+
#
|
57
|
+
# @return [Google::Auth::APIKeyCredentials, nil]
|
58
|
+
# Credentials if the API key environment variable is present,
|
59
|
+
# nil otherwise
|
60
|
+
def from_env _scope = nil, options = {}
|
61
|
+
api_key = ENV[API_KEY_VAR]
|
62
|
+
return nil if api_key.nil? || api_key.empty?
|
63
|
+
new options.merge(api_key: api_key)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create the APIKeyCredentials.
|
67
|
+
#
|
68
|
+
# @param [Hash] options The credentials options
|
69
|
+
# @option options [String] :api_key
|
70
|
+
# The API key to use for authentication
|
71
|
+
# @option options [String] :universe_domain
|
72
|
+
# The universe domain of the universe this API key
|
73
|
+
# belongs to (defaults to googleapis.com)
|
74
|
+
# @return [Google::Auth::APIKeyCredentials]
|
75
|
+
def make_creds options = {}
|
76
|
+
new options
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Initialize the APIKeyCredentials.
|
81
|
+
#
|
82
|
+
# @param [Hash] options The credentials options
|
83
|
+
# @option options [String] :api_key
|
84
|
+
# The API key to use for authentication
|
85
|
+
# @option options [String] :universe_domain
|
86
|
+
# The universe domain of the universe this API key
|
87
|
+
# belongs to (defaults to googleapis.com)
|
88
|
+
def initialize options = {}
|
89
|
+
raise ArgumentError, "API key must be provided" if options[:api_key].nil? || options[:api_key].empty?
|
90
|
+
@api_key = options[:api_key]
|
91
|
+
@universe_domain = options[:universe_domain] || "googleapis.com"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Determines if the credentials object has expired.
|
95
|
+
# Since API keys don't expire, this always returns false.
|
96
|
+
#
|
97
|
+
# @param [Fixnum] _seconds
|
98
|
+
# The optional timeout in seconds since the last refresh
|
99
|
+
# @return [Boolean]
|
100
|
+
# True if the token has expired, false otherwise.
|
101
|
+
def expires_within? _seconds
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
105
|
+
# Creates a duplicate of these credentials.
|
106
|
+
#
|
107
|
+
# @param [Hash] options Additional options for configuring the credentials
|
108
|
+
# @return [Google::Auth::APIKeyCredentials]
|
109
|
+
def duplicate options = {}
|
110
|
+
self.class.new(
|
111
|
+
api_key: options[:api_key] || @api_key,
|
112
|
+
universe_domain: options[:universe_domain] || @universe_domain
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Updates the provided hash with the API Key header.
|
117
|
+
#
|
118
|
+
# The `apply!` method modifies the provided hash in place, adding the
|
119
|
+
# `x-goog-api-key` header with the API Key value.
|
120
|
+
#
|
121
|
+
# The API Key is hashed before being logged for security purposes.
|
122
|
+
#
|
123
|
+
# NB: this method typically would be called through `updater_proc`.
|
124
|
+
# Some older clients call it directly though, so it has to be public.
|
125
|
+
#
|
126
|
+
# @param [Hash] a_hash The hash to which the API Key header should be added.
|
127
|
+
# This is typically a hash representing the request headers. This hash
|
128
|
+
# will be modified in place.
|
129
|
+
# @param [Hash] _opts Additional options (currently not used). Included
|
130
|
+
# for consistency with the `BaseClient` interface.
|
131
|
+
# @return [Hash] The modified hash (the same hash passed as the `a_hash`
|
132
|
+
# argument).
|
133
|
+
def apply! a_hash, _opts = {}
|
134
|
+
a_hash[API_KEY_HEADER] = @api_key
|
135
|
+
logger&.debug do
|
136
|
+
hash = Digest::SHA256.hexdigest @api_key
|
137
|
+
Google::Logging::Message.from message: "Sending API key auth token. (sha256:#{hash})"
|
138
|
+
end
|
139
|
+
a_hash
|
140
|
+
end
|
141
|
+
|
142
|
+
protected
|
143
|
+
|
144
|
+
# The token type should be :api_key
|
145
|
+
def token_type
|
146
|
+
:api_key
|
147
|
+
end
|
148
|
+
|
149
|
+
# We don't need to fetch access tokens for API key auth
|
150
|
+
def fetch_access_token! _options = {}
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# Copyright 2025 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "googleauth/base_client"
|
16
|
+
|
17
|
+
module Google
|
18
|
+
module Auth
|
19
|
+
##
|
20
|
+
# Implementation of Bearer Token authentication scenario.
|
21
|
+
#
|
22
|
+
# Bearer tokens are strings representing an authorization grant.
|
23
|
+
# They can be OAuth2 ("ya.29") tokens, JWTs, IDTokens -- anything
|
24
|
+
# that is sent as a `Bearer` in an `Authorization` header.
|
25
|
+
#
|
26
|
+
# Not all 'authentication' strings can be used with this class,
|
27
|
+
# e.g. an API key cannot since API keys are sent in a
|
28
|
+
# `x-goog-api-key` header or as a query parameter.
|
29
|
+
#
|
30
|
+
# This class should be used when the end-user is managing the
|
31
|
+
# authentication token separately, e.g. with a separate service.
|
32
|
+
# This means that tasks like tracking the lifetime of and
|
33
|
+
# refreshing the token are outside the scope of this class.
|
34
|
+
#
|
35
|
+
# There is no JSON representation for this type of credentials.
|
36
|
+
# If the end-user has credentials in JSON format they should typically
|
37
|
+
# use the corresponding credentials type, e.g. ServiceAccountCredentials
|
38
|
+
# with the service account JSON.
|
39
|
+
#
|
40
|
+
class BearerTokenCredentials
|
41
|
+
include Google::Auth::BaseClient
|
42
|
+
|
43
|
+
# @private Authorization header name
|
44
|
+
AUTH_METADATA_KEY = Google::Auth::BaseClient::AUTH_METADATA_KEY
|
45
|
+
|
46
|
+
# @return [String] The token to be sent as a part of Bearer claim
|
47
|
+
attr_reader :token
|
48
|
+
# The following aliasing is needed for BaseClient since it sends :token_type
|
49
|
+
alias bearer_token token
|
50
|
+
|
51
|
+
# @return [Time, nil] The token expiration time provided by the end-user.
|
52
|
+
attr_reader :expires_at
|
53
|
+
|
54
|
+
# @return [String] The universe domain of the universe
|
55
|
+
# this token is for
|
56
|
+
attr_accessor :universe_domain
|
57
|
+
|
58
|
+
class << self
|
59
|
+
# Create the BearerTokenCredentials.
|
60
|
+
#
|
61
|
+
# @param [Hash] options The credentials options
|
62
|
+
# @option options [String] :token The bearer token to use.
|
63
|
+
# @option options [Time, Numeric, nil] :expires_at The token expiration time provided by the end-user.
|
64
|
+
# Optional, for the end-user's convenience. Can be a Time object, a number of seconds since epoch.
|
65
|
+
# If `expires_at` is `nil`, it is treated as "token never expires".
|
66
|
+
# @option options [String] :universe_domain The universe domain of the universe
|
67
|
+
# this token is for (defaults to googleapis.com)
|
68
|
+
# @return [Google::Auth::BearerTokenCredentials]
|
69
|
+
def make_creds options = {}
|
70
|
+
new options
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Initialize the BearerTokenCredentials.
|
75
|
+
#
|
76
|
+
# @param [Hash] options The credentials options
|
77
|
+
# @option options [String] :token The bearer token to use.
|
78
|
+
# @option options [Time, Numeric, nil] :expires_at The token expiration time provided by the end-user.
|
79
|
+
# Optional, for the end-user's convenience. Can be a Time object, a number of seconds since epoch.
|
80
|
+
# If `expires_at` is `nil`, it is treated as "token never expires".
|
81
|
+
# @option options [String] :universe_domain The universe domain of the universe
|
82
|
+
# this token is for (defaults to googleapis.com)
|
83
|
+
def initialize options = {}
|
84
|
+
raise ArgumentError, "Bearer token must be provided" if options[:token].nil? || options[:token].empty?
|
85
|
+
@token = options[:token]
|
86
|
+
@expires_at = case options[:expires_at]
|
87
|
+
when Time
|
88
|
+
options[:expires_at]
|
89
|
+
when Numeric
|
90
|
+
Time.at options[:expires_at]
|
91
|
+
end
|
92
|
+
|
93
|
+
@universe_domain = options[:universe_domain] || "googleapis.com"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Determines if the credentials object has expired.
|
97
|
+
#
|
98
|
+
# @param [Numeric] seconds The optional timeout in seconds.
|
99
|
+
# @return [Boolean] True if the token has expired, false otherwise, or
|
100
|
+
# if the expires_at was not provided.
|
101
|
+
def expires_within? seconds
|
102
|
+
return false if @expires_at.nil? # Treat nil expiration as "never expires"
|
103
|
+
Time.now + seconds >= @expires_at
|
104
|
+
end
|
105
|
+
|
106
|
+
# Creates a duplicate of these credentials.
|
107
|
+
#
|
108
|
+
# @param [Hash] options Additional options for configuring the credentials
|
109
|
+
# @option options [String] :token The bearer token to use.
|
110
|
+
# @option options [Time, Numeric] :expires_at The token expiration time. Can be a Time
|
111
|
+
# object or a number of seconds since epoch.
|
112
|
+
# @option options [String] :universe_domain The universe domain (defaults to googleapis.com)
|
113
|
+
# @return [Google::Auth::BearerTokenCredentials]
|
114
|
+
def duplicate options = {}
|
115
|
+
self.class.new(
|
116
|
+
token: options[:token] || @token,
|
117
|
+
expires_at: options[:expires_at] || @expires_at,
|
118
|
+
universe_domain: options[:universe_domain] || @universe_domain
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
##
|
125
|
+
# BearerTokenCredentials do not support fetching a new token.
|
126
|
+
#
|
127
|
+
# If the token has an expiration time and is expired, this method will
|
128
|
+
# raise an error.
|
129
|
+
#
|
130
|
+
# @param [Hash] _options Options for fetching a new token (not used).
|
131
|
+
# @return [nil] Always returns nil.
|
132
|
+
# @raise [StandardError] If the token is expired.
|
133
|
+
def fetch_access_token! _options = {}
|
134
|
+
if @expires_at && Time.now >= @expires_at
|
135
|
+
raise "Bearer token has expired."
|
136
|
+
end
|
137
|
+
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def token_type
|
144
|
+
:bearer_token
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -87,12 +87,30 @@ module Google
|
|
87
87
|
def initialize options = {}
|
88
88
|
# Override the constructor to remember whether the universe domain was
|
89
89
|
# overridden by a constructor argument.
|
90
|
-
@universe_domain_overridden = options["universe_domain"] || options[:universe_domain]
|
90
|
+
@universe_domain_overridden = options["universe_domain"] || options[:universe_domain]
|
91
91
|
# TODO: Remove when universe domain metadata endpoint is stable (see b/349488459).
|
92
92
|
@disable_universe_domain_check = true
|
93
93
|
super options
|
94
94
|
end
|
95
95
|
|
96
|
+
# Creates a duplicate of these credentials
|
97
|
+
# without the Signet::OAuth2::Client-specific
|
98
|
+
# transient state (e.g. cached tokens)
|
99
|
+
#
|
100
|
+
# @param options [Hash] Overrides for the credentials parameters.
|
101
|
+
# The following keys are recognized in addition to keys in the
|
102
|
+
# Signet::OAuth2::Client
|
103
|
+
# * `:universe_domain_overridden` Whether the universe domain was
|
104
|
+
# overriden during credentials creation
|
105
|
+
def duplicate options = {}
|
106
|
+
options = deep_hash_normalize options
|
107
|
+
super(
|
108
|
+
{
|
109
|
+
universe_domain_overridden: @universe_domain_overridden
|
110
|
+
}.merge(options)
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
96
114
|
# @private
|
97
115
|
# Overrides universe_domain getter to fetch lazily if it hasn't been
|
98
116
|
# fetched yet. This is necessary specifically for Compute Engine because
|
@@ -136,6 +154,27 @@ module Google
|
|
136
154
|
end
|
137
155
|
end
|
138
156
|
|
157
|
+
# Destructively updates these credentials.
|
158
|
+
#
|
159
|
+
# This method is called by `Signet::OAuth2::Client`'s constructor
|
160
|
+
#
|
161
|
+
# @param options [Hash] Overrides for the credentials parameters.
|
162
|
+
# The following keys are recognized in addition to keys in the
|
163
|
+
# Signet::OAuth2::Client
|
164
|
+
# * `:universe_domain_overridden` Whether the universe domain was
|
165
|
+
# overriden during credentials creation
|
166
|
+
# @return [Google::Auth::GCECredentials]
|
167
|
+
def update! options = {}
|
168
|
+
# Normalize all keys to symbols to allow indifferent access.
|
169
|
+
options = deep_hash_normalize options
|
170
|
+
|
171
|
+
@universe_domain_overridden = options[:universe_domain_overridden] if options.key? :universe_domain_overridden
|
172
|
+
|
173
|
+
super(options)
|
174
|
+
|
175
|
+
self
|
176
|
+
end
|
177
|
+
|
139
178
|
private
|
140
179
|
|
141
180
|
def log_fetch_query
|
@@ -26,6 +26,14 @@ module Google
|
|
26
26
|
# In most cases, it is subclassed by API-specific credential classes that
|
27
27
|
# can be instantiated by clients.
|
28
28
|
#
|
29
|
+
# **Important:** If you accept a credential configuration (credential
|
30
|
+
# JSON/File/Stream) from an external source for authentication to Google
|
31
|
+
# Cloud, you must validate it before providing it to any Google API or
|
32
|
+
# library. Providing an unvalidated credential configuration to Google APIs
|
33
|
+
# can compromise the security of your systems and data. For more
|
34
|
+
# information, refer to [Validate credential configurations from external
|
35
|
+
# sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
|
36
|
+
#
|
29
37
|
# ## Options
|
30
38
|
#
|
31
39
|
# Credentials classes are configured with options that dictate default
|
@@ -321,9 +329,6 @@ module Google
|
|
321
329
|
# @return [String, Array<String>] The scope for this client. A scope is an access range
|
322
330
|
# defined by the authorization server. The scope can be a single value or a list of values.
|
323
331
|
#
|
324
|
-
# @!attribute [r] target_audience
|
325
|
-
# @return [String] The final target audience for ID tokens returned by this credential.
|
326
|
-
#
|
327
332
|
# @!attribute [r] issuer
|
328
333
|
# @return [String] The issuer ID associated with this client.
|
329
334
|
#
|
@@ -334,6 +339,9 @@ module Google
|
|
334
339
|
# @return [Proc] Returns a reference to the {Signet::OAuth2::Client#apply} method,
|
335
340
|
# suitable for passing as a closure.
|
336
341
|
#
|
342
|
+
# @!attribute [r] target_audience
|
343
|
+
# @return [String] The final target audience for ID tokens returned by this credential.
|
344
|
+
#
|
337
345
|
# @!attribute [rw] universe_domain
|
338
346
|
# @return [String] The universe domain issuing these credentials.
|
339
347
|
#
|
@@ -349,33 +357,53 @@ module Google
|
|
349
357
|
# Creates a new Credentials instance with the provided auth credentials, and with the default
|
350
358
|
# values configured on the class.
|
351
359
|
#
|
352
|
-
# @param [String, Hash, Signet::OAuth2::Client]
|
353
|
-
# The
|
360
|
+
# @param [String, Hash, Signet::OAuth2::Client] source_creds
|
361
|
+
# The source of credentials. It can be provided as one of the following:
|
354
362
|
#
|
355
363
|
# * The path to a JSON keyfile (as a `String`)
|
356
364
|
# * The contents of a JSON keyfile (as a `Hash`)
|
357
|
-
# * A `Signet::OAuth2::Client` object
|
365
|
+
# * A `Signet::OAuth2::Client` credentials object
|
366
|
+
# * Any credentials object that supports the methods this wrapper delegates to an inner client.
|
367
|
+
#
|
368
|
+
# If this parameter is an object (`Signet::OAuth2::Client` or other) it will be used as an inner client.
|
369
|
+
# Otherwise the inner client will be constructed from the JSON keyfile or the contens of the hash.
|
370
|
+
#
|
358
371
|
# @param [Hash] options
|
359
|
-
# The options for configuring
|
372
|
+
# The options for configuring this wrapper credentials object and the inner client.
|
373
|
+
# The options hash is used in two ways:
|
360
374
|
#
|
361
|
-
#
|
362
|
-
#
|
363
|
-
# * `:connection_builder` - the connection builder to use for the client
|
364
|
-
# * `:default_connection` - the default connection to use for the client
|
365
|
-
# * `:logger` - the logger used to log credential operations such as token refresh.
|
375
|
+
# 1. **Configuring the wrapper object:** Some options are used to directly
|
376
|
+
# configure the wrapper `Credentials` instance. These include:
|
366
377
|
#
|
367
|
-
|
368
|
-
|
378
|
+
# * `:project_id` (and optionally `:project`) - the project identifier for the client
|
379
|
+
# * `:quota_project_id` - the quota project identifier for the client
|
380
|
+
# * `:logger` - the logger used to log credential operations such as token refresh.
|
381
|
+
#
|
382
|
+
# 2. **Configuring the inner client:** When the `source_creds` parameter
|
383
|
+
# is a `String` or `Hash`, a new `Signet::OAuth2::Client` is created
|
384
|
+
# internally. The following options are used to configure this inner client:
|
385
|
+
#
|
386
|
+
# * `:scope` - the scope for the client
|
387
|
+
# * `:target_audience` - the target audience for the client
|
388
|
+
#
|
389
|
+
# Any other options in the `options` hash are passed directly to the
|
390
|
+
# inner client constructor. This allows you to configure additional
|
391
|
+
# parameters of the `Signet::OAuth2::Client`, such as connection parameters,
|
392
|
+
# timeouts, etc.
|
393
|
+
#
|
394
|
+
def initialize source_creds, options = {}
|
395
|
+
raise "The source credentials passed to Google::Auth::Credentials.new were nil." if source_creds.nil?
|
396
|
+
|
369
397
|
options = symbolize_hash_keys options
|
370
398
|
@project_id = options[:project_id] || options[:project]
|
371
399
|
@quota_project_id = options[:quota_project_id]
|
372
|
-
case
|
373
|
-
when
|
374
|
-
|
400
|
+
case source_creds
|
401
|
+
when String
|
402
|
+
update_from_filepath source_creds, options
|
375
403
|
when Hash
|
376
|
-
update_from_hash
|
404
|
+
update_from_hash source_creds, options
|
377
405
|
else
|
378
|
-
|
406
|
+
update_from_client source_creds
|
379
407
|
end
|
380
408
|
setup_logging logger: options.fetch(:logger, :default)
|
381
409
|
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
@@ -481,14 +509,50 @@ module Google
|
|
481
509
|
:from_application_default,
|
482
510
|
:from_io
|
483
511
|
|
484
|
-
protected
|
485
512
|
|
486
|
-
#
|
487
|
-
|
488
|
-
|
489
|
-
|
513
|
+
# Creates a duplicate of these credentials. This method tries to create the duplicate of the
|
514
|
+
# wrapped credentials if they support duplication and use them as is if they don't.
|
515
|
+
#
|
516
|
+
# The wrapped credentials are typically `Signet::OAuth2::Client` objects and they keep
|
517
|
+
# the transient state (token, refresh token, etc). The duplication discards that state,
|
518
|
+
# allowing e.g. to get the token with a different scope.
|
519
|
+
#
|
520
|
+
# @param options [Hash] Overrides for the credentials parameters.
|
521
|
+
#
|
522
|
+
# The options hash is used in two ways:
|
523
|
+
#
|
524
|
+
# 1. **Configuring the duplicate of the wrapper object:** Some options are used to directly
|
525
|
+
# configure the wrapper `Credentials` instance. These include:
|
526
|
+
#
|
527
|
+
# * `:project_id` (and optionally `:project`) - the project identifier for the credentials
|
528
|
+
# * `:quota_project_id` - the quota project identifier for the credentials
|
529
|
+
#
|
530
|
+
# 2. **Configuring the duplicate of the inner client:** If the inner client supports duplication
|
531
|
+
# the options hash is passed to it. This allows for configuration of additional parameters,
|
532
|
+
# most importantly (but not limited to) the following:
|
533
|
+
#
|
534
|
+
# * `:scope` - the scope for the client
|
535
|
+
#
|
536
|
+
# @return [Credentials]
|
537
|
+
def duplicate options = {}
|
538
|
+
options = deep_hash_normalize options
|
539
|
+
|
540
|
+
options = {
|
541
|
+
project_id: @project_id,
|
542
|
+
quota_project_id: @quota_project_id
|
543
|
+
}.merge(options)
|
544
|
+
|
545
|
+
new_client = if @client.respond_to? :duplicate
|
546
|
+
@client.duplicate options
|
547
|
+
else
|
548
|
+
@client
|
549
|
+
end
|
550
|
+
|
551
|
+
self.class.new new_client, options
|
490
552
|
end
|
491
553
|
|
554
|
+
protected
|
555
|
+
|
492
556
|
# Verify that the keyfile argument is a file.
|
493
557
|
def verify_keyfile_exists! keyfile
|
494
558
|
exists = ::File.file? keyfile
|
@@ -530,11 +594,12 @@ module Google
|
|
530
594
|
options
|
531
595
|
end
|
532
596
|
|
533
|
-
def
|
597
|
+
def update_from_client client
|
534
598
|
@project_id ||= client.project_id if client.respond_to? :project_id
|
535
599
|
@quota_project_id ||= client.quota_project_id if client.respond_to? :quota_project_id
|
536
600
|
@client = client
|
537
601
|
end
|
602
|
+
alias update_from_signet update_from_client
|
538
603
|
|
539
604
|
def update_from_hash hash, options
|
540
605
|
hash = stringify_hash_keys hash
|
@@ -571,6 +636,23 @@ module Google
|
|
571
636
|
end
|
572
637
|
@client.logger = logger
|
573
638
|
end
|
639
|
+
|
640
|
+
private
|
641
|
+
|
642
|
+
# Convert all keys in this hash (nested) to symbols for uniform retrieval
|
643
|
+
def recursive_hash_normalize_keys val
|
644
|
+
if val.is_a? Hash
|
645
|
+
deep_hash_normalize val
|
646
|
+
else
|
647
|
+
val
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
def deep_hash_normalize old_hash
|
652
|
+
sym_hash = {}
|
653
|
+
old_hash&.each { |k, v| sym_hash[k.to_sym] = recursive_hash_normalize_keys v }
|
654
|
+
sym_hash
|
655
|
+
end
|
574
656
|
end
|
575
657
|
end
|
576
658
|
end
|
@@ -37,7 +37,7 @@ module Google
|
|
37
37
|
AWS_SESSION_TOKEN_VAR = "AWS_SESSION_TOKEN".freeze
|
38
38
|
GCLOUD_POSIX_COMMAND = "gcloud".freeze
|
39
39
|
GCLOUD_WINDOWS_COMMAND = "gcloud.cmd".freeze
|
40
|
-
GCLOUD_CONFIG_COMMAND = "config config-helper --format json --verbosity none".freeze
|
40
|
+
GCLOUD_CONFIG_COMMAND = "config config-helper --format json --verbosity none --quiet".freeze
|
41
41
|
|
42
42
|
CREDENTIALS_FILE_NAME = "application_default_credentials.json".freeze
|
43
43
|
NOT_FOUND_ERROR = "Unable to read the credential file specified by #{ENV_VAR}".freeze
|
@@ -146,7 +146,7 @@ module Google
|
|
146
146
|
def load_gcloud_project_id
|
147
147
|
gcloud = GCLOUD_WINDOWS_COMMAND if OS.windows?
|
148
148
|
gcloud = GCLOUD_POSIX_COMMAND unless OS.windows?
|
149
|
-
gcloud_json = IO.popen("#{gcloud} #{GCLOUD_CONFIG_COMMAND}",
|
149
|
+
gcloud_json = IO.popen("#{gcloud} #{GCLOUD_CONFIG_COMMAND}", err: :close, &:read)
|
150
150
|
config = MultiJson.load gcloud_json
|
151
151
|
config["configuration"]["properties"]["core"]["project"]
|
152
152
|
rescue StandardError
|