googleauth 1.11.0 → 1.12.2
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 +32 -0
- data/lib/googleauth/base_client.rb +16 -4
- data/lib/googleauth/compute_engine.rb +100 -25
- data/lib/googleauth/credentials.rb +38 -10
- data/lib/googleauth/external_account/base_credentials.rb +34 -3
- data/lib/googleauth/id_tokens.rb +0 -2
- data/lib/googleauth/service_account.rb +12 -1
- data/lib/googleauth/signet.rb +85 -2
- data/lib/googleauth/token_store.rb +3 -3
- data/lib/googleauth/version.rb +1 -1
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34f510693238aa2d0ac63fb3d7a91f8685d34dc9962e33952220b6ee8845beef
|
4
|
+
data.tar.gz: 97d0eb5127ac1c609740d8b422b2002bd8f983043ff1a11cc09130c3c650d30f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 821238707fdf60880359514bc2385a273b4d16fe6bc6bd8ad804fcd36d2255667ad4a4dd39e7fabbd5f422367208a7fc7b74949943cda444481a8da3edfd16e2
|
7
|
+
data.tar.gz: 792636b6a808d5c93dc7a3883a7c7d1e62cbb3d8b33b76e4da025cdbdac8cbd915c1cd4c5e1e698a58173d6fb2840e7623bd8c2a5673edc69113b662486029c4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,37 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 1.12.2 (2024-12-19)
|
4
|
+
|
5
|
+
#### Bug Fixes
|
6
|
+
|
7
|
+
* GCECredentials lazily fetches from the metadata server to ensure a universe domain is known ([#509](https://github.com/googleapis/google-auth-library-ruby/issues/509))
|
8
|
+
|
9
|
+
### 1.12.1 (2024-12-17)
|
10
|
+
|
11
|
+
#### Bug Fixes
|
12
|
+
|
13
|
+
* Restored previous behavior where the apply! method returns the auth header ([#506](https://github.com/googleapis/google-auth-library-ruby/issues/506))
|
14
|
+
|
15
|
+
### 1.12.0 (2024-12-05)
|
16
|
+
|
17
|
+
#### Features
|
18
|
+
|
19
|
+
* provided opt-in debug logging ([#490](https://github.com/googleapis/google-auth-library-ruby/issues/490))
|
20
|
+
|
21
|
+
### 1.11.2 (2024-10-23)
|
22
|
+
|
23
|
+
#### Bug Fixes
|
24
|
+
|
25
|
+
* Temporarily disable universe domain query from GCE metadata server ([#493](https://github.com/googleapis/google-auth-library-ruby/issues/493))
|
26
|
+
* Use updated metadata path for universe-domain ([#496](https://github.com/googleapis/google-auth-library-ruby/issues/496))
|
27
|
+
|
28
|
+
### 1.11.1 (2024-10-04)
|
29
|
+
|
30
|
+
#### Bug Fixes
|
31
|
+
|
32
|
+
* Fixed parsing of expiration timestamp from ID tokens ([#492](https://github.com/googleapis/google-auth-library-ruby/issues/492))
|
33
|
+
* Use NoMethodError instead of NotImplementedError for unimplemented base class methods ([#487](https://github.com/googleapis/google-auth-library-ruby/issues/487))
|
34
|
+
|
3
35
|
### 1.11.0 (2024-02-09)
|
4
36
|
|
5
37
|
#### Features
|
@@ -12,6 +12,8 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require "google/logging/message"
|
16
|
+
|
15
17
|
module Google
|
16
18
|
# Module Auth provides classes that provide Google-specific authorization
|
17
19
|
# used to access Google APIs.
|
@@ -29,7 +31,14 @@ module Google
|
|
29
31
|
# fetch the access token there is currently not one, or if the client
|
30
32
|
# has expired
|
31
33
|
fetch_access_token! opts if needs_access_token?
|
32
|
-
|
34
|
+
token = send token_type
|
35
|
+
a_hash[AUTH_METADATA_KEY] = "Bearer #{token}"
|
36
|
+
logger&.debug do
|
37
|
+
hash = Digest::SHA256.hexdigest token
|
38
|
+
Google::Logging::Message.from message: "Sending auth token. (sha256:#{hash})"
|
39
|
+
end
|
40
|
+
|
41
|
+
a_hash[AUTH_METADATA_KEY]
|
33
42
|
end
|
34
43
|
|
35
44
|
# Returns a clone of a_hash updated with the authentication token
|
@@ -63,17 +72,20 @@ module Google
|
|
63
72
|
end
|
64
73
|
|
65
74
|
def expires_within?
|
66
|
-
raise
|
75
|
+
raise NoMethodError, "expires_within? not implemented"
|
67
76
|
end
|
68
77
|
|
78
|
+
# The logger used to log operations on this client, such as token refresh.
|
79
|
+
attr_accessor :logger
|
80
|
+
|
69
81
|
private
|
70
82
|
|
71
83
|
def token_type
|
72
|
-
raise
|
84
|
+
raise NoMethodError, "token_type not implemented"
|
73
85
|
end
|
74
86
|
|
75
87
|
def fetch_access_token!
|
76
|
-
raise
|
88
|
+
raise NoMethodError, "fetch_access_token! not implemented"
|
77
89
|
end
|
78
90
|
end
|
79
91
|
end
|
@@ -80,69 +80,144 @@ module Google
|
|
80
80
|
alias unmemoize_all reset_cache
|
81
81
|
end
|
82
82
|
|
83
|
+
# @private Temporary; remove when universe domain metadata endpoint is stable (see b/349488459).
|
84
|
+
attr_accessor :disable_universe_domain_check
|
85
|
+
|
83
86
|
# Construct a GCECredentials
|
84
87
|
def initialize options = {}
|
85
88
|
# Override the constructor to remember whether the universe domain was
|
86
89
|
# overridden by a constructor argument.
|
87
90
|
@universe_domain_overridden = options["universe_domain"] || options[:universe_domain] ? true : false
|
91
|
+
# TODO: Remove when universe domain metadata endpoint is stable (see b/349488459).
|
92
|
+
@disable_universe_domain_check = true
|
88
93
|
super options
|
89
94
|
end
|
90
95
|
|
96
|
+
# @private
|
97
|
+
# Overrides universe_domain getter to fetch lazily if it hasn't been
|
98
|
+
# fetched yet. This is necessary specifically for Compute Engine because
|
99
|
+
# the universe comes from the metadata service, and isn't known
|
100
|
+
# immediately on credential construction. All other credential types read
|
101
|
+
# the universe from their json key or other immediate input.
|
102
|
+
def universe_domain
|
103
|
+
value = super
|
104
|
+
return value unless value.nil?
|
105
|
+
fetch_access_token!
|
106
|
+
super
|
107
|
+
end
|
108
|
+
|
91
109
|
# Overrides the super class method to change how access tokens are
|
92
110
|
# fetched.
|
93
111
|
def fetch_access_token _options = {}
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
112
|
+
query, entry =
|
113
|
+
if token_type == :id_token
|
114
|
+
[{ "audience" => target_audience, "format" => "full" }, "service-accounts/default/identity"]
|
115
|
+
else
|
116
|
+
[{}, "service-accounts/default/token"]
|
117
|
+
end
|
101
118
|
query[:scopes] = Array(scope).join "," if scope
|
102
119
|
begin
|
120
|
+
log_fetch_query
|
103
121
|
resp = Google::Cloud.env.lookup_metadata_response "instance", entry, query: query
|
122
|
+
log_fetch_resp resp
|
104
123
|
case resp.status
|
105
124
|
when 200
|
106
125
|
build_token_hash resp.body, resp.headers["content-type"], resp.retrieval_monotonic_time
|
107
126
|
when 403, 500
|
108
|
-
|
109
|
-
raise Signet::UnexpectedStatusError, msg
|
127
|
+
raise Signet::UnexpectedStatusError, "Unexpected error code #{resp.status} #{UNEXPECTED_ERROR_SUFFIX}"
|
110
128
|
when 404
|
111
129
|
raise Signet::AuthorizationError, NO_METADATA_SERVER_ERROR
|
112
130
|
else
|
113
|
-
|
114
|
-
raise Signet::AuthorizationError, msg
|
131
|
+
raise Signet::AuthorizationError, "Unexpected error code #{resp.status} #{UNEXPECTED_ERROR_SUFFIX}"
|
115
132
|
end
|
116
133
|
rescue Google::Cloud::Env::MetadataServerNotResponding => e
|
134
|
+
log_fetch_err e
|
117
135
|
raise Signet::AuthorizationError, e.message
|
118
136
|
end
|
119
137
|
end
|
120
138
|
|
121
139
|
private
|
122
140
|
|
141
|
+
def log_fetch_query
|
142
|
+
if token_type == :id_token
|
143
|
+
logger&.info do
|
144
|
+
Google::Logging::Message.from(
|
145
|
+
message: "Requesting id token from MDS with aud=#{target_audience}",
|
146
|
+
"credentialsId" => object_id
|
147
|
+
)
|
148
|
+
end
|
149
|
+
else
|
150
|
+
logger&.info do
|
151
|
+
Google::Logging::Message.from(
|
152
|
+
message: "Requesting access token from MDS",
|
153
|
+
"credentialsId" => object_id
|
154
|
+
)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def log_fetch_resp resp
|
160
|
+
logger&.info do
|
161
|
+
Google::Logging::Message.from(
|
162
|
+
message: "Received #{resp.status} from MDS",
|
163
|
+
"credentialsId" => object_id
|
164
|
+
)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def log_fetch_err _err
|
169
|
+
logger&.info do
|
170
|
+
Google::Logging::Message.from(
|
171
|
+
message: "MDS did not respond to token request",
|
172
|
+
"credentialsId" => object_id
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
123
177
|
def build_token_hash body, content_type, retrieval_time
|
124
178
|
hash =
|
125
179
|
if ["text/html", "application/text"].include? content_type
|
126
|
-
|
180
|
+
parse_encoded_token body
|
127
181
|
else
|
128
182
|
Signet::OAuth2.parse_credentials body, content_type
|
129
183
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
offset = 1 + (Process.clock_gettime(Process::CLOCK_MONOTONIC) - retrieval_time).round
|
141
|
-
hash["expires_in"] -= offset if offset.positive?
|
142
|
-
hash["expires_in"] = 0 if hash["expires_in"].negative?
|
184
|
+
add_universe_domain_to hash
|
185
|
+
adjust_for_stale_expires_in hash, retrieval_time
|
186
|
+
hash
|
187
|
+
end
|
188
|
+
|
189
|
+
def parse_encoded_token body
|
190
|
+
hash = { token_type.to_s => body }
|
191
|
+
if token_type == :id_token
|
192
|
+
expires_at = expires_at_from_id_token body
|
193
|
+
hash["expires_at"] = expires_at if expires_at
|
143
194
|
end
|
144
195
|
hash
|
145
196
|
end
|
197
|
+
|
198
|
+
def add_universe_domain_to hash
|
199
|
+
return if @universe_domain_overridden
|
200
|
+
universe_domain =
|
201
|
+
if disable_universe_domain_check
|
202
|
+
# TODO: Remove when universe domain metadata endpoint is stable (see b/349488459).
|
203
|
+
"googleapis.com"
|
204
|
+
else
|
205
|
+
Google::Cloud.env.lookup_metadata "universe", "universe-domain"
|
206
|
+
end
|
207
|
+
universe_domain = "googleapis.com" if !universe_domain || universe_domain.empty?
|
208
|
+
hash["universe_domain"] = universe_domain.strip
|
209
|
+
end
|
210
|
+
|
211
|
+
# The response might have been cached, which means expires_in might be
|
212
|
+
# stale. Update it based on the time since the data was retrieved.
|
213
|
+
# We also ensure expires_in is conservative; subtracting at least 1
|
214
|
+
# second to offset any skew from metadata server latency.
|
215
|
+
def adjust_for_stale_expires_in hash, retrieval_time
|
216
|
+
return unless hash["expires_in"].is_a? Numeric
|
217
|
+
offset = 1 + (Process.clock_gettime(Process::CLOCK_MONOTONIC) - retrieval_time).round
|
218
|
+
hash["expires_in"] -= offset if offset.positive?
|
219
|
+
hash["expires_in"] = 0 if hash["expires_in"].negative?
|
220
|
+
end
|
146
221
|
end
|
147
222
|
end
|
148
223
|
end
|
@@ -299,6 +299,12 @@ module Google
|
|
299
299
|
#
|
300
300
|
attr_reader :quota_project_id
|
301
301
|
|
302
|
+
# @private Temporary; remove when universe domain metadata endpoint is stable (see b/349488459).
|
303
|
+
def disable_universe_domain_check
|
304
|
+
return false unless @client.respond_to? :disable_universe_domain_check
|
305
|
+
@client.disable_universe_domain_check
|
306
|
+
end
|
307
|
+
|
302
308
|
# @private Delegate client methods to the client object.
|
303
309
|
extend Forwardable
|
304
310
|
|
@@ -331,10 +337,13 @@ module Google
|
|
331
337
|
# @!attribute [rw] universe_domain
|
332
338
|
# @return [String] The universe domain issuing these credentials.
|
333
339
|
#
|
340
|
+
# @!attribute [rw] logger
|
341
|
+
# @return [Logger] The logger used to log credential operations such as token refresh.
|
342
|
+
#
|
334
343
|
def_delegators :@client,
|
335
344
|
:token_credential_uri, :audience,
|
336
345
|
:scope, :issuer, :signing_key, :updater_proc, :target_audience,
|
337
|
-
:universe_domain, :universe_domain=
|
346
|
+
:universe_domain, :universe_domain=, :logger, :logger=
|
338
347
|
|
339
348
|
##
|
340
349
|
# Creates a new Credentials instance with the provided auth credentials, and with the default
|
@@ -343,16 +352,17 @@ module Google
|
|
343
352
|
# @param [String, Hash, Signet::OAuth2::Client] keyfile
|
344
353
|
# The keyfile can be provided as one of the following:
|
345
354
|
#
|
346
|
-
# * The path to a JSON keyfile (as a
|
347
|
-
# * The contents of a JSON keyfile (as a
|
348
|
-
# * A
|
355
|
+
# * The path to a JSON keyfile (as a `String`)
|
356
|
+
# * The contents of a JSON keyfile (as a `Hash`)
|
357
|
+
# * A `Signet::OAuth2::Client` object
|
349
358
|
# @param [Hash] options
|
350
359
|
# The options for configuring the credentials instance. The following is supported:
|
351
360
|
#
|
352
|
-
# *
|
353
|
-
# *
|
354
|
-
# *
|
355
|
-
# *
|
361
|
+
# * `:scope` - the scope for the client
|
362
|
+
# * `project_id` (and optionally `project`) - the project identifier for the client
|
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.
|
356
366
|
#
|
357
367
|
def initialize keyfile, options = {}
|
358
368
|
verify_keyfile_provided! keyfile
|
@@ -367,8 +377,8 @@ module Google
|
|
367
377
|
else
|
368
378
|
update_from_filepath keyfile, options
|
369
379
|
end
|
380
|
+
setup_logging logger: options.fetch(:logger, :default)
|
370
381
|
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
371
|
-
@client.fetch_access_token! if @client.needs_access_token?
|
372
382
|
@env_vars = nil
|
373
383
|
@paths = nil
|
374
384
|
@scope = nil
|
@@ -462,7 +472,8 @@ module Google
|
|
462
472
|
audience: options[:audience] || audience
|
463
473
|
}
|
464
474
|
client = Google::Auth::DefaultCredentials.make_creds creds_input
|
465
|
-
|
475
|
+
options = options.select { |k, _v| k == :logger }
|
476
|
+
new client, options
|
466
477
|
end
|
467
478
|
|
468
479
|
private_class_method :from_env_vars,
|
@@ -543,6 +554,23 @@ module Google
|
|
543
554
|
@quota_project_id ||= json["quota_project_id"]
|
544
555
|
@client = init_client json, options
|
545
556
|
end
|
557
|
+
|
558
|
+
def setup_logging logger: :default
|
559
|
+
return unless @client.respond_to? :logger=
|
560
|
+
logging_env = ENV["GOOGLE_SDK_RUBY_LOGGING_GEMS"].to_s.downcase
|
561
|
+
if ["false", "none"].include? logging_env
|
562
|
+
logger = nil
|
563
|
+
elsif @client.logger
|
564
|
+
logger = @client.logger
|
565
|
+
elsif logger == :default
|
566
|
+
logger = nil
|
567
|
+
if ["true", "all"].include?(logging_env) || logging_env.split(",").include?("googleauth")
|
568
|
+
formatter = Google::Logging::StructuredFormatter.new if Google::Cloud::Env.get.logging_agent_expected?
|
569
|
+
logger = Logger.new $stderr, progname: "googleauth", formatter: formatter
|
570
|
+
end
|
571
|
+
end
|
572
|
+
@client.logger = logger
|
573
|
+
end
|
546
574
|
end
|
547
575
|
end
|
548
576
|
end
|
@@ -76,7 +76,7 @@ module Google
|
|
76
76
|
# The retrieved subject token.
|
77
77
|
#
|
78
78
|
def retrieve_subject_token!
|
79
|
-
raise
|
79
|
+
raise NoMethodError, "retrieve_subject_token! not implemented"
|
80
80
|
end
|
81
81
|
|
82
82
|
# Returns whether the credentials represent a workforce pool (True) or
|
@@ -129,7 +129,7 @@ module Google
|
|
129
129
|
if @client_id.nil? && @workforce_pool_user_project
|
130
130
|
additional_options = { userProject: @workforce_pool_user_project }
|
131
131
|
end
|
132
|
-
|
132
|
+
token_request = {
|
133
133
|
audience: @audience,
|
134
134
|
grant_type: STS_GRANT_TYPE,
|
135
135
|
subject_token: retrieve_subject_token!,
|
@@ -137,10 +137,31 @@ module Google
|
|
137
137
|
scopes: @service_account_impersonation_url ? IAM_SCOPE : @scope,
|
138
138
|
requested_token_type: STS_REQUESTED_TOKEN_TYPE,
|
139
139
|
additional_options: additional_options
|
140
|
-
|
140
|
+
}
|
141
|
+
log_token_request token_request
|
142
|
+
@sts_client.exchange_token token_request
|
143
|
+
end
|
144
|
+
|
145
|
+
def log_token_request token_request
|
146
|
+
logger&.info do
|
147
|
+
Google::Logging::Message.from(
|
148
|
+
message: "Requesting access token from #{token_request[:grant_type]}",
|
149
|
+
"credentialsId" => object_id
|
150
|
+
)
|
151
|
+
end
|
152
|
+
logger&.debug do
|
153
|
+
digest = Digest::SHA256.hexdigest token_request[:subject_token].to_s
|
154
|
+
loggable_request = token_request.merge subject_token: "(sha256:#{digest})"
|
155
|
+
Google::Logging::Message.from(
|
156
|
+
message: "Request data",
|
157
|
+
"request" => loggable_request,
|
158
|
+
"credentialsId" => object_id
|
159
|
+
)
|
160
|
+
end
|
141
161
|
end
|
142
162
|
|
143
163
|
def get_impersonated_access_token token, _options = {}
|
164
|
+
log_impersonated_token_request token
|
144
165
|
response = connection.post @service_account_impersonation_url do |req|
|
145
166
|
req.headers["Authorization"] = "Bearer #{token}"
|
146
167
|
req.headers["Content-Type"] = "application/json"
|
@@ -153,6 +174,16 @@ module Google
|
|
153
174
|
|
154
175
|
MultiJson.load response.body
|
155
176
|
end
|
177
|
+
|
178
|
+
def log_impersonated_token_request original_token
|
179
|
+
logger&.info do
|
180
|
+
digest = Digest::SHA256.hexdigest original_token
|
181
|
+
Google::Logging::Message.from(
|
182
|
+
message: "Requesting impersonated access token with original token (sha256:#{digest})",
|
183
|
+
"credentialsId" => object_id
|
184
|
+
)
|
185
|
+
end
|
186
|
+
end
|
156
187
|
end
|
157
188
|
end
|
158
189
|
end
|
data/lib/googleauth/id_tokens.rb
CHANGED
@@ -168,7 +168,6 @@ module Google
|
|
168
168
|
aud: nil,
|
169
169
|
azp: nil,
|
170
170
|
iss: OIDC_ISSUERS
|
171
|
-
|
172
171
|
verifier = Verifier.new key_source: oidc_key_source,
|
173
172
|
aud: aud,
|
174
173
|
azp: azp,
|
@@ -206,7 +205,6 @@ module Google
|
|
206
205
|
aud: nil,
|
207
206
|
azp: nil,
|
208
207
|
iss: IAP_ISSUERS
|
209
|
-
|
210
208
|
verifier = Verifier.new key_source: iap_key_source,
|
211
209
|
aud: aud,
|
212
210
|
azp: azp,
|
@@ -12,6 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require "google/logging/message"
|
15
16
|
require "googleauth/signet"
|
16
17
|
require "googleauth/credentials_loader"
|
17
18
|
require "googleauth/json_key_reader"
|
@@ -123,6 +124,7 @@ module Google
|
|
123
124
|
}
|
124
125
|
key_io = StringIO.new MultiJson.dump(cred_json)
|
125
126
|
alt = ServiceAccountJwtHeaderCredentials.make_creds json_key_io: key_io, scope: scope
|
127
|
+
alt.logger = logger
|
126
128
|
alt.apply! a_hash
|
127
129
|
end
|
128
130
|
end
|
@@ -147,6 +149,7 @@ module Google
|
|
147
149
|
attr_reader :project_id
|
148
150
|
attr_reader :quota_project_id
|
149
151
|
attr_accessor :universe_domain
|
152
|
+
attr_accessor :logger
|
150
153
|
|
151
154
|
# Create a ServiceAccountJwtHeaderCredentials.
|
152
155
|
#
|
@@ -187,10 +190,14 @@ module Google
|
|
187
190
|
return a_hash if jwt_aud_uri.nil? && @scope.nil?
|
188
191
|
jwt_token = new_jwt_token jwt_aud_uri, opts
|
189
192
|
a_hash[AUTH_METADATA_KEY] = "Bearer #{jwt_token}"
|
193
|
+
logger&.debug do
|
194
|
+
hash = Digest::SHA256.hexdigest jwt_token
|
195
|
+
Google::Logging::Message.from message: "Sending JWT auth token. (sha256:#{hash})"
|
196
|
+
end
|
190
197
|
a_hash
|
191
198
|
end
|
192
199
|
|
193
|
-
# Returns a clone of a_hash updated with the
|
200
|
+
# Returns a clone of a_hash updated with the authorization header
|
194
201
|
def apply a_hash, opts = {}
|
195
202
|
a_copy = a_hash.clone
|
196
203
|
apply! a_copy, opts
|
@@ -219,6 +226,10 @@ module Google
|
|
219
226
|
assertion["scope"] = Array(@scope).join " " if @scope
|
220
227
|
assertion["aud"] = jwt_aud_uri if jwt_aud_uri
|
221
228
|
|
229
|
+
logger&.debug do
|
230
|
+
Google::Logging::Message.from message: "JWT assertion: #{assertion}"
|
231
|
+
end
|
232
|
+
|
222
233
|
JWT.encode assertion, @signing_key, SIGNING_ALGORITHM
|
223
234
|
end
|
224
235
|
|
data/lib/googleauth/signet.rb
CHANGED
@@ -12,6 +12,8 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require "base64"
|
16
|
+
require "json"
|
15
17
|
require "signet/oauth_2/client"
|
16
18
|
require "googleauth/base_client"
|
17
19
|
|
@@ -29,6 +31,8 @@ module Signet
|
|
29
31
|
|
30
32
|
def update_token! options = {}
|
31
33
|
options = deep_hash_normalize options
|
34
|
+
id_token_expires_at = expires_at_from_id_token options[:id_token]
|
35
|
+
options[:expires_at] = id_token_expires_at if id_token_expires_at
|
32
36
|
update_token_signet_base options
|
33
37
|
self.universe_domain = options[:universe_domain] if options.key? :universe_domain
|
34
38
|
self
|
@@ -61,6 +65,24 @@ module Signet
|
|
61
65
|
info
|
62
66
|
end
|
63
67
|
|
68
|
+
alias googleauth_orig_generate_access_token_request generate_access_token_request
|
69
|
+
def generate_access_token_request options = {}
|
70
|
+
parameters = googleauth_orig_generate_access_token_request options
|
71
|
+
logger&.info do
|
72
|
+
Google::Logging::Message.from(
|
73
|
+
message: "Requesting access token from #{parameters['grant_type']}",
|
74
|
+
"credentialsId" => object_id
|
75
|
+
)
|
76
|
+
end
|
77
|
+
logger&.debug do
|
78
|
+
Google::Logging::Message.from(
|
79
|
+
message: "Token fetch params: #{parameters}",
|
80
|
+
"credentialsId" => object_id
|
81
|
+
)
|
82
|
+
end
|
83
|
+
parameters
|
84
|
+
end
|
85
|
+
|
64
86
|
def build_default_connection
|
65
87
|
if !defined?(@connection_info)
|
66
88
|
nil
|
@@ -75,20 +97,81 @@ module Signet
|
|
75
97
|
retry_count = 0
|
76
98
|
|
77
99
|
begin
|
78
|
-
yield
|
100
|
+
yield.tap { |resp| log_response resp }
|
79
101
|
rescue StandardError => e
|
80
|
-
|
102
|
+
if e.is_a?(Signet::AuthorizationError) || e.is_a?(Signet::ParseError)
|
103
|
+
log_auth_error e
|
104
|
+
raise e
|
105
|
+
end
|
81
106
|
|
82
107
|
if retry_count < max_retry_count
|
108
|
+
log_transient_error e
|
83
109
|
retry_count += 1
|
84
110
|
sleep retry_count * 0.3
|
85
111
|
retry
|
86
112
|
else
|
113
|
+
log_retries_exhausted e
|
87
114
|
msg = "Unexpected error: #{e.inspect}"
|
88
115
|
raise Signet::AuthorizationError, msg
|
89
116
|
end
|
90
117
|
end
|
91
118
|
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def expires_at_from_id_token id_token
|
123
|
+
match = /^[\w=-]+\.([\w=-]+)\.[\w=-]+$/.match id_token.to_s
|
124
|
+
return unless match
|
125
|
+
json = JSON.parse Base64.urlsafe_decode64 match[1]
|
126
|
+
return unless json.key? "exp"
|
127
|
+
Time.at json["exp"].to_i
|
128
|
+
rescue StandardError
|
129
|
+
# Shouldn't happen unless we get a garbled ID token
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def log_response token_response
|
134
|
+
response_hash = JSON.parse token_response rescue {}
|
135
|
+
if response_hash["access_token"]
|
136
|
+
digest = Digest::SHA256.hexdigest response_hash["access_token"]
|
137
|
+
response_hash["access_token"] = "(sha256:#{digest})"
|
138
|
+
end
|
139
|
+
if response_hash["id_token"]
|
140
|
+
digest = Digest::SHA256.hexdigest response_hash["id_token"]
|
141
|
+
response_hash["id_token"] = "(sha256:#{digest})"
|
142
|
+
end
|
143
|
+
Google::Logging::Message.from(
|
144
|
+
message: "Received auth token response: #{response_hash}",
|
145
|
+
"credentialsId" => object_id
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
def log_auth_error err
|
150
|
+
logger&.info do
|
151
|
+
Google::Logging::Message.from(
|
152
|
+
message: "Auth error when fetching auth token: #{err}",
|
153
|
+
"credentialsId" => object_id
|
154
|
+
)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def log_transient_error err
|
159
|
+
logger&.info do
|
160
|
+
Google::Logging::Message.from(
|
161
|
+
message: "Transient error when fetching auth token: #{err}",
|
162
|
+
"credentialsId" => object_id
|
163
|
+
)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def log_retries_exhausted err
|
168
|
+
logger&.info do
|
169
|
+
Google::Logging::Message.from(
|
170
|
+
message: "Exhausted retries when fetching auth token: #{err}",
|
171
|
+
"credentialsId" => object_id
|
172
|
+
)
|
173
|
+
end
|
174
|
+
end
|
92
175
|
end
|
93
176
|
end
|
94
177
|
end
|
@@ -29,7 +29,7 @@ module Google
|
|
29
29
|
# @return [String]
|
30
30
|
# The loaded token data.
|
31
31
|
def load _id
|
32
|
-
raise "
|
32
|
+
raise NoMethodError, "load not implemented"
|
33
33
|
end
|
34
34
|
|
35
35
|
# Put the token data into storage for the given ID.
|
@@ -39,7 +39,7 @@ module Google
|
|
39
39
|
# @param [String] token
|
40
40
|
# The token data to store.
|
41
41
|
def store _id, _token
|
42
|
-
raise "
|
42
|
+
raise NoMethodError, "store not implemented"
|
43
43
|
end
|
44
44
|
|
45
45
|
# Remove the token data from storage for the given ID.
|
@@ -47,7 +47,7 @@ module Google
|
|
47
47
|
# @param [String] id
|
48
48
|
# ID of the token data to delete
|
49
49
|
def delete _id
|
50
|
-
raise "
|
50
|
+
raise NoMethodError, "delete not implemented"
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
data/lib/googleauth/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: googleauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.12.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Emiola
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -36,14 +36,28 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '2.
|
39
|
+
version: '2.2'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '2.
|
46
|
+
version: '2.2'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: google-logging-utils
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.1'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0.1'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: jwt
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
200
|
- !ruby/object:Gem::Version
|
187
201
|
version: '0'
|
188
202
|
requirements: []
|
189
|
-
rubygems_version: 3.5.
|
203
|
+
rubygems_version: 3.5.23
|
190
204
|
signing_key:
|
191
205
|
specification_version: 4
|
192
206
|
summary: Google Auth Library for Ruby
|