• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *    * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *    * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *
15  *    * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package com.google.auth.oauth2;
33 
34 import static org.junit.Assert.*;
35 
36 import com.google.api.client.json.GenericJson;
37 import com.google.api.client.util.Clock;
38 import com.google.auth.Credentials;
39 import com.google.auth.TestUtils;
40 import com.google.auth.http.HttpTransportFactory;
41 import com.google.auth.oauth2.ExternalAccountAuthorizedUserCredentialsTest.MockExternalAccountAuthorizedUserCredentialsTransportFactory;
42 import com.google.auth.oauth2.IdentityPoolCredentialsTest.MockExternalAccountCredentialsTransportFactory;
43 import com.google.auth.oauth2.ImpersonatedCredentialsTest.MockIAMCredentialsServiceTransportFactory;
44 import com.google.common.collect.ImmutableList;
45 import java.io.ByteArrayInputStream;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.net.URI;
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.concurrent.atomic.AtomicReference;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.junit.runners.JUnit4;
58 
59 /** Test case for {@link GoogleCredentials}. */
60 @RunWith(JUnit4.class)
61 public class GoogleCredentialsTest extends BaseSerializationTest {
62 
63   private static final String SA_CLIENT_EMAIL =
64       "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr@developer.gserviceaccount.com";
65   private static final String SA_CLIENT_ID =
66       "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com";
67   private static final String SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d";
68   private static final String SA_PRIVATE_KEY_PKCS8 =
69       ServiceAccountCredentialsTest.PRIVATE_KEY_PKCS8;
70   private static final String GDCH_SA_FORMAT_VERSION = GdchCredentials.SUPPORTED_FORMAT_VERSION;
71   private static final String GDCH_SA_PROJECT_ID = "gdch-service-account-project-id";
72   private static final String GDCH_SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d";
73   private static final String GDCH_SA_PRIVATE_KEY_PKC8 = GdchCredentialsTest.PRIVATE_KEY_PKCS8;
74   private static final String GDCH_SA_SERVICE_IDENTITY_NAME =
75       "gdch-service-account-service-identity-name";
76   private static final URI GDCH_SA_TOKEN_SERVER_URI =
77       URI.create("https://service-identity.domain/authenticate");
78   private static final String GDCH_SA_CA_CERT_FILE_NAME = "cert.pem";
79   private static final String GDCH_SA_CA_CERT_PATH =
80       GdchCredentialsTest.class.getClassLoader().getResource(GDCH_SA_CA_CERT_FILE_NAME).getPath();
81   private static final URI GDCH_API_AUDIENCE = URI.create("https://gdch-api-audience");
82   private static final String USER_CLIENT_SECRET = "jakuaL9YyieakhECKL2SwZcu";
83   private static final String USER_CLIENT_ID = "ya29.1.AADtN_UtlxN3PuGAxrN2XQnZTVRvDyVWnYq4I6dws";
84   private static final String REFRESH_TOKEN = "1/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY";
85   private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2";
86   private static final HttpTransportFactory DUMMY_TRANSPORT_FACTORY =
87       new MockTokenServerTransportFactory();
88   private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo");
89   private static final String QUOTA_PROJECT = "sample-quota-project-id";
90 
91   private static final Collection<String> SCOPES =
92       Collections.unmodifiableCollection(Arrays.asList("scope1", "scope2"));
93   private static final Collection<String> DEFAULT_SCOPES =
94       Collections.unmodifiableCollection(Arrays.asList("scope3"));
95   private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com";
96   private static final String TPC_UNIVERSE = "foo.bar";
97 
98   @Test
getApplicationDefault_nullTransport_throws()99   public void getApplicationDefault_nullTransport_throws() throws IOException {
100     try {
101       GoogleCredentials.getApplicationDefault(null);
102       fail();
103     } catch (NullPointerException expected) {
104       // Expected
105     }
106   }
107 
108   @Test
fromStream_unknownType_throws()109   public void fromStream_unknownType_throws() throws IOException {
110     MockHttpTransportFactory transportFactory = new MockHttpTransportFactory();
111     GenericJson json = new GenericJson();
112     json.put("type", "unsupported_credential");
113     InputStream stream = TestUtils.jsonToInputStream(json);
114     try {
115       GoogleCredentials.fromStream(stream, transportFactory);
116       fail("Should throw if type is unknown.");
117     } catch (IOException expected) {
118       String expectedError =
119           "Error reading credentials from stream, 'type' value "
120               + "'unsupported_credential' not recognized. Valid values are 'authorized_user', "
121               + "'service_account', 'gdch_service_account', 'external_account', "
122               + "'external_account_authorized_user', 'impersonated_service_account'.";
123       assertTrue(expected.getMessage().contains(expectedError));
124     }
125   }
126 
127   @Test
fromStream_nullTransport_throws()128   public void fromStream_nullTransport_throws() throws IOException {
129     InputStream stream = new ByteArrayInputStream("foo".getBytes());
130     try {
131       GoogleCredentials.fromStream(stream, null);
132       fail("Should throw if HttpTransportFactory is null");
133     } catch (NullPointerException expected) {
134       // Expected
135     }
136   }
137 
138   @Test
fromStream_noType_throws()139   public void fromStream_noType_throws() throws IOException {
140     MockHttpTransportFactory transportFactory = new MockHttpTransportFactory();
141     GenericJson json =
142         ServiceAccountCredentialsTest.writeServiceAccountJson(
143             "project_id", QUOTA_PROJECT, "universe");
144     json.remove("type");
145     InputStream stream = TestUtils.jsonToInputStream(json);
146     try {
147       GoogleCredentials.fromStream(stream, transportFactory);
148       fail("Should throw if type is unknown.");
149     } catch (IOException expected) {
150       String expectedError = "Error reading credentials from stream, 'type' field not specified.";
151       assertEquals(expectedError, expected.getMessage());
152     }
153   }
154 
155   @Test
fromStream_nullStream_throws()156   public void fromStream_nullStream_throws() throws IOException {
157     MockHttpTransportFactory transportFactory = new MockHttpTransportFactory();
158     try {
159       GoogleCredentials.fromStream(null, transportFactory);
160       fail("Should throw if InputStream is null");
161     } catch (NullPointerException expected) {
162       // Expected
163     }
164   }
165 
166   @Test
fromStream_serviceAccount_noUniverse_providesToken()167   public void fromStream_serviceAccount_noUniverse_providesToken() throws IOException {
168     MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
169     transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN);
170     InputStream serviceAccountStream =
171         ServiceAccountCredentialsTest.writeServiceAccountStream(
172             SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);
173 
174     GoogleCredentials credentials =
175         GoogleCredentials.fromStream(serviceAccountStream, transportFactory);
176 
177     assertNotNull(credentials);
178     assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
179     assertEquals(false, credentials.isExplicitUniverseDomain());
180     credentials = credentials.createScoped(SCOPES);
181     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
182     TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN);
183 
184     credentials = credentials.createScoped(SCOPES, DEFAULT_SCOPES);
185     metadata = credentials.getRequestMetadata(CALL_URI);
186     TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN);
187   }
188 
189   @Test
fromStream_serviceAccount_Universe_noToken()190   public void fromStream_serviceAccount_Universe_noToken() throws IOException {
191     MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
192     transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN);
193     InputStream serviceAccountStream =
194         ServiceAccountCredentialsTest.writeServiceAccountStream(
195             SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, TPC_UNIVERSE);
196 
197     GoogleCredentials credentials =
198         GoogleCredentials.fromStream(serviceAccountStream, transportFactory);
199 
200     assertNotNull(credentials);
201     assertEquals(TPC_UNIVERSE, credentials.getUniverseDomain());
202     assertEquals(true, credentials.isExplicitUniverseDomain());
203     credentials = credentials.createScoped(SCOPES);
204     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
205     assertNotNull(((ServiceAccountCredentials) credentials).getSelfSignedJwtCredentialsWithScope());
206   }
207 
208   @Test
fromStream_serviceAccountNoClientId_throws()209   public void fromStream_serviceAccountNoClientId_throws() throws IOException {
210     InputStream serviceAccountStream =
211         ServiceAccountCredentialsTest.writeServiceAccountStream(
212             null, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);
213 
214     testFromStreamException(serviceAccountStream, "client_id");
215   }
216 
217   @Test
fromStream_serviceAccountNoClientEmail_throws()218   public void fromStream_serviceAccountNoClientEmail_throws() throws IOException {
219     InputStream serviceAccountStream =
220         ServiceAccountCredentialsTest.writeServiceAccountStream(
221             SA_CLIENT_ID, null, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID);
222 
223     testFromStreamException(serviceAccountStream, "client_email");
224   }
225 
226   @Test
fromStream_serviceAccountNoPrivateKey_throws()227   public void fromStream_serviceAccountNoPrivateKey_throws() throws IOException {
228     InputStream serviceAccountStream =
229         ServiceAccountCredentialsTest.writeServiceAccountStream(
230             SA_CLIENT_ID, SA_CLIENT_EMAIL, null, SA_PRIVATE_KEY_ID);
231 
232     testFromStreamException(serviceAccountStream, "private_key");
233   }
234 
235   @Test
fromStream_serviceAccountNoPrivateKeyId_throws()236   public void fromStream_serviceAccountNoPrivateKeyId_throws() throws IOException {
237     InputStream serviceAccountStream =
238         ServiceAccountCredentialsTest.writeServiceAccountStream(
239             SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, null);
240 
241     testFromStreamException(serviceAccountStream, "private_key_id");
242   }
243 
244   @Test
fromStream_gdchServiceAccount_correct()245   public void fromStream_gdchServiceAccount_correct() throws IOException {
246     MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
247     InputStream gdchServiceAccountStream =
248         GdchCredentialsTest.writeGdchServiceAccountStream(
249             GDCH_SA_FORMAT_VERSION,
250             GDCH_SA_PROJECT_ID,
251             GDCH_SA_PRIVATE_KEY_ID,
252             GDCH_SA_PRIVATE_KEY_PKC8,
253             GDCH_SA_SERVICE_IDENTITY_NAME,
254             GDCH_SA_CA_CERT_PATH,
255             GDCH_SA_TOKEN_SERVER_URI);
256     GoogleCredentials credentials =
257         GoogleCredentials.fromStream(gdchServiceAccountStream, transportFactory);
258 
259     assertNotNull(credentials);
260     assertTrue(credentials instanceof GdchCredentials);
261     assertEquals(GDCH_SA_PROJECT_ID, ((GdchCredentials) credentials).getProjectId());
262     assertEquals(
263         GDCH_SA_SERVICE_IDENTITY_NAME, ((GdchCredentials) credentials).getServiceIdentityName());
264     assertEquals(GDCH_SA_TOKEN_SERVER_URI, ((GdchCredentials) credentials).getTokenServerUri());
265     assertEquals(GDCH_SA_CA_CERT_PATH, ((GdchCredentials) credentials).getCaCertPath());
266     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
267     assertNull(((GdchCredentials) credentials).getApiAudience());
268 
269     credentials = ((GdchCredentials) credentials).createWithGdchAudience(GDCH_API_AUDIENCE);
270     assertNotNull(credentials);
271     assertTrue(credentials instanceof GdchCredentials);
272     assertEquals(GDCH_SA_PROJECT_ID, ((GdchCredentials) credentials).getProjectId());
273     assertEquals(
274         GDCH_SA_SERVICE_IDENTITY_NAME, ((GdchCredentials) credentials).getServiceIdentityName());
275     assertEquals(GDCH_SA_TOKEN_SERVER_URI, ((GdchCredentials) credentials).getTokenServerUri());
276     assertEquals(GDCH_SA_CA_CERT_PATH, ((GdchCredentials) credentials).getCaCertPath());
277     assertNotNull(((GdchCredentials) credentials).getApiAudience());
278   }
279 
280   @Test
fromStream_gdchServiceAccountNoFormatVersion_throws()281   public void fromStream_gdchServiceAccountNoFormatVersion_throws() throws IOException {
282     InputStream gdchServiceAccountStream =
283         GdchCredentialsTest.writeGdchServiceAccountStream(
284             null,
285             GDCH_SA_PROJECT_ID,
286             GDCH_SA_PRIVATE_KEY_ID,
287             GDCH_SA_PRIVATE_KEY_PKC8,
288             GDCH_SA_SERVICE_IDENTITY_NAME,
289             GDCH_SA_CA_CERT_PATH,
290             GDCH_SA_TOKEN_SERVER_URI);
291 
292     testFromStreamException(gdchServiceAccountStream, "format_version");
293   }
294 
295   @Test
fromStream_gdchServiceAccountNoProjectId_throws()296   public void fromStream_gdchServiceAccountNoProjectId_throws() throws IOException {
297     InputStream gdchServiceAccountStream =
298         GdchCredentialsTest.writeGdchServiceAccountStream(
299             GDCH_SA_FORMAT_VERSION,
300             null,
301             GDCH_SA_PRIVATE_KEY_ID,
302             GDCH_SA_PRIVATE_KEY_PKC8,
303             GDCH_SA_SERVICE_IDENTITY_NAME,
304             GDCH_SA_CA_CERT_PATH,
305             GDCH_SA_TOKEN_SERVER_URI);
306 
307     testFromStreamException(gdchServiceAccountStream, "project");
308   }
309 
310   @Test
fromStream_gdchServiceAccountNoPrivateKeyId_throws()311   public void fromStream_gdchServiceAccountNoPrivateKeyId_throws() throws IOException {
312     InputStream gdchServiceAccountStream =
313         GdchCredentialsTest.writeGdchServiceAccountStream(
314             GDCH_SA_FORMAT_VERSION,
315             GDCH_SA_PROJECT_ID,
316             null,
317             GDCH_SA_PRIVATE_KEY_PKC8,
318             GDCH_SA_SERVICE_IDENTITY_NAME,
319             GDCH_SA_CA_CERT_PATH,
320             GDCH_SA_TOKEN_SERVER_URI);
321 
322     testFromStreamException(gdchServiceAccountStream, "private_key_id");
323   }
324 
325   @Test
fromStream_gdchServiceAccountNoPrivateKey_throws()326   public void fromStream_gdchServiceAccountNoPrivateKey_throws() throws IOException {
327     InputStream gdchServiceAccountStream =
328         GdchCredentialsTest.writeGdchServiceAccountStream(
329             GDCH_SA_FORMAT_VERSION,
330             GDCH_SA_PROJECT_ID,
331             GDCH_SA_PRIVATE_KEY_ID,
332             null,
333             GDCH_SA_SERVICE_IDENTITY_NAME,
334             GDCH_SA_CA_CERT_PATH,
335             GDCH_SA_TOKEN_SERVER_URI);
336 
337     testFromStreamException(gdchServiceAccountStream, "private_key");
338   }
339 
340   @Test
fromStream_gdchServiceAccountNoServiceIdentityName_throws()341   public void fromStream_gdchServiceAccountNoServiceIdentityName_throws() throws IOException {
342     InputStream gdchServiceAccountStream =
343         GdchCredentialsTest.writeGdchServiceAccountStream(
344             GDCH_SA_FORMAT_VERSION,
345             GDCH_SA_PROJECT_ID,
346             GDCH_SA_PRIVATE_KEY_ID,
347             GDCH_SA_PRIVATE_KEY_PKC8,
348             null,
349             GDCH_SA_CA_CERT_PATH,
350             GDCH_SA_TOKEN_SERVER_URI);
351 
352     testFromStreamException(gdchServiceAccountStream, "name");
353   }
354 
355   @Test
fromStream_gdchServiceAccountNoTokenServerUri_throws()356   public void fromStream_gdchServiceAccountNoTokenServerUri_throws() throws IOException {
357     InputStream gdchServiceAccountStream =
358         GdchCredentialsTest.writeGdchServiceAccountStream(
359             GDCH_SA_FORMAT_VERSION,
360             GDCH_SA_PROJECT_ID,
361             GDCH_SA_PRIVATE_KEY_ID,
362             GDCH_SA_PRIVATE_KEY_PKC8,
363             GDCH_SA_SERVICE_IDENTITY_NAME,
364             GDCH_SA_CA_CERT_PATH,
365             null);
366 
367     testFromStreamException(gdchServiceAccountStream, "token_uri");
368   }
369 
370   @Test
fromStream_gdchServiceAccountInvalidFormatVersion_throws()371   public void fromStream_gdchServiceAccountInvalidFormatVersion_throws() throws IOException {
372     InputStream gdchServiceAccountStream =
373         GdchCredentialsTest.writeGdchServiceAccountStream(
374             "100",
375             GDCH_SA_PROJECT_ID,
376             GDCH_SA_PRIVATE_KEY_ID,
377             GDCH_SA_PRIVATE_KEY_PKC8,
378             GDCH_SA_SERVICE_IDENTITY_NAME,
379             GDCH_SA_CA_CERT_PATH,
380             GDCH_SA_TOKEN_SERVER_URI);
381 
382     testFromStreamException(
383         gdchServiceAccountStream,
384         String.format("Only format version %s is supported", GDCH_SA_FORMAT_VERSION));
385   }
386 
387   @Test
fromStream_gdchServiceAccountInvalidCaCertPath_throws()388   public void fromStream_gdchServiceAccountInvalidCaCertPath_throws() throws IOException {
389     InputStream gdchServiceAccountStream =
390         GdchCredentialsTest.writeGdchServiceAccountStream(
391             GDCH_SA_FORMAT_VERSION,
392             GDCH_SA_PROJECT_ID,
393             GDCH_SA_PRIVATE_KEY_ID,
394             GDCH_SA_PRIVATE_KEY_PKC8,
395             GDCH_SA_SERVICE_IDENTITY_NAME,
396             "/path/to/missing/file",
397             GDCH_SA_TOKEN_SERVER_URI);
398 
399     testFromStreamException(
400         gdchServiceAccountStream,
401         String.format("Error reading certificate file from CA cert path"));
402   }
403 
404   @Test
fromStream_userCredentials_providesToken()405   public void fromStream_userCredentials_providesToken() throws IOException {
406     MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
407     transportFactory.transport.addClient(USER_CLIENT_ID, USER_CLIENT_SECRET);
408     transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN);
409     InputStream userStream =
410         UserCredentialsTest.writeUserStream(
411             USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, null);
412 
413     GoogleCredentials credentials = GoogleCredentials.fromStream(userStream, transportFactory);
414 
415     assertNotNull(credentials);
416     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
417     TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN);
418   }
419 
420   @Test
fromStream_userCredentials_defaultUniverse()421   public void fromStream_userCredentials_defaultUniverse() throws IOException {
422     MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
423     InputStream userStream =
424         UserCredentialsTest.writeUserStream(
425             USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, null);
426 
427     GoogleCredentials credentials = GoogleCredentials.fromStream(userStream, transportFactory);
428 
429     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
430   }
431 
432   @Test
fromStream_userCredentials_NoClientId_throws()433   public void fromStream_userCredentials_NoClientId_throws() throws IOException {
434     InputStream userStream =
435         UserCredentialsTest.writeUserStream(null, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT);
436 
437     testFromStreamException(userStream, "client_id");
438   }
439 
440   @Test
fromStream_userCredentials_NoClientSecret_throws()441   public void fromStream_userCredentials_NoClientSecret_throws() throws IOException {
442     InputStream userStream =
443         UserCredentialsTest.writeUserStream(USER_CLIENT_ID, null, REFRESH_TOKEN, QUOTA_PROJECT);
444 
445     testFromStreamException(userStream, "client_secret");
446   }
447 
448   @Test
fromStream_userCredentials_NoRefreshToken_throws()449   public void fromStream_userCredentials_NoRefreshToken_throws() throws IOException {
450     InputStream userStream =
451         UserCredentialsTest.writeUserStream(
452             USER_CLIENT_ID, USER_CLIENT_SECRET, null, QUOTA_PROJECT);
453 
454     testFromStreamException(userStream, "refresh_token");
455   }
456 
457   @Test
fromStream_identityPoolCredentials_providesToken()458   public void fromStream_identityPoolCredentials_providesToken() throws IOException {
459     MockExternalAccountCredentialsTransportFactory transportFactory =
460         new MockExternalAccountCredentialsTransportFactory();
461     InputStream identityPoolCredentialStream =
462         IdentityPoolCredentialsTest.writeIdentityPoolCredentialsStream(
463             transportFactory.transport.getStsUrl(),
464             transportFactory.transport.getMetadataUrl(),
465             /* serviceAccountImpersonationUrl= */ null,
466             /* serviceAccountImpersonationOptionsMap= */ null);
467 
468     GoogleCredentials credentials =
469         GoogleCredentials.fromStream(identityPoolCredentialStream, transportFactory);
470 
471     assertNotNull(credentials);
472     credentials = credentials.createScoped(SCOPES);
473     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
474     TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken());
475   }
476 
477   @Test
fromStream_identityPoolCredentials_defaultUniverse()478   public void fromStream_identityPoolCredentials_defaultUniverse() throws IOException {
479     MockExternalAccountCredentialsTransportFactory transportFactory =
480         new MockExternalAccountCredentialsTransportFactory();
481     InputStream identityPoolCredentialStream =
482         IdentityPoolCredentialsTest.writeIdentityPoolCredentialsStream(
483             transportFactory.transport.getStsUrl(),
484             transportFactory.transport.getMetadataUrl(),
485             /* serviceAccountImpersonationUrl= */ null,
486             /* serviceAccountImpersonationOptionsMap= */ null);
487 
488     GoogleCredentials credentials =
489         GoogleCredentials.fromStream(identityPoolCredentialStream, transportFactory);
490 
491     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
492   }
493 
494   @Test
fromStream_awsCredentials_providesToken()495   public void fromStream_awsCredentials_providesToken() throws IOException {
496     MockExternalAccountCredentialsTransportFactory transportFactory =
497         new MockExternalAccountCredentialsTransportFactory();
498 
499     InputStream awsCredentialStream =
500         AwsCredentialsTest.writeAwsCredentialsStream(
501             transportFactory.transport.getStsUrl(),
502             transportFactory.transport.getAwsRegionUrl(),
503             transportFactory.transport.getAwsCredentialsUrl());
504 
505     GoogleCredentials credentials =
506         GoogleCredentials.fromStream(awsCredentialStream, transportFactory);
507 
508     assertNotNull(credentials);
509     credentials = credentials.createScoped(SCOPES);
510     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
511     TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken());
512   }
513 
514   @Test
fromStream_awsCredentials_defaultUniverse()515   public void fromStream_awsCredentials_defaultUniverse() throws IOException {
516     MockExternalAccountCredentialsTransportFactory transportFactory =
517         new MockExternalAccountCredentialsTransportFactory();
518 
519     InputStream awsCredentialStream =
520         AwsCredentialsTest.writeAwsCredentialsStream(
521             transportFactory.transport.getStsUrl(),
522             transportFactory.transport.getAwsRegionUrl(),
523             transportFactory.transport.getAwsCredentialsUrl());
524 
525     GoogleCredentials credentials =
526         GoogleCredentials.fromStream(awsCredentialStream, transportFactory);
527 
528     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
529   }
530 
531   @Test
fromStream_pluggableAuthCredentials_providesToken()532   public void fromStream_pluggableAuthCredentials_providesToken() throws IOException {
533     MockExternalAccountCredentialsTransportFactory transportFactory =
534         new MockExternalAccountCredentialsTransportFactory();
535 
536     InputStream stream =
537         PluggableAuthCredentialsTest.writeCredentialsStream(transportFactory.transport.getStsUrl());
538 
539     GoogleCredentials credentials = GoogleCredentials.fromStream(stream, transportFactory);
540 
541     assertNotNull(credentials);
542 
543     // Create copy with mock executable handler.
544     PluggableAuthCredentials copy =
545         PluggableAuthCredentials.newBuilder((PluggableAuthCredentials) credentials)
546             .setExecutableHandler(options -> "pluggableAuthToken")
547             .build();
548 
549     copy = copy.createScoped(SCOPES);
550     Map<String, List<String>> metadata = copy.getRequestMetadata(CALL_URI);
551     TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken());
552   }
553 
554   @Test
fromStream_pluggableAuthCredentials_defaultUniverse()555   public void fromStream_pluggableAuthCredentials_defaultUniverse() throws IOException {
556     MockExternalAccountCredentialsTransportFactory transportFactory =
557         new MockExternalAccountCredentialsTransportFactory();
558 
559     InputStream stream =
560         PluggableAuthCredentialsTest.writeCredentialsStream(transportFactory.transport.getStsUrl());
561 
562     GoogleCredentials credentials = GoogleCredentials.fromStream(stream, transportFactory);
563 
564     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
565   }
566 
567   @Test
fromStream_externalAccountAuthorizedUserCredentials_providesToken()568   public void fromStream_externalAccountAuthorizedUserCredentials_providesToken()
569       throws IOException {
570     MockExternalAccountAuthorizedUserCredentialsTransportFactory transportFactory =
571         new MockExternalAccountAuthorizedUserCredentialsTransportFactory();
572     InputStream stream =
573         TestUtils.jsonToInputStream(
574             ExternalAccountAuthorizedUserCredentialsTest.buildJsonCredentials());
575 
576     GoogleCredentials credentials = GoogleCredentials.fromStream(stream, transportFactory);
577 
578     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
579     TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken());
580   }
581 
582   @Test
fromStream_externalAccountAuthorizedUserCredentials_defaultUniverse()583   public void fromStream_externalAccountAuthorizedUserCredentials_defaultUniverse()
584       throws IOException {
585     MockExternalAccountAuthorizedUserCredentialsTransportFactory transportFactory =
586         new MockExternalAccountAuthorizedUserCredentialsTransportFactory();
587 
588     GenericJson json = ExternalAccountAuthorizedUserCredentialsTest.buildJsonCredentials();
589     json.remove("universe_domain");
590     InputStream stream = TestUtils.jsonToInputStream(json);
591 
592     GoogleCredentials credentials = GoogleCredentials.fromStream(stream, transportFactory);
593 
594     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
595   }
596 
597   @Test
fromStream_Impersonation_providesToken_WithQuotaProject()598   public void fromStream_Impersonation_providesToken_WithQuotaProject() throws IOException {
599     MockTokenServerTransportFactory transportFactoryForSource =
600         new MockTokenServerTransportFactory();
601     transportFactoryForSource.transport.addServiceAccount(
602         ImpersonatedCredentialsTest.SA_CLIENT_EMAIL, ImpersonatedCredentialsTest.ACCESS_TOKEN);
603 
604     MockIAMCredentialsServiceTransportFactory transportFactory =
605         new MockIAMCredentialsServiceTransportFactory();
606     transportFactory.transport.setTargetPrincipal(
607         ImpersonatedCredentialsTest.IMPERSONATED_CLIENT_EMAIL);
608     transportFactory.transport.setAccessToken(ImpersonatedCredentialsTest.ACCESS_TOKEN);
609     transportFactory.transport.setExpireTime(ImpersonatedCredentialsTest.getDefaultExpireTime());
610     transportFactory.transport.setAccessTokenEndpoint(
611         ImpersonatedCredentialsTest.IMPERSONATION_URL);
612 
613     InputStream impersonationCredentialsStream =
614         ImpersonatedCredentialsTest.writeImpersonationCredentialsStream(
615             ImpersonatedCredentialsTest.IMPERSONATION_URL,
616             ImpersonatedCredentialsTest.DELEGATES,
617             ImpersonatedCredentialsTest.QUOTA_PROJECT_ID);
618 
619     ImpersonatedCredentials credentials =
620         (ImpersonatedCredentials)
621             GoogleCredentials.fromStream(impersonationCredentialsStream, transportFactoryForSource);
622     credentials.setTransportFactory(transportFactory);
623 
624     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
625     TestUtils.assertContainsBearerToken(metadata, ImpersonatedCredentialsTest.ACCESS_TOKEN);
626 
627     assertTrue(metadata.containsKey("x-goog-user-project"));
628     List<String> headerValues = metadata.get("x-goog-user-project");
629     assertEquals(1, headerValues.size());
630     assertEquals(ImpersonatedCredentialsTest.QUOTA_PROJECT_ID, headerValues.get(0));
631   }
632 
633   @Test
fromStream_Impersonation_defaultUniverse()634   public void fromStream_Impersonation_defaultUniverse() throws IOException {
635     MockTokenServerTransportFactory transportFactoryForSource =
636         new MockTokenServerTransportFactory();
637     transportFactoryForSource.transport.addServiceAccount(
638         ImpersonatedCredentialsTest.SA_CLIENT_EMAIL, ImpersonatedCredentialsTest.ACCESS_TOKEN);
639 
640     MockIAMCredentialsServiceTransportFactory transportFactory =
641         new MockIAMCredentialsServiceTransportFactory();
642 
643     InputStream impersonationCredentialsStream =
644         ImpersonatedCredentialsTest.writeImpersonationCredentialsStream(
645             ImpersonatedCredentialsTest.IMPERSONATION_URL,
646             ImpersonatedCredentialsTest.DELEGATES,
647             ImpersonatedCredentialsTest.QUOTA_PROJECT_ID);
648 
649     ImpersonatedCredentials credentials =
650         (ImpersonatedCredentials)
651             GoogleCredentials.fromStream(impersonationCredentialsStream, transportFactoryForSource);
652     credentials.setTransportFactory(transportFactory);
653 
654     assertEquals(Credentials.GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
655   }
656 
657   @Test
fromStream_Impersonation_providesToken_WithoutQuotaProject()658   public void fromStream_Impersonation_providesToken_WithoutQuotaProject() throws IOException {
659     MockTokenServerTransportFactory transportFactoryForSource =
660         new MockTokenServerTransportFactory();
661     transportFactoryForSource.transport.addServiceAccount(
662         ImpersonatedCredentialsTest.SA_CLIENT_EMAIL, ImpersonatedCredentialsTest.ACCESS_TOKEN);
663 
664     MockIAMCredentialsServiceTransportFactory transportFactory =
665         new MockIAMCredentialsServiceTransportFactory();
666     transportFactory.transport.setTargetPrincipal(
667         ImpersonatedCredentialsTest.IMPERSONATED_CLIENT_EMAIL);
668     transportFactory.transport.setAccessToken(ImpersonatedCredentialsTest.ACCESS_TOKEN);
669     transportFactory.transport.setExpireTime(ImpersonatedCredentialsTest.getDefaultExpireTime());
670     transportFactory.transport.setAccessTokenEndpoint(
671         ImpersonatedCredentialsTest.IMPERSONATION_URL);
672 
673     InputStream impersonationCredentialsStream =
674         ImpersonatedCredentialsTest.writeImpersonationCredentialsStream(
675             ImpersonatedCredentialsTest.IMPERSONATION_URL,
676             ImpersonatedCredentialsTest.DELEGATES,
677             null);
678 
679     ImpersonatedCredentials credentials =
680         (ImpersonatedCredentials)
681             GoogleCredentials.fromStream(impersonationCredentialsStream, transportFactoryForSource);
682     credentials.setTransportFactory(transportFactory);
683 
684     Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI);
685     TestUtils.assertContainsBearerToken(metadata, ImpersonatedCredentialsTest.ACCESS_TOKEN);
686 
687     assertFalse(metadata.containsKey("x-goog-user-project"));
688   }
689 
690   @Test
createScoped_overloadCallsImplementation()691   public void createScoped_overloadCallsImplementation() {
692     final AtomicReference<Collection<String>> called = new AtomicReference<>();
693     final GoogleCredentials expectedScopedCredentials = new GoogleCredentials();
694 
695     GoogleCredentials credentials =
696         new GoogleCredentials() {
697           @Override
698           public GoogleCredentials createScoped(Collection<String> scopes) {
699             called.set(scopes);
700             return expectedScopedCredentials;
701           }
702         };
703 
704     GoogleCredentials scopedCredentials = credentials.createScoped("foo", "bar");
705 
706     assertEquals(expectedScopedCredentials, scopedCredentials);
707     assertEquals(ImmutableList.of("foo", "bar"), called.get());
708   }
709 
710   @Test
create_withoutUniverse()711   public void create_withoutUniverse() throws IOException {
712     AccessToken token = AccessToken.newBuilder().setTokenValue(ACCESS_TOKEN).build();
713     GoogleCredentials credentials = GoogleCredentials.create(token);
714 
715     assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain());
716     assertEquals(false, credentials.isExplicitUniverseDomain());
717   }
718 
719   @Test
create_withUniverse()720   public void create_withUniverse() throws IOException {
721     AccessToken token = AccessToken.newBuilder().setTokenValue(ACCESS_TOKEN).build();
722     GoogleCredentials credentials = GoogleCredentials.create("some-universe", token);
723 
724     assertEquals("some-universe", credentials.getUniverseDomain());
725     assertEquals(true, credentials.isExplicitUniverseDomain());
726   }
727 
728   @Test
buildWithQuotaProject()729   public void buildWithQuotaProject() {
730     final GoogleCredentials googleCredentials =
731         new GoogleCredentials.Builder().setQuotaProjectId("old_quota").build();
732     GoogleCredentials withUpdatedQuota = googleCredentials.createWithQuotaProject("new_quota");
733 
734     assertEquals("old_quota", googleCredentials.getQuotaProjectId());
735     assertEquals("new_quota", withUpdatedQuota.getQuotaProjectId());
736 
737     GoogleCredentials withEmptyQuota = googleCredentials.createWithQuotaProject("");
738     assertEquals("", withEmptyQuota.getQuotaProjectId());
739 
740     GoogleCredentials sameCredentials = googleCredentials.createWithQuotaProject(null);
741     assertEquals(null, sameCredentials.getQuotaProjectId());
742   }
743 
744   @Test
buildWithUniverseDomain()745   public void buildWithUniverseDomain() throws IOException {
746     final GoogleCredentials original =
747         new GoogleCredentials.Builder().setUniverseDomain("universe1").build();
748     GoogleCredentials updated = original.toBuilder().setUniverseDomain("universe2").build();
749 
750     assertEquals("universe1", original.getUniverseDomain());
751     assertEquals(true, original.isExplicitUniverseDomain());
752     assertEquals("universe2", updated.getUniverseDomain());
753     assertEquals(true, updated.isExplicitUniverseDomain());
754 
755     GoogleCredentials withEmpty = original.toBuilder().setUniverseDomain("").build();
756     assertEquals(GOOGLE_DEFAULT_UNIVERSE, withEmpty.getUniverseDomain());
757     assertEquals(false, withEmpty.isExplicitUniverseDomain());
758 
759     GoogleCredentials withNull = original.toBuilder().setUniverseDomain(null).build();
760     assertEquals(GOOGLE_DEFAULT_UNIVERSE, withNull.getUniverseDomain());
761     assertEquals(false, withNull.isExplicitUniverseDomain());
762   }
763 
764   @Test
serialize()765   public void serialize() throws IOException, ClassNotFoundException {
766     final GoogleCredentials testCredentials = new GoogleCredentials.Builder().build();
767     GoogleCredentials deserializedCredentials = serializeAndDeserialize(testCredentials);
768     assertEquals(testCredentials, deserializedCredentials);
769     assertEquals(testCredentials.hashCode(), deserializedCredentials.hashCode());
770     assertEquals(testCredentials.toString(), deserializedCredentials.toString());
771     assertSame(deserializedCredentials.clock, Clock.SYSTEM);
772   }
773 
774   @Test
toString_containsFields()775   public void toString_containsFields() throws IOException {
776     String expectedToString =
777         String.format(
778             "GoogleCredentials{quotaProjectId=%s, universeDomain=%s, isExplicitUniverseDomain=%s}",
779             "some-project", "googleapis.com", false, "[some scope]");
780     GoogleCredentials credentials =
781         GoogleCredentials.newBuilder().setQuotaProjectId("some-project").build();
782     assertEquals(expectedToString, credentials.toString());
783   }
784 
785   @Test
hashCode_equals()786   public void hashCode_equals() throws IOException {
787     GoogleCredentials credentials =
788         GoogleCredentials.newBuilder().setUniverseDomain("some-domain").build();
789     GoogleCredentials otherCredentials =
790         GoogleCredentials.newBuilder().setUniverseDomain("some-domain").build();
791     assertEquals(credentials.hashCode(), otherCredentials.hashCode());
792   }
793 
794   @Test
equals_true()795   public void equals_true() throws IOException {
796     GoogleCredentials credentials =
797         GoogleCredentials.newBuilder().setUniverseDomain("some-domain").build();
798     GoogleCredentials otherCredentials =
799         GoogleCredentials.newBuilder().setUniverseDomain("some-domain").build();
800     assertTrue(credentials.equals(otherCredentials));
801     assertTrue(otherCredentials.equals(credentials));
802   }
803 
testFromStreamException(InputStream stream, String expectedMessageContent)804   private static void testFromStreamException(InputStream stream, String expectedMessageContent) {
805     try {
806       GoogleCredentials.fromStream(stream, DUMMY_TRANSPORT_FACTORY);
807       fail(
808           String.format(
809               "Should throw exception with message containing '%s'", expectedMessageContent));
810     } catch (IOException expected) {
811       assertTrue(expected.getMessage().contains(expectedMessageContent));
812     }
813   }
814 }
815