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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.md +113 -21
  4. data/README.md +13 -15
  5. data/SECURITY.md +7 -0
  6. data/lib/googleauth/application_default.rb +9 -9
  7. data/lib/googleauth/compute_engine.rb +55 -30
  8. data/lib/googleauth/credentials.rb +253 -64
  9. data/lib/googleauth/credentials_loader.rb +15 -16
  10. data/lib/googleauth/iam.rb +1 -1
  11. data/{spec/googleauth/stores/store_examples.rb → lib/googleauth/id_tokens/errors.rb} +36 -23
  12. data/lib/googleauth/id_tokens/key_sources.rb +396 -0
  13. data/lib/googleauth/id_tokens/verifier.rb +142 -0
  14. data/lib/googleauth/id_tokens.rb +233 -0
  15. data/lib/googleauth/json_key_reader.rb +6 -2
  16. data/lib/googleauth/scope_util.rb +1 -1
  17. data/lib/googleauth/service_account.rb +61 -36
  18. data/lib/googleauth/signet.rb +9 -7
  19. data/lib/googleauth/stores/file_token_store.rb +1 -0
  20. data/lib/googleauth/stores/redis_token_store.rb +1 -0
  21. data/lib/googleauth/user_authorizer.rb +8 -3
  22. data/lib/googleauth/user_refresh.rb +1 -1
  23. data/lib/googleauth/version.rb +1 -1
  24. data/lib/googleauth/web_user_authorizer.rb +5 -8
  25. data/lib/googleauth.rb +1 -0
  26. metadata +33 -76
  27. data/.github/CONTRIBUTING.md +0 -74
  28. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -36
  29. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -21
  30. data/.github/ISSUE_TEMPLATE/support_request.md +0 -7
  31. data/.gitignore +0 -36
  32. data/.kokoro/build.bat +0 -16
  33. data/.kokoro/build.sh +0 -4
  34. data/.kokoro/continuous/common.cfg +0 -24
  35. data/.kokoro/continuous/linux.cfg +0 -15
  36. data/.kokoro/continuous/osx.cfg +0 -3
  37. data/.kokoro/continuous/windows.cfg +0 -19
  38. data/.kokoro/osx.sh +0 -4
  39. data/.kokoro/presubmit/common.cfg +0 -24
  40. data/.kokoro/presubmit/linux.cfg +0 -14
  41. data/.kokoro/presubmit/osx.cfg +0 -3
  42. data/.kokoro/presubmit/windows.cfg +0 -19
  43. data/.kokoro/release.cfg +0 -53
  44. data/.kokoro/trampoline.bat +0 -10
  45. data/.kokoro/trampoline.sh +0 -4
  46. data/.rspec +0 -2
  47. data/.rubocop.yml +0 -42
  48. data/Gemfile +0 -25
  49. data/Rakefile +0 -89
  50. data/googleauth.gemspec +0 -35
  51. data/spec/googleauth/apply_auth_examples.rb +0 -148
  52. data/spec/googleauth/client_id_spec.rb +0 -160
  53. data/spec/googleauth/compute_engine_spec.rb +0 -122
  54. data/spec/googleauth/credentials_spec.rb +0 -459
  55. data/spec/googleauth/get_application_default_spec.rb +0 -286
  56. data/spec/googleauth/iam_spec.rb +0 -80
  57. data/spec/googleauth/scope_util_spec.rb +0 -77
  58. data/spec/googleauth/service_account_spec.rb +0 -482
  59. data/spec/googleauth/signet_spec.rb +0 -134
  60. data/spec/googleauth/stores/file_token_store_spec.rb +0 -57
  61. data/spec/googleauth/stores/redis_token_store_spec.rb +0 -50
  62. data/spec/googleauth/user_authorizer_spec.rb +0 -323
  63. data/spec/googleauth/user_refresh_spec.rb +0 -359
  64. data/spec/googleauth/web_user_authorizer_spec.rb +0 -172
  65. data/spec/spec_helper.rb +0 -92
  66. /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 responsible for representing the authentication when connecting to an API. This
40
- # class is also intended to be inherited by API-specific classes.
41
- class Credentials
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
- return @token_credential_uri unless @token_credential_uri.nil?
59
-
60
- const_get :TOKEN_CREDENTIAL_URI if const_defined? :TOKEN_CREDENTIAL_URI
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
- return @audience unless @audience.nil?
81
-
82
- const_get :AUDIENCE if const_defined? :AUDIENCE
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
- # @return [String, Array<String>]
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
- return @scope unless @scope.nil?
104
-
105
- tmp_scope = []
106
- # Pull in values is the SCOPE constant exists.
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
- # @param [String, Array<String>] new_scope
115
- # @return [String, Array<String>]
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
- return @env_vars unless @env_vars.nil?
200
+ env_vars_internal || []
201
+ end
130
202
 
131
- # Pull values when PATH_ENV_VARS or JSON_ENV_VARS constants exists.
132
- tmp_env_vars = []
133
- tmp_env_vars << const_get(:PATH_ENV_VARS) if const_defined? :PATH_ENV_VARS
134
- tmp_env_vars << const_get(:JSON_ENV_VARS) if const_defined? :JSON_ENV_VARS
135
- tmp_env_vars.flatten.uniq
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>] new_env_vars
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
- return @paths unless @paths.nil?
235
+ paths_internal || []
236
+ end
156
237
 
157
- tmp_paths = []
158
- # Pull in values is the DEFAULT_PATHS constant exists.
159
- tmp_paths << const_get(:DEFAULT_PATHS) if const_defined? :DEFAULT_PATHS
160
- tmp_paths.flatten.uniq
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>] new_paths
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
- if keyfile.is_a? Signet::OAuth2::Client
243
- @client = keyfile
244
- @project_id ||= keyfile.project_id if keyfile.respond_to? :project_id
245
- elsif keyfile.is_a? Hash
246
- hash = stringify_hash_keys keyfile
247
- hash["scope"] ||= scope
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
- verify_keyfile_exists! keyfile
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
- return new str, options if ::File.file? str
303
- return new ::JSON.parse(str), options rescue nil
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
- .select { |p| ::File.file? p }
313
- .each do |file|
314
- return new file, options
315
- end
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
- client = Google::Auth.get_application_default scope
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
- Hash[hash.map { |k, v| [k.to_s, v] }]
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
- "using end user credentials from Google Cloud SDK. We recommend that "\
69
- "most server applications use service accounts instead. If your "\
70
- "application continues to use end user credentials from Cloud SDK, "\
71
- 'you might receive a "quota exceeded" or "API not enabled" error. For'\
72
- " more information about service accounts, see "\
73
- "https://cloud.google.com/docs/authentication/.".freeze
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
- return make_creds options
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].all? do |key|
197
- ENV[key] && !ENV[key].empty?
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].all? do |key|
203
- ENV[key] && !ENV[key].empty?
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
@@ -68,7 +68,7 @@ module Google
68
68
  # Returns a reference to the #apply method, suitable for passing as
69
69
  # a closure
70
70
  def updater_proc
71
- lambda(&method(:apply))
71
+ proc { |a_hash, _opts = {}| apply a_hash }
72
72
  end
73
73
  end
74
74
  end
@@ -1,5 +1,6 @@
1
- # Copyright 2015, Google Inc.
2
- # All rights reserved.
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
- require "spec_helper"
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
- shared_examples "token store" do
37
- before :each do
38
- store.store "default", "test"
39
- end
40
+ ##
41
+ # Failed to verify a token.
42
+ #
43
+ class VerificationError < StandardError; end
40
44
 
41
- it "should return a stored value" do
42
- expect(store.load("default")).to eq "test"
43
- end
45
+ ##
46
+ # Failed to verify a token because it is expired.
47
+ #
48
+ class ExpiredTokenError < VerificationError; end
44
49
 
45
- it "should return nil for missing tokens" do
46
- expect(store.load("notavalidkey")).to be_nil
47
- end
50
+ ##
51
+ # Failed to verify a token because its signature did not match.
52
+ #
53
+ class SignatureError < VerificationError; end
48
54
 
49
- it "should return nil for deleted tokens" do
50
- store.delete "default"
51
- expect(store.load("default")).to be_nil
52
- end
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
- it "should save overwrite values on store" do
55
- store.store "default", "test2"
56
- expect(store.load("default")).to eq "test2"
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