googleauth 0.9.0 → 0.17.1
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/.yardopts +11 -0
- data/CHANGELOG.md +113 -21
- data/README.md +13 -15
- data/SECURITY.md +7 -0
- data/lib/googleauth/application_default.rb +9 -9
- data/lib/googleauth/compute_engine.rb +55 -30
- data/lib/googleauth/credentials.rb +253 -64
- data/lib/googleauth/credentials_loader.rb +15 -16
- data/lib/googleauth/iam.rb +1 -1
- data/{spec/googleauth/stores/store_examples.rb → lib/googleauth/id_tokens/errors.rb} +36 -23
- data/lib/googleauth/id_tokens/key_sources.rb +396 -0
- data/lib/googleauth/id_tokens/verifier.rb +142 -0
- data/lib/googleauth/id_tokens.rb +233 -0
- data/lib/googleauth/json_key_reader.rb +6 -2
- data/lib/googleauth/scope_util.rb +1 -1
- data/lib/googleauth/service_account.rb +61 -36
- data/lib/googleauth/signet.rb +9 -7
- data/lib/googleauth/stores/file_token_store.rb +1 -0
- data/lib/googleauth/stores/redis_token_store.rb +1 -0
- data/lib/googleauth/user_authorizer.rb +8 -3
- data/lib/googleauth/user_refresh.rb +1 -1
- data/lib/googleauth/version.rb +1 -1
- data/lib/googleauth/web_user_authorizer.rb +5 -8
- data/lib/googleauth.rb +1 -0
- metadata +33 -76
- data/.github/CONTRIBUTING.md +0 -74
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -36
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -21
- data/.github/ISSUE_TEMPLATE/support_request.md +0 -7
- data/.gitignore +0 -36
- data/.kokoro/build.bat +0 -16
- data/.kokoro/build.sh +0 -4
- data/.kokoro/continuous/common.cfg +0 -24
- data/.kokoro/continuous/linux.cfg +0 -15
- data/.kokoro/continuous/osx.cfg +0 -3
- data/.kokoro/continuous/windows.cfg +0 -19
- data/.kokoro/osx.sh +0 -4
- data/.kokoro/presubmit/common.cfg +0 -24
- data/.kokoro/presubmit/linux.cfg +0 -14
- data/.kokoro/presubmit/osx.cfg +0 -3
- data/.kokoro/presubmit/windows.cfg +0 -19
- data/.kokoro/release.cfg +0 -53
- data/.kokoro/trampoline.bat +0 -10
- data/.kokoro/trampoline.sh +0 -4
- data/.rspec +0 -2
- data/.rubocop.yml +0 -42
- data/Gemfile +0 -25
- data/Rakefile +0 -89
- data/googleauth.gemspec +0 -35
- data/spec/googleauth/apply_auth_examples.rb +0 -148
- data/spec/googleauth/client_id_spec.rb +0 -160
- data/spec/googleauth/compute_engine_spec.rb +0 -122
- data/spec/googleauth/credentials_spec.rb +0 -459
- data/spec/googleauth/get_application_default_spec.rb +0 -286
- data/spec/googleauth/iam_spec.rb +0 -80
- data/spec/googleauth/scope_util_spec.rb +0 -77
- data/spec/googleauth/service_account_spec.rb +0 -482
- data/spec/googleauth/signet_spec.rb +0 -134
- data/spec/googleauth/stores/file_token_store_spec.rb +0 -57
- data/spec/googleauth/stores/redis_token_store_spec.rb +0 -50
- data/spec/googleauth/user_authorizer_spec.rb +0 -323
- data/spec/googleauth/user_refresh_spec.rb +0 -359
- data/spec/googleauth/web_user_authorizer_spec.rb +0 -172
- data/spec/spec_helper.rb +0 -92
- /data/{COPYING → LICENSE} +0 -0
@@ -36,9 +36,46 @@ require "googleauth/credentials_loader"
|
|
36
36
|
module Google
|
37
37
|
module Auth
|
38
38
|
##
|
39
|
-
# Credentials is
|
40
|
-
#
|
41
|
-
|
39
|
+
# Credentials is a high-level base class used by Google's API client
|
40
|
+
# libraries to represent the authentication when connecting to an API.
|
41
|
+
# In most cases, it is subclassed by API-specific credential classes that
|
42
|
+
# can be instantiated by clients.
|
43
|
+
#
|
44
|
+
# ## Options
|
45
|
+
#
|
46
|
+
# Credentials classes are configured with options that dictate default
|
47
|
+
# values for parameters such as scope and audience. These defaults are
|
48
|
+
# expressed as class attributes, and may differ from endpoint to endpoint.
|
49
|
+
# Normally, an API client will provide subclasses specific to each
|
50
|
+
# endpoint, configured with appropriate values.
|
51
|
+
#
|
52
|
+
# Note that these options inherit up the class hierarchy. If a particular
|
53
|
+
# options is not set for a subclass, its superclass is queried.
|
54
|
+
#
|
55
|
+
# Some older users of this class set options via constants. This usage is
|
56
|
+
# deprecated. For example, instead of setting the `AUDIENCE` constant on
|
57
|
+
# your subclass, call the `audience=` method.
|
58
|
+
#
|
59
|
+
# ## Example
|
60
|
+
#
|
61
|
+
# class MyCredentials < Google::Auth::Credentials
|
62
|
+
# # Set the default scope for these credentials
|
63
|
+
# self.scope = "http://example.com/my_scope"
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# # creds is a credentials object suitable for Google API clients
|
67
|
+
# creds = MyCredentials.default
|
68
|
+
# creds.scope # => ["http://example.com/my_scope"]
|
69
|
+
#
|
70
|
+
# class SubCredentials < MyCredentials
|
71
|
+
# # Override the default scope for this subclass
|
72
|
+
# self.scope = "http://example.com/sub_scope"
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# creds2 = SubCredentials.default
|
76
|
+
# creds2.scope # => ["http://example.com/sub_scope"]
|
77
|
+
#
|
78
|
+
class Credentials # rubocop:disable Metrics/ClassLength
|
42
79
|
##
|
43
80
|
# The default token credential URI to be used when none is provided during initialization.
|
44
81
|
TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token".freeze
|
@@ -47,6 +84,8 @@ module Google
|
|
47
84
|
# The default target audience ID to be used when none is provided during initialization.
|
48
85
|
AUDIENCE = "https://oauth2.googleapis.com/token".freeze
|
49
86
|
|
87
|
+
@audience = @scope = @target_audience = @env_vars = @paths = @token_credential_uri = nil
|
88
|
+
|
50
89
|
##
|
51
90
|
# The default token credential URI to be used when none is provided during initialization.
|
52
91
|
# The URI is the authorization server's HTTP endpoint capable of issuing tokens and
|
@@ -55,16 +94,15 @@ module Google
|
|
55
94
|
# @return [String]
|
56
95
|
#
|
57
96
|
def self.token_credential_uri
|
58
|
-
|
59
|
-
|
60
|
-
|
97
|
+
lookup_auth_param :token_credential_uri do
|
98
|
+
lookup_local_constant :TOKEN_CREDENTIAL_URI
|
99
|
+
end
|
61
100
|
end
|
62
101
|
|
63
102
|
##
|
64
103
|
# Set the default token credential URI to be used when none is provided during initialization.
|
65
104
|
#
|
66
105
|
# @param [String] new_token_credential_uri
|
67
|
-
# @return [String]
|
68
106
|
#
|
69
107
|
def self.token_credential_uri= new_token_credential_uri
|
70
108
|
@token_credential_uri = new_token_credential_uri
|
@@ -77,16 +115,15 @@ module Google
|
|
77
115
|
# @return [String]
|
78
116
|
#
|
79
117
|
def self.audience
|
80
|
-
|
81
|
-
|
82
|
-
|
118
|
+
lookup_auth_param :audience do
|
119
|
+
lookup_local_constant :AUDIENCE
|
120
|
+
end
|
83
121
|
end
|
84
122
|
|
85
123
|
##
|
86
124
|
# Sets the default target audience ID to be used when none is provided during initialization.
|
87
125
|
#
|
88
126
|
# @param [String] new_audience
|
89
|
-
# @return [String]
|
90
127
|
#
|
91
128
|
def self.audience= new_audience
|
92
129
|
@audience = new_audience
|
@@ -97,49 +134,91 @@ module Google
|
|
97
134
|
# A scope is an access range defined by the authorization server.
|
98
135
|
# The scope can be a single value or a list of values.
|
99
136
|
#
|
100
|
-
#
|
137
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
138
|
+
# If {#scope} is set, this credential will produce access tokens.
|
139
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
140
|
+
#
|
141
|
+
# @return [String, Array<String>, nil]
|
101
142
|
#
|
102
143
|
def self.scope
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
tmp_scope << const_get(:SCOPE) if const_defined? :SCOPE
|
108
|
-
tmp_scope.flatten.uniq
|
144
|
+
lookup_auth_param :scope do
|
145
|
+
vals = lookup_local_constant :SCOPE
|
146
|
+
vals ? Array(vals).flatten.uniq : nil
|
147
|
+
end
|
109
148
|
end
|
110
149
|
|
111
150
|
##
|
112
151
|
# Sets the default scope to be used when none is provided during initialization.
|
113
152
|
#
|
114
|
-
#
|
115
|
-
#
|
153
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
154
|
+
# If {#scope} is set, this credential will produce access tokens.
|
155
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
156
|
+
#
|
157
|
+
# @param [String, Array<String>, nil] new_scope
|
116
158
|
#
|
117
159
|
def self.scope= new_scope
|
118
160
|
new_scope = Array new_scope unless new_scope.nil?
|
119
161
|
@scope = new_scope
|
120
162
|
end
|
121
163
|
|
164
|
+
##
|
165
|
+
# The default final target audience for ID tokens, to be used when none
|
166
|
+
# is provided during initialization.
|
167
|
+
#
|
168
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
169
|
+
# If {#scope} is set, this credential will produce access tokens.
|
170
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
171
|
+
#
|
172
|
+
# @return [String, nil]
|
173
|
+
#
|
174
|
+
def self.target_audience
|
175
|
+
lookup_auth_param :target_audience
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Sets the default final target audience for ID tokens, to be used when none
|
180
|
+
# is provided during initialization.
|
181
|
+
#
|
182
|
+
# Either {#scope} or {#target_audience}, but not both, should be non-nil.
|
183
|
+
# If {#scope} is set, this credential will produce access tokens.
|
184
|
+
# If {#target_audience} is set, this credential will produce ID tokens.
|
185
|
+
#
|
186
|
+
# @param [String, nil] new_target_audience
|
187
|
+
#
|
188
|
+
def self.target_audience= new_target_audience
|
189
|
+
@target_audience = new_target_audience
|
190
|
+
end
|
191
|
+
|
122
192
|
##
|
123
193
|
# The environment variables to search for credentials. Values can either be a file path to the
|
124
194
|
# credentials file, or the JSON contents of the credentials file.
|
195
|
+
# The env_vars will never be nil. If there are no vars, the empty array is returned.
|
125
196
|
#
|
126
197
|
# @return [Array<String>]
|
127
198
|
#
|
128
199
|
def self.env_vars
|
129
|
-
|
200
|
+
env_vars_internal || []
|
201
|
+
end
|
130
202
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
203
|
+
##
|
204
|
+
# @private
|
205
|
+
# Internal recursive lookup for env_vars.
|
206
|
+
#
|
207
|
+
def self.env_vars_internal
|
208
|
+
lookup_auth_param :env_vars, :env_vars_internal do
|
209
|
+
# Pull values when PATH_ENV_VARS or JSON_ENV_VARS constants exists.
|
210
|
+
path_env_vars = lookup_local_constant :PATH_ENV_VARS
|
211
|
+
json_env_vars = lookup_local_constant :JSON_ENV_VARS
|
212
|
+
(Array(path_env_vars) + Array(json_env_vars)).flatten.uniq if path_env_vars || json_env_vars
|
213
|
+
end
|
136
214
|
end
|
137
215
|
|
138
216
|
##
|
139
217
|
# Sets the environment variables to search for credentials.
|
218
|
+
# Setting to `nil` "unsets" the value, and defaults to the superclass
|
219
|
+
# (or to the empty array if there is no superclass).
|
140
220
|
#
|
141
|
-
# @param [Array<String
|
142
|
-
# @return [Array<String>]
|
221
|
+
# @param [String, Array<String>, nil] new_env_vars
|
143
222
|
#
|
144
223
|
def self.env_vars= new_env_vars
|
145
224
|
new_env_vars = Array new_env_vars unless new_env_vars.nil?
|
@@ -148,29 +227,72 @@ module Google
|
|
148
227
|
|
149
228
|
##
|
150
229
|
# The file paths to search for credentials files.
|
230
|
+
# The paths will never be nil. If there are no paths, the empty array is returned.
|
151
231
|
#
|
152
232
|
# @return [Array<String>]
|
153
233
|
#
|
154
234
|
def self.paths
|
155
|
-
|
235
|
+
paths_internal || []
|
236
|
+
end
|
156
237
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
238
|
+
##
|
239
|
+
# @private
|
240
|
+
# Internal recursive lookup for paths.
|
241
|
+
#
|
242
|
+
def self.paths_internal
|
243
|
+
lookup_auth_param :paths, :paths_internal do
|
244
|
+
# Pull in values if the DEFAULT_PATHS constant exists.
|
245
|
+
vals = lookup_local_constant :DEFAULT_PATHS
|
246
|
+
vals ? Array(vals).flatten.uniq : nil
|
247
|
+
end
|
161
248
|
end
|
162
249
|
|
163
250
|
##
|
164
251
|
# Set the file paths to search for credentials files.
|
252
|
+
# Setting to `nil` "unsets" the value, and defaults to the superclass
|
253
|
+
# (or to the empty array if there is no superclass).
|
165
254
|
#
|
166
|
-
# @param [Array<String
|
167
|
-
# @return [Array<String>]
|
255
|
+
# @param [String, Array<String>, nil] new_paths
|
168
256
|
#
|
169
257
|
def self.paths= new_paths
|
170
258
|
new_paths = Array new_paths unless new_paths.nil?
|
171
259
|
@paths = new_paths
|
172
260
|
end
|
173
261
|
|
262
|
+
##
|
263
|
+
# @private
|
264
|
+
# Return the given parameter value, defaulting up the class hierarchy.
|
265
|
+
#
|
266
|
+
# First returns the value of the instance variable, if set.
|
267
|
+
# Next, calls the given block if provided. (This is generally used to
|
268
|
+
# look up legacy constant-based values.)
|
269
|
+
# Otherwise, calls the superclass method if present.
|
270
|
+
# Returns nil if all steps fail.
|
271
|
+
#
|
272
|
+
# @param name [Symbol] The parameter name
|
273
|
+
# @param method_name [Symbol] The lookup method name, if different
|
274
|
+
# @return [Object] The value
|
275
|
+
#
|
276
|
+
def self.lookup_auth_param name, method_name = name
|
277
|
+
val = instance_variable_get "@#{name}".to_sym
|
278
|
+
val = yield if val.nil? && block_given?
|
279
|
+
return val unless val.nil?
|
280
|
+
return superclass.send method_name if superclass.respond_to? method_name
|
281
|
+
nil
|
282
|
+
end
|
283
|
+
|
284
|
+
##
|
285
|
+
# @private
|
286
|
+
# Return the value of the given constant if it is defined directly in
|
287
|
+
# this class, or nil if not.
|
288
|
+
#
|
289
|
+
# @param [Symbol] Name of the constant
|
290
|
+
# @return [Object] The value
|
291
|
+
#
|
292
|
+
def self.lookup_local_constant name
|
293
|
+
const_defined?(name, false) ? const_get(name) : nil
|
294
|
+
end
|
295
|
+
|
174
296
|
##
|
175
297
|
# The Signet::OAuth2::Client object the Credentials instance is using.
|
176
298
|
#
|
@@ -185,6 +307,13 @@ module Google
|
|
185
307
|
#
|
186
308
|
attr_reader :project_id
|
187
309
|
|
310
|
+
##
|
311
|
+
# Identifier for a separate project used for billing/quota, if any.
|
312
|
+
#
|
313
|
+
# @return [String,nil]
|
314
|
+
#
|
315
|
+
attr_reader :quota_project_id
|
316
|
+
|
188
317
|
# @private Delegate client methods to the client object.
|
189
318
|
extend Forwardable
|
190
319
|
|
@@ -201,6 +330,9 @@ module Google
|
|
201
330
|
# @return [String, Array<String>] The scope for this client. A scope is an access range
|
202
331
|
# defined by the authorization server. The scope can be a single value or a list of values.
|
203
332
|
#
|
333
|
+
# @!attribute [r] target_audience
|
334
|
+
# @return [String] The final target audience for ID tokens returned by this credential.
|
335
|
+
#
|
204
336
|
# @!attribute [r] issuer
|
205
337
|
# @return [String] The issuer ID associated with this client.
|
206
338
|
#
|
@@ -213,9 +345,7 @@ module Google
|
|
213
345
|
#
|
214
346
|
def_delegators :@client,
|
215
347
|
:token_credential_uri, :audience,
|
216
|
-
:scope, :issuer, :signing_key, :updater_proc
|
217
|
-
|
218
|
-
# rubocop:disable Metrics/AbcSize
|
348
|
+
:scope, :issuer, :signing_key, :updater_proc, :target_audience
|
219
349
|
|
220
350
|
##
|
221
351
|
# Creates a new Credentials instance with the provided auth credentials, and with the default
|
@@ -236,29 +366,24 @@ module Google
|
|
236
366
|
# * +:default_connection+ - the default connection to use for the client
|
237
367
|
#
|
238
368
|
def initialize keyfile, options = {}
|
239
|
-
scope = options[:scope]
|
240
369
|
verify_keyfile_provided! keyfile
|
241
370
|
@project_id = options["project_id"] || options["project"]
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
@client = init_client hash, options
|
249
|
-
@project_id ||= (hash["project_id"] || hash["project"])
|
371
|
+
@quota_project_id = options["quota_project_id"]
|
372
|
+
case keyfile
|
373
|
+
when Signet::OAuth2::Client
|
374
|
+
update_from_signet keyfile
|
375
|
+
when Hash
|
376
|
+
update_from_hash keyfile, options
|
250
377
|
else
|
251
|
-
|
252
|
-
json = JSON.parse ::File.read(keyfile)
|
253
|
-
json["scope"] ||= scope
|
254
|
-
@project_id ||= (json["project_id"] || json["project"])
|
255
|
-
@client = init_client json, options
|
378
|
+
update_from_filepath keyfile, options
|
256
379
|
end
|
257
380
|
CredentialsLoader.warn_if_cloud_sdk_credentials @client.client_id
|
258
381
|
@project_id ||= CredentialsLoader.load_gcloud_project_id
|
259
382
|
@client.fetch_access_token!
|
383
|
+
@env_vars = nil
|
384
|
+
@paths = nil
|
385
|
+
@scope = nil
|
260
386
|
end
|
261
|
-
# rubocop:enable Metrics/AbcSize
|
262
387
|
|
263
388
|
##
|
264
389
|
# Creates a new Credentials instance with auth credentials acquired by searching the
|
@@ -299,8 +424,15 @@ module Google
|
|
299
424
|
env_vars.each do |env_var|
|
300
425
|
str = ENV[env_var]
|
301
426
|
next if str.nil?
|
302
|
-
|
303
|
-
|
427
|
+
io =
|
428
|
+
if ::File.file? str
|
429
|
+
::StringIO.new ::File.read str
|
430
|
+
else
|
431
|
+
json = ::JSON.parse str rescue nil
|
432
|
+
json ? ::StringIO.new(str) : nil
|
433
|
+
end
|
434
|
+
next if io.nil?
|
435
|
+
return from_io io, options
|
304
436
|
end
|
305
437
|
nil
|
306
438
|
end
|
@@ -308,11 +440,11 @@ module Google
|
|
308
440
|
##
|
309
441
|
# @private Lookup Credentials from default file paths.
|
310
442
|
def self.from_default_paths options
|
311
|
-
paths
|
312
|
-
|
313
|
-
.
|
314
|
-
|
315
|
-
|
443
|
+
paths.each do |path|
|
444
|
+
next unless path && ::File.file?(path)
|
445
|
+
io = ::StringIO.new ::File.read path
|
446
|
+
return from_io io, options
|
447
|
+
end
|
316
448
|
nil
|
317
449
|
end
|
318
450
|
|
@@ -320,13 +452,34 @@ module Google
|
|
320
452
|
# @private Lookup Credentials using Google::Auth.get_application_default.
|
321
453
|
def self.from_application_default options
|
322
454
|
scope = options[:scope] || self.scope
|
323
|
-
|
455
|
+
auth_opts = {
|
456
|
+
token_credential_uri: options[:token_credential_uri] || token_credential_uri,
|
457
|
+
audience: options[:audience] || audience,
|
458
|
+
target_audience: options[:target_audience] || target_audience,
|
459
|
+
enable_self_signed_jwt: options[:enable_self_signed_jwt] && options[:scope].nil?
|
460
|
+
}
|
461
|
+
client = Google::Auth.get_application_default scope, auth_opts
|
324
462
|
new client, options
|
325
463
|
end
|
326
464
|
|
465
|
+
# @private Read credentials from a JSON stream.
|
466
|
+
def self.from_io io, options
|
467
|
+
creds_input = {
|
468
|
+
json_key_io: io,
|
469
|
+
scope: options[:scope] || scope,
|
470
|
+
target_audience: options[:target_audience] || target_audience,
|
471
|
+
enable_self_signed_jwt: options[:enable_self_signed_jwt] && options[:scope].nil?,
|
472
|
+
token_credential_uri: options[:token_credential_uri] || token_credential_uri,
|
473
|
+
audience: options[:audience] || audience
|
474
|
+
}
|
475
|
+
client = Google::Auth::DefaultCredentials.make_creds creds_input
|
476
|
+
new client
|
477
|
+
end
|
478
|
+
|
327
479
|
private_class_method :from_env_vars,
|
328
480
|
:from_default_paths,
|
329
|
-
:from_application_default
|
481
|
+
:from_application_default,
|
482
|
+
:from_io
|
330
483
|
|
331
484
|
protected
|
332
485
|
|
@@ -351,22 +504,58 @@ module Google
|
|
351
504
|
|
352
505
|
# returns a new Hash with string keys instead of symbol keys.
|
353
506
|
def stringify_hash_keys hash
|
354
|
-
|
507
|
+
hash.to_h.transform_keys(&:to_s)
|
355
508
|
end
|
356
509
|
|
510
|
+
# rubocop:disable Metrics/AbcSize
|
511
|
+
|
357
512
|
def client_options options
|
358
513
|
# Keyfile options have higher priority over constructor defaults
|
359
514
|
options["token_credential_uri"] ||= self.class.token_credential_uri
|
360
515
|
options["audience"] ||= self.class.audience
|
361
516
|
options["scope"] ||= self.class.scope
|
517
|
+
options["target_audience"] ||= self.class.target_audience
|
518
|
+
|
519
|
+
if !Array(options["scope"]).empty? && options["target_audience"]
|
520
|
+
raise ArgumentError, "Cannot specify both scope and target_audience"
|
521
|
+
end
|
362
522
|
|
523
|
+
needs_scope = options["target_audience"].nil?
|
363
524
|
# client options for initializing signet client
|
364
525
|
{ token_credential_uri: options["token_credential_uri"],
|
365
526
|
audience: options["audience"],
|
366
|
-
scope: Array(options["scope"]),
|
527
|
+
scope: (needs_scope ? Array(options["scope"]) : nil),
|
528
|
+
target_audience: options["target_audience"],
|
367
529
|
issuer: options["client_email"],
|
368
530
|
signing_key: OpenSSL::PKey::RSA.new(options["private_key"]) }
|
369
531
|
end
|
532
|
+
|
533
|
+
# rubocop:enable Metrics/AbcSize
|
534
|
+
|
535
|
+
def update_from_signet client
|
536
|
+
@project_id ||= client.project_id if client.respond_to? :project_id
|
537
|
+
@quota_project_id ||= client.quota_project_id if client.respond_to? :quota_project_id
|
538
|
+
@client = client
|
539
|
+
end
|
540
|
+
|
541
|
+
def update_from_hash hash, options
|
542
|
+
hash = stringify_hash_keys hash
|
543
|
+
hash["scope"] ||= options[:scope]
|
544
|
+
hash["target_audience"] ||= options[:target_audience]
|
545
|
+
@project_id ||= (hash["project_id"] || hash["project"])
|
546
|
+
@quota_project_id ||= hash["quota_project_id"]
|
547
|
+
@client = init_client hash, options
|
548
|
+
end
|
549
|
+
|
550
|
+
def update_from_filepath path, options
|
551
|
+
verify_keyfile_exists! path
|
552
|
+
json = JSON.parse ::File.read(path)
|
553
|
+
json["scope"] ||= options[:scope]
|
554
|
+
json["target_audience"] ||= options[:target_audience]
|
555
|
+
@project_id ||= (json["project_id"] || json["project"])
|
556
|
+
@quota_project_id ||= json["quota_project_id"]
|
557
|
+
@client = init_client json, options
|
558
|
+
end
|
370
559
|
end
|
371
560
|
end
|
372
561
|
end
|
@@ -64,13 +64,13 @@ module Google
|
|
64
64
|
CLOUD_SDK_CLIENT_ID = "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.app"\
|
65
65
|
"s.googleusercontent.com".freeze
|
66
66
|
|
67
|
-
CLOUD_SDK_CREDENTIALS_WARNING = "Your application has authenticated "\
|
68
|
-
"
|
69
|
-
"
|
70
|
-
|
71
|
-
|
72
|
-
"
|
73
|
-
"
|
67
|
+
CLOUD_SDK_CREDENTIALS_WARNING = "Your application has authenticated using end user "\
|
68
|
+
"credentials from Google Cloud SDK. We recommend that most server applications use "\
|
69
|
+
"service accounts instead. If your application continues to use end user credentials "\
|
70
|
+
'from Cloud SDK, you might receive a "quota exceeded" or "API not enabled" error. For '\
|
71
|
+
"more information about service accounts, see "\
|
72
|
+
"https://cloud.google.com/docs/authentication/. To suppress this message, set the "\
|
73
|
+
"GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS environment variable.".freeze
|
74
74
|
|
75
75
|
# make_creds proxies the construction of a credentials instance
|
76
76
|
#
|
@@ -103,7 +103,7 @@ module Google
|
|
103
103
|
return make_creds options.merge(json_key_io: f)
|
104
104
|
end
|
105
105
|
elsif service_account_env_vars? || authorized_user_env_vars?
|
106
|
-
|
106
|
+
make_creds options
|
107
107
|
end
|
108
108
|
rescue StandardError => e
|
109
109
|
raise "#{NOT_FOUND_ERROR}: #{e}"
|
@@ -163,11 +163,13 @@ module Google
|
|
163
163
|
raise "#{SYSTEM_DEFAULT_ERROR}: #{e}"
|
164
164
|
end
|
165
165
|
|
166
|
+
module_function
|
167
|
+
|
166
168
|
# Issues warning if cloud sdk client id is used
|
167
169
|
def warn_if_cloud_sdk_credentials client_id
|
170
|
+
return if ENV["GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS"]
|
168
171
|
warn CLOUD_SDK_CREDENTIALS_WARNING if client_id == CLOUD_SDK_CLIENT_ID
|
169
172
|
end
|
170
|
-
module_function :warn_if_cloud_sdk_credentials
|
171
173
|
|
172
174
|
# Finds project_id from gcloud CLI configuration
|
173
175
|
def load_gcloud_project_id
|
@@ -179,7 +181,6 @@ module Google
|
|
179
181
|
rescue StandardError
|
180
182
|
nil
|
181
183
|
end
|
182
|
-
module_function :load_gcloud_project_id
|
183
184
|
|
184
185
|
private
|
185
186
|
|
@@ -193,15 +194,13 @@ module Google
|
|
193
194
|
end
|
194
195
|
|
195
196
|
def service_account_env_vars?
|
196
|
-
[PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR].
|
197
|
-
ENV
|
198
|
-
end
|
197
|
+
([PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR] - ENV.keys).empty? &&
|
198
|
+
!ENV.to_h.fetch_values(PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR).join(" ").empty?
|
199
199
|
end
|
200
200
|
|
201
201
|
def authorized_user_env_vars?
|
202
|
-
[CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR].
|
203
|
-
ENV
|
204
|
-
end
|
202
|
+
([CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR] - ENV.keys).empty? &&
|
203
|
+
!ENV.to_h.fetch_values(CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR).join(" ").empty?
|
205
204
|
end
|
206
205
|
end
|
207
206
|
end
|
data/lib/googleauth/iam.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2020 Google LLC
|
3
4
|
#
|
4
5
|
# Redistribution and use in source and binary forms, with or without
|
5
6
|
# modification, are permitted provided that the following conditions are
|
@@ -27,32 +28,44 @@
|
|
27
28
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
29
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
30
|
|
30
|
-
spec_dir = File.expand_path File.join(File.dirname(__FILE__))
|
31
|
-
$LOAD_PATH.unshift spec_dir
|
32
|
-
$LOAD_PATH.uniq!
|
33
31
|
|
34
|
-
|
32
|
+
module Google
|
33
|
+
module Auth
|
34
|
+
module IDTokens
|
35
|
+
##
|
36
|
+
# Failed to obtain keys from the key source.
|
37
|
+
#
|
38
|
+
class KeySourceError < StandardError; end
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
##
|
41
|
+
# Failed to verify a token.
|
42
|
+
#
|
43
|
+
class VerificationError < StandardError; end
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
45
|
+
##
|
46
|
+
# Failed to verify a token because it is expired.
|
47
|
+
#
|
48
|
+
class ExpiredTokenError < VerificationError; end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
##
|
51
|
+
# Failed to verify a token because its signature did not match.
|
52
|
+
#
|
53
|
+
class SignatureError < VerificationError; end
|
48
54
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
##
|
56
|
+
# Failed to verify a token because its issuer did not match.
|
57
|
+
#
|
58
|
+
class IssuerMismatchError < VerificationError; end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Failed to verify a token because its audience did not match.
|
62
|
+
#
|
63
|
+
class AudienceMismatchError < VerificationError; end
|
53
64
|
|
54
|
-
|
55
|
-
|
56
|
-
|
65
|
+
##
|
66
|
+
# Failed to verify a token because its authorized party did not match.
|
67
|
+
#
|
68
|
+
class AuthorizedPartyMismatchError < VerificationError; end
|
69
|
+
end
|
57
70
|
end
|
58
71
|
end
|