googleauth 0.9.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.kokoro/continuous/linux.cfg +12 -2
  3. data/.kokoro/continuous/osx.cfg +5 -0
  4. data/.kokoro/continuous/post.cfg +30 -0
  5. data/.kokoro/continuous/windows.cfg +10 -0
  6. data/.kokoro/presubmit/linux.cfg +11 -1
  7. data/.kokoro/presubmit/osx.cfg +5 -0
  8. data/.kokoro/presubmit/windows.cfg +10 -0
  9. data/.kokoro/release.cfg +42 -1
  10. data/.repo-metadata.json +5 -0
  11. data/.rubocop.yml +12 -35
  12. data/CHANGELOG.md +32 -0
  13. data/Gemfile +8 -3
  14. data/README.md +7 -11
  15. data/Rakefile +48 -5
  16. data/googleauth.gemspec +7 -4
  17. data/integration/helper.rb +31 -0
  18. data/integration/id_tokens/key_source_test.rb +74 -0
  19. data/lib/googleauth.rb +1 -0
  20. data/lib/googleauth/application_default.rb +9 -9
  21. data/lib/googleauth/compute_engine.rb +30 -27
  22. data/lib/googleauth/credentials.rb +92 -22
  23. data/lib/googleauth/credentials_loader.rb +14 -15
  24. data/lib/googleauth/id_tokens.rb +233 -0
  25. data/lib/googleauth/id_tokens/errors.rb +71 -0
  26. data/lib/googleauth/id_tokens/key_sources.rb +394 -0
  27. data/lib/googleauth/id_tokens/verifier.rb +144 -0
  28. data/lib/googleauth/json_key_reader.rb +6 -2
  29. data/lib/googleauth/service_account.rb +16 -7
  30. data/lib/googleauth/signet.rb +8 -6
  31. data/lib/googleauth/user_authorizer.rb +8 -3
  32. data/lib/googleauth/user_refresh.rb +1 -1
  33. data/lib/googleauth/version.rb +1 -1
  34. data/lib/googleauth/web_user_authorizer.rb +1 -1
  35. data/rakelib/devsite_builder.rb +45 -0
  36. data/rakelib/link_checker.rb +64 -0
  37. data/rakelib/repo_metadata.rb +59 -0
  38. data/spec/googleauth/apply_auth_examples.rb +28 -5
  39. data/spec/googleauth/compute_engine_spec.rb +37 -13
  40. data/spec/googleauth/credentials_spec.rb +25 -6
  41. data/spec/googleauth/service_account_spec.rb +23 -16
  42. data/spec/googleauth/signet_spec.rb +15 -7
  43. data/spec/googleauth/user_authorizer_spec.rb +21 -1
  44. data/spec/googleauth/user_refresh_spec.rb +1 -1
  45. data/test/helper.rb +33 -0
  46. data/test/id_tokens/key_sources_test.rb +240 -0
  47. data/test/id_tokens/verifier_test.rb +269 -0
  48. metadata +45 -12
@@ -0,0 +1,59 @@
1
+ require "json"
2
+
3
+ class RepoMetadata
4
+ attr_reader :data
5
+
6
+ def initialize data
7
+ @data = data
8
+ normalize_data!
9
+ end
10
+
11
+ def allowed_fields
12
+ [
13
+ "name", "version", "language", "distribution-name",
14
+ "product-page", "github-repository", "issue-tracker"
15
+ ]
16
+ end
17
+
18
+ def build output_directory
19
+ fields = @data.to_a.map { |kv| "--#{kv[0]} #{kv[1]}" }
20
+ Dir.chdir output_directory do
21
+ cmd "python3 -m docuploader create-metadata #{fields.join ' '}"
22
+ end
23
+ end
24
+
25
+ def normalize_data!
26
+ require_relative "../lib/googleauth/version.rb"
27
+
28
+ @data.delete_if { |k, _| !allowed_fields.include?(k) }
29
+ @data["version"] = "v#{Google::Auth::VERSION}"
30
+ end
31
+
32
+ def [] key
33
+ data[key]
34
+ end
35
+
36
+ def []= key, value
37
+ @data[key] = value
38
+ end
39
+
40
+ def cmd line
41
+ puts line
42
+ output = `#{line}`
43
+ puts output
44
+ output
45
+ end
46
+
47
+ def self.from_source source
48
+ if source.is_a? RepoMetadata
49
+ data = source.data
50
+ elsif source.is_a? Hash
51
+ data = source
52
+ elsif File.file? source
53
+ data = JSON.parse File.read(source)
54
+ else
55
+ raise "Source must be a path, hash, or RepoMetadata instance"
56
+ end
57
+ RepoMetadata.new data
58
+ end
59
+ end
@@ -45,26 +45,37 @@ shared_examples "apply/apply! are OK" do
45
45
  # auth client
46
46
  describe "#fetch_access_token" do
47
47
  let(:token) { "1/abcdef1234567890" }
48
- let :stub do
48
+ let :access_stub do
49
49
  make_auth_stubs access_token: token
50
50
  end
51
+ let :id_stub do
52
+ make_auth_stubs id_token: token
53
+ end
51
54
 
52
55
  it "should set access_token to the fetched value" do
53
- stub
56
+ access_stub
54
57
  @client.fetch_access_token!
55
58
  expect(@client.access_token).to eq(token)
56
- expect(stub).to have_been_requested
59
+ expect(access_stub).to have_been_requested
60
+ end
61
+
62
+ it "should set id_token to the fetched value" do
63
+ skip unless @id_client
64
+ id_stub
65
+ @id_client.fetch_access_token!
66
+ expect(@id_client.id_token).to eq(token)
67
+ expect(id_stub).to have_been_requested
57
68
  end
58
69
 
59
70
  it "should notify refresh listeners after updating" do
60
- stub
71
+ access_stub
61
72
  expect do |b|
62
73
  @client.on_refresh(&b)
63
74
  @client.fetch_access_token!
64
75
  end.to yield_with_args(have_attributes(
65
76
  access_token: "1/abcdef1234567890"
66
77
  ))
67
- expect(stub).to have_been_requested
78
+ expect(access_stub).to have_been_requested
68
79
  end
69
80
  end
70
81
 
@@ -79,6 +90,18 @@ shared_examples "apply/apply! are OK" do
79
90
  expect(md).to eq(want)
80
91
  expect(stub).to have_been_requested
81
92
  end
93
+
94
+ it "should update the target hash with fetched ID token" do
95
+ skip unless @id_client
96
+ token = "1/abcdef1234567890"
97
+ stub = make_auth_stubs id_token: token
98
+
99
+ md = { foo: "bar" }
100
+ @id_client.apply! md
101
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
102
+ expect(md).to eq(want)
103
+ expect(stub).to have_been_requested
104
+ end
82
105
  end
83
106
 
84
107
  describe "updater_proc" do
@@ -37,31 +37,52 @@ require "googleauth/compute_engine"
37
37
  require "spec_helper"
38
38
 
39
39
  describe Google::Auth::GCECredentials do
40
- MD_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
40
+ MD_ACCESS_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
41
+ MD_ID_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://pubsub.googleapis.com/&format=full".freeze
41
42
  GCECredentials = Google::Auth::GCECredentials
42
43
 
43
44
  before :example do
44
45
  @client = GCECredentials.new
46
+ @id_client = GCECredentials.new target_audience: "https://pubsub.googleapis.com/"
45
47
  end
46
48
 
47
- def make_auth_stubs opts = {}
48
- access_token = opts[:access_token] || ""
49
- body = MultiJson.dump("access_token" => access_token,
50
- "token_type" => "Bearer",
51
- "expires_in" => 3600)
52
- stub_request(:get, MD_URI)
53
- .with(headers: { "Metadata-Flavor" => "Google" })
54
- .to_return(body: body,
55
- status: 200,
56
- headers: { "Content-Type" => "application/json" })
49
+ def make_auth_stubs opts
50
+ if opts[:access_token]
51
+ body = MultiJson.dump("access_token" => opts[:access_token],
52
+ "token_type" => "Bearer",
53
+ "expires_in" => 3600)
54
+
55
+ uri = MD_ACCESS_URI
56
+ uri += "?scopes=#{opts[:scope]}" if opts[:scope]
57
+
58
+ stub_request(:get, uri)
59
+ .with(headers: { "Metadata-Flavor" => "Google" })
60
+ .to_return(body: body,
61
+ status: 200,
62
+ headers: { "Content-Type" => "application/json" })
63
+ elsif opts[:id_token]
64
+ stub_request(:get, MD_ID_URI)
65
+ .with(headers: { "Metadata-Flavor" => "Google" })
66
+ .to_return(body: opts[:id_token],
67
+ status: 200,
68
+ headers: { "Content-Type" => "text/html" })
69
+ end
57
70
  end
58
71
 
59
72
  it_behaves_like "apply/apply! are OK"
60
73
 
61
74
  context "metadata is unavailable" do
62
75
  describe "#fetch_access_token" do
76
+ it "should pass scopes when requesting an access token" do
77
+ scope = "https://www.googleapis.com/auth/drive"
78
+ stub = make_auth_stubs access_token: "1/abcdef1234567890", scope: scope
79
+ @client = GCECredentials.new(scope: [scope])
80
+ @client.fetch_access_token!
81
+ expect(stub).to have_been_requested
82
+ end
83
+
63
84
  it "should fail if the metadata request returns a 404" do
64
- stub = stub_request(:get, MD_URI)
85
+ stub = stub_request(:get, MD_ACCESS_URI)
65
86
  .to_return(status: 404,
66
87
  headers: { "Metadata-Flavor" => "Google" })
67
88
  expect { @client.fetch_access_token! }
@@ -70,7 +91,7 @@ describe Google::Auth::GCECredentials do
70
91
  end
71
92
 
72
93
  it "should fail if the metadata request returns an unexpected code" do
73
- stub = stub_request(:get, MD_URI)
94
+ stub = stub_request(:get, MD_ACCESS_URI)
74
95
  .to_return(status: 503,
75
96
  headers: { "Metadata-Flavor" => "Google" })
76
97
  expect { @client.fetch_access_token! }
@@ -97,6 +118,7 @@ describe Google::Auth::GCECredentials do
97
118
  describe "#on_gce?" do
98
119
  it "should be true when Metadata-Flavor is Google" do
99
120
  stub = stub_request(:get, "http://169.254.169.254")
121
+ .with(headers: { "Metadata-Flavor" => "Google" })
100
122
  .to_return(status: 200,
101
123
  headers: { "Metadata-Flavor" => "Google" })
102
124
  expect(GCECredentials.on_gce?({}, true)).to eq(true)
@@ -105,6 +127,7 @@ describe Google::Auth::GCECredentials do
105
127
 
106
128
  it "should be false when Metadata-Flavor is not Google" do
107
129
  stub = stub_request(:get, "http://169.254.169.254")
130
+ .with(headers: { "Metadata-Flavor" => "Google" })
108
131
  .to_return(status: 200,
109
132
  headers: { "Metadata-Flavor" => "NotGoogle" })
110
133
  expect(GCECredentials.on_gce?({}, true)).to eq(false)
@@ -113,6 +136,7 @@ describe Google::Auth::GCECredentials do
113
136
 
114
137
  it "should be false if the response is not 200" do
115
138
  stub = stub_request(:get, "http://169.254.169.254")
139
+ .with(headers: { "Metadata-Flavor" => "Google" })
116
140
  .to_return(status: 404,
117
141
  headers: { "Metadata-Flavor" => "NotGoogle" })
118
142
  expect(GCECredentials.on_gce?({}, true)).to eq(false)
@@ -36,12 +36,13 @@ require "googleauth"
36
36
  describe Google::Auth::Credentials, :private do
37
37
  let :default_keyfile_hash do
38
38
  {
39
- "private_key_id" => "testabc1234567890xyz",
40
- "private_key" => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
41
- "client_email" => "credz-testabc1234567890xyz@developer.gserviceaccount.com",
42
- "client_id" => "credz-testabc1234567890xyz.apps.googleusercontent.com",
43
- "type" => "service_account",
44
- "project_id" => "a_project_id"
39
+ "private_key_id" => "testabc1234567890xyz",
40
+ "private_key" => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
41
+ "client_email" => "credz-testabc1234567890xyz@developer.gserviceaccount.com",
42
+ "client_id" => "credz-testabc1234567890xyz.apps.googleusercontent.com",
43
+ "type" => "service_account",
44
+ "project_id" => "a_project_id",
45
+ "quota_project_id" => "b_project_id"
45
46
  }
46
47
  end
47
48
 
@@ -118,6 +119,7 @@ describe Google::Auth::Credentials, :private do
118
119
  expect(creds).to be_a_kind_of(TestCredentials1)
119
120
  expect(creds.client).to eq(mocked_signet)
120
121
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
122
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
121
123
  end
122
124
 
123
125
  it "subclasses can use PATH_ENV_VARS to get keyfile path" do
@@ -128,6 +130,7 @@ describe Google::Auth::Credentials, :private do
128
130
  DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
129
131
  end
130
132
 
133
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
131
134
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
132
135
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
133
136
  allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
@@ -152,6 +155,7 @@ describe Google::Auth::Credentials, :private do
152
155
  expect(creds).to be_a_kind_of(TestCredentials2)
153
156
  expect(creds.client).to eq(mocked_signet)
154
157
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
158
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
155
159
  end
156
160
 
157
161
  it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
@@ -164,6 +168,7 @@ describe Google::Auth::Credentials, :private do
164
168
  DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
165
169
  end
166
170
 
171
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
167
172
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
168
173
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
169
174
  allow(::File).to receive(:file?).with(test_json_env_val) { false }
@@ -188,6 +193,7 @@ describe Google::Auth::Credentials, :private do
188
193
  expect(creds).to be_a_kind_of(TestCredentials3)
189
194
  expect(creds.client).to eq(mocked_signet)
190
195
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
196
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
191
197
  end
192
198
 
193
199
  it "subclasses can use DEFAULT_PATHS to get keyfile path" do
@@ -198,6 +204,7 @@ describe Google::Auth::Credentials, :private do
198
204
  DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
199
205
  end
200
206
 
207
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
201
208
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
202
209
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
203
210
  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
@@ -222,6 +229,7 @@ describe Google::Auth::Credentials, :private do
222
229
  expect(creds).to be_a_kind_of(TestCredentials4)
223
230
  expect(creds.client).to eq(mocked_signet)
224
231
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
232
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
225
233
  end
226
234
 
227
235
  it "subclasses that find no matches default to Google::Auth.get_application_default" do
@@ -232,6 +240,7 @@ describe Google::Auth::Credentials, :private do
232
240
  DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
233
241
  end
234
242
 
243
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
235
244
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
236
245
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
237
246
  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
@@ -262,6 +271,7 @@ describe Google::Auth::Credentials, :private do
262
271
  expect(creds).to be_a_kind_of(TestCredentials5)
263
272
  expect(creds.client).to eq(mocked_signet)
264
273
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
274
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
265
275
  end
266
276
  end
267
277
 
@@ -301,6 +311,7 @@ describe Google::Auth::Credentials, :private do
301
311
  expect(creds).to be_a_kind_of(TestCredentials11)
302
312
  expect(creds.client).to eq(mocked_signet)
303
313
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
314
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
304
315
  end
305
316
 
306
317
  it "subclasses can use PATH_ENV_VARS to get keyfile path" do
@@ -310,6 +321,7 @@ describe Google::Auth::Credentials, :private do
310
321
  self.paths = ["~/default/path/to/file.txt"]
311
322
  end
312
323
 
324
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
313
325
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
314
326
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
315
327
  allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
@@ -334,6 +346,7 @@ describe Google::Auth::Credentials, :private do
334
346
  expect(creds).to be_a_kind_of(TestCredentials12)
335
347
  expect(creds.client).to eq(mocked_signet)
336
348
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
349
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
337
350
  end
338
351
 
339
352
  it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
@@ -345,6 +358,7 @@ describe Google::Auth::Credentials, :private do
345
358
  self.paths = ["~/default/path/to/file.txt"]
346
359
  end
347
360
 
361
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
348
362
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
349
363
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
350
364
  allow(::File).to receive(:file?).with(test_json_env_val) { false }
@@ -369,6 +383,7 @@ describe Google::Auth::Credentials, :private do
369
383
  expect(creds).to be_a_kind_of(TestCredentials13)
370
384
  expect(creds.client).to eq(mocked_signet)
371
385
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
386
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
372
387
  end
373
388
 
374
389
  it "subclasses can use DEFAULT_PATHS to get keyfile path" do
@@ -378,6 +393,7 @@ describe Google::Auth::Credentials, :private do
378
393
  self.paths = ["~/default/path/to/file.txt"]
379
394
  end
380
395
 
396
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
381
397
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
382
398
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
383
399
  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
@@ -402,6 +418,7 @@ describe Google::Auth::Credentials, :private do
402
418
  expect(creds).to be_a_kind_of(TestCredentials14)
403
419
  expect(creds.client).to eq(mocked_signet)
404
420
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
421
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
405
422
  end
406
423
 
407
424
  it "subclasses that find no matches default to Google::Auth.get_application_default" do
@@ -411,6 +428,7 @@ describe Google::Auth::Credentials, :private do
411
428
  self.paths = ["~/default/path/to/file.txt"]
412
429
  end
413
430
 
431
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
414
432
  allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
415
433
  allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
416
434
  allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
@@ -441,6 +459,7 @@ describe Google::Auth::Credentials, :private do
441
459
  expect(creds).to be_a_kind_of(TestCredentials15)
442
460
  expect(creds.client).to eq(mocked_signet)
443
461
  expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
462
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
444
463
  end
445
464
  end
446
465
 
@@ -112,12 +112,13 @@ describe Google::Auth::ServiceAccountCredentials do
112
112
  let(:client_email) { "app@developer.gserviceaccount.com" }
113
113
  let :cred_json do
114
114
  {
115
- private_key_id: "a_private_key_id",
116
- private_key: @key.to_pem,
117
- client_email: client_email,
118
- client_id: "app.apps.googleusercontent.com",
119
- type: "service_account",
120
- project_id: "a_project_id"
115
+ private_key_id: "a_private_key_id",
116
+ private_key: @key.to_pem,
117
+ client_email: client_email,
118
+ client_id: "app.apps.googleusercontent.com",
119
+ type: "service_account",
120
+ project_id: "a_project_id",
121
+ quota_project_id: "b_project_id"
121
122
  }
122
123
  end
123
124
 
@@ -127,24 +128,28 @@ describe Google::Auth::ServiceAccountCredentials do
127
128
  json_key_io: StringIO.new(cred_json_text),
128
129
  scope: "https://www.googleapis.com/auth/userinfo.profile"
129
130
  )
131
+ @id_client = ServiceAccountCredentials.make_creds(
132
+ json_key_io: StringIO.new(cred_json_text),
133
+ target_audience: "https://pubsub.googleapis.com/"
134
+ )
130
135
  end
131
136
 
132
- def make_auth_stubs opts = {}
133
- access_token = opts[:access_token] || ""
134
- body = MultiJson.dump("access_token" => access_token,
135
- "token_type" => "Bearer",
136
- "expires_in" => 3600)
137
+ def make_auth_stubs opts
138
+ body_fields = { "token_type" => "Bearer", "expires_in" => 3600 }
139
+ body_fields["access_token"] = opts[:access_token] if opts[:access_token]
140
+ body_fields["id_token"] = opts[:id_token] if opts[:id_token]
141
+ body = MultiJson.dump body_fields
137
142
  blk = proc do |request|
138
143
  params = Addressable::URI.form_unencode request.body
139
- _claim, _header = JWT.decode(params.assoc("assertion").last,
140
- @key.public_key, true,
141
- algorithm: "RS256")
144
+ claim, _header = JWT.decode(params.assoc("assertion").last,
145
+ @key.public_key, true,
146
+ algorithm: "RS256")
147
+ !opts[:id_token] || claim["target_audience"] == "https://pubsub.googleapis.com/"
142
148
  end
143
149
  stub_request(:post, "https://www.googleapis.com/oauth2/v4/token")
144
150
  .with(body: hash_including(
145
151
  "grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"
146
- ),
147
- &blk)
152
+ ), &blk)
148
153
  .to_return(body: body,
149
154
  status: 200,
150
155
  headers: { "Content-Type" => "application/json" })
@@ -285,6 +290,7 @@ describe Google::Auth::ServiceAccountCredentials do
285
290
  ENV["APPDATA"] = dir
286
291
  credentials = @clz.from_well_known_path @scope
287
292
  expect(credentials.project_id).to eq(cred_json[:project_id])
293
+ expect(credentials.quota_project_id).to eq(cred_json[:quota_project_id])
288
294
  end
289
295
  end
290
296
 
@@ -476,6 +482,7 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
476
482
  ENV["APPDATA"] = dir
477
483
  credentials = clz.from_well_known_path @scope
478
484
  expect(credentials.project_id).to eq(cred_json[:project_id])
485
+ expect(credentials.quota_project_id).to be_nil
479
486
  end
480
487
  end
481
488
  end
@@ -47,18 +47,26 @@ describe Signet::OAuth2::Client do
47
47
  audience: "https://oauth2.googleapis.com/token",
48
48
  signing_key: @key
49
49
  )
50
+ @id_client = Signet::OAuth2::Client.new(
51
+ token_credential_uri: "https://oauth2.googleapis.com/token",
52
+ target_audience: "https://pubsub.googleapis.com/",
53
+ issuer: "app@example.com",
54
+ audience: "https://oauth2.googleapis.com/token",
55
+ signing_key: @key
56
+ )
50
57
  end
51
58
 
52
59
  def make_auth_stubs opts
53
- access_token = opts[:access_token] || ""
54
- body = MultiJson.dump("access_token" => access_token,
55
- "token_type" => "Bearer",
56
- "expires_in" => 3600)
60
+ body_fields = { "token_type" => "Bearer", "expires_in" => 3600 }
61
+ body_fields["access_token"] = opts[:access_token] if opts[:access_token]
62
+ body_fields["id_token"] = opts[:id_token] if opts[:id_token]
63
+ body = MultiJson.dump body_fields
57
64
  blk = proc do |request|
58
65
  params = Addressable::URI.form_unencode request.body
59
- _claim, _header = JWT.decode(params.assoc("assertion").last,
60
- @key.public_key, true,
61
- algorithm: "RS256")
66
+ claim, _header = JWT.decode(params.assoc("assertion").last,
67
+ @key.public_key, true,
68
+ algorithm: "RS256")
69
+ !opts[:id_token] || claim["target_audience"] == "https://pubsub.googleapis.com/"
62
70
  end
63
71
  with_params = { body: hash_including(
64
72
  "grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer"