diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java
index 5ded1a140..191f584de 100644
--- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java
+++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java
@@ -200,7 +200,8 @@ private ImpersonatedCredentials initializeImpersonatedCredentials() {
.build();
}
- String targetPrincipal = extractTargetPrincipal(serviceAccountImpersonationUrl);
+ String targetPrincipal =
+ ImpersonatedCredentials.extractTargetPrincipal(serviceAccountImpersonationUrl);
return ImpersonatedCredentials.newBuilder()
.setSourceCredentials(sourceCredentials)
.setHttpTransportFactory(transportFactory)
@@ -359,19 +360,6 @@ protected AccessToken exchangeExternalCredentialForAccessToken(
return response.getAccessToken();
}
- private static String extractTargetPrincipal(String serviceAccountImpersonationUrl) {
- // Extract the target principal.
- int startIndex = serviceAccountImpersonationUrl.lastIndexOf('/');
- int endIndex = serviceAccountImpersonationUrl.indexOf(":generateAccessToken");
-
- if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) {
- return serviceAccountImpersonationUrl.substring(startIndex + 1, endIndex);
- } else {
- throw new IllegalArgumentException(
- "Unable to determine target principal from service account impersonation URL.");
- }
- }
-
/**
* Retrieves the external subject token to be exchanged for a GCP access token.
*
diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
index 5a215322f..af7cc8ecd 100644
--- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
+++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
@@ -78,8 +78,12 @@ public static GoogleCredentials create(AccessToken accessToken) {
*
* - Credentials file pointed to by the {@code GOOGLE_APPLICATION_CREDENTIALS} environment
* variable
- *
- Credentials provided by the Google Cloud SDK {@code gcloud auth application-default
- * login} command
+ *
- Credentials provided by the Google Cloud SDK.
+ *
+ * - {@code gcloud auth application-default login} for user account credentials.
+ *
- {@code gcloud auth application-default login --impersonate-service-account} for
+ * impersonated service account credentials.
+ *
* - Google App Engine built-in credentials
*
- Google Cloud Shell built-in credentials
*
- Google Compute Engine built-in credentials
@@ -169,6 +173,9 @@ public static GoogleCredentials fromStream(
if (ExternalAccountCredentials.EXTERNAL_ACCOUNT_FILE_TYPE.equals(fileType)) {
return ExternalAccountCredentials.fromJson(fileContents, transportFactory);
}
+ if ("impersonated_service_account".equals(fileType)) {
+ return ImpersonatedCredentials.fromJson(fileContents, transportFactory);
+ }
throw new IOException(
String.format(
"Error reading credentials from stream, 'type' value '%s' not recognized."
diff --git a/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java
index 6ddb116cc..700ad2117 100644
--- a/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java
+++ b/oauth2_http/java/com/google/auth/oauth2/ImpersonatedCredentials.java
@@ -32,6 +32,7 @@
package com.google.auth.oauth2;
import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkNotNull;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
@@ -45,6 +46,7 @@
import com.google.auth.ServiceAccountSigner;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.http.HttpTransportFactory;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
@@ -53,6 +55,7 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -85,7 +88,7 @@
*
*/
public class ImpersonatedCredentials extends GoogleCredentials
- implements ServiceAccountSigner, IdTokenProvider {
+ implements ServiceAccountSigner, IdTokenProvider, QuotaProjectIdProvider {
private static final long serialVersionUID = -2133257318957488431L;
private static final String RFC3339 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
@@ -101,12 +104,14 @@ public class ImpersonatedCredentials extends GoogleCredentials
private List delegates;
private List scopes;
private int lifetime;
+ private String quotaProjectId;
private final String transportFactoryClassName;
private transient HttpTransportFactory transportFactory;
/**
- * @param sourceCredentials the source credential used as to acquire the impersonated credentials
+ * @param sourceCredentials the source credential used to acquire the impersonated credentials. It
+ * should be either a user account credential or a service account credential.
* @param targetPrincipal the service account to impersonate
* @param delegates the chained list of delegates required to grant the final access_token. If
* set, the sequence of identities must have "Service Account Token Creator" capability
@@ -144,7 +149,52 @@ public static ImpersonatedCredentials create(
}
/**
- * @param sourceCredentials the source credential used as to acquire the impersonated credentials
+ * @param sourceCredentials the source credential used to acquire the impersonated credentials. It
+ * should be either a user account credential or a service account credential.
+ * @param targetPrincipal the service account to impersonate
+ * @param delegates the chained list of delegates required to grant the final access_token. If
+ * set, the sequence of identities must have "Service Account Token Creator" capability
+ * granted to the preceding identity. For example, if set to [serviceAccountB,
+ * serviceAccountC], the sourceCredential must have the Token Creator role on serviceAccountB.
+ * serviceAccountB must have the Token Creator on serviceAccountC. Finally, C must have Token
+ * Creator on target_principal. If unset, sourceCredential must have that role on
+ * targetPrincipal.
+ * @param scopes scopes to request during the authorization grant
+ * @param lifetime number of seconds the delegated credential should be valid. By default this
+ * value should be at most 3600. However, you can follow these
+ * instructions to set up the service account and extend the maximum lifetime to 43200 (12
+ * hours). If the given lifetime is 0, default value 3600 will be used instead when creating
+ * the credentials.
+ * @param transportFactory HTTP transport factory that creates the transport used to get access
+ * tokens.
+ * @param quotaProjectId the project used for quota and billing purposes. Should be null unless
+ * the caller wants to use a project different from the one that owns the impersonated
+ * credential for billing/quota purposes.
+ * @return new credentials
+ */
+ public static ImpersonatedCredentials create(
+ GoogleCredentials sourceCredentials,
+ String targetPrincipal,
+ List delegates,
+ List scopes,
+ int lifetime,
+ HttpTransportFactory transportFactory,
+ String quotaProjectId) {
+ return ImpersonatedCredentials.newBuilder()
+ .setSourceCredentials(sourceCredentials)
+ .setTargetPrincipal(targetPrincipal)
+ .setDelegates(delegates)
+ .setScopes(scopes)
+ .setLifetime(lifetime)
+ .setHttpTransportFactory(transportFactory)
+ .setQuotaProjectId(quotaProjectId)
+ .build();
+ }
+
+ /**
+ * @param sourceCredentials the source credential used to acquire the impersonated credentials. It
+ * should be either a user account credential or a service account credential.
* @param targetPrincipal the service account to impersonate
* @param delegates the chained list of delegates required to grant the final access_token. If
* set, the sequence of identities must have "Service Account Token Creator" capability
@@ -179,6 +229,19 @@ public static ImpersonatedCredentials create(
.build();
}
+ static String extractTargetPrincipal(String serviceAccountImpersonationUrl) {
+ // Extract the target principal.
+ int startIndex = serviceAccountImpersonationUrl.lastIndexOf('/');
+ int endIndex = serviceAccountImpersonationUrl.indexOf(":generateAccessToken");
+
+ if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) {
+ return serviceAccountImpersonationUrl.substring(startIndex + 1, endIndex);
+ } else {
+ throw new IllegalArgumentException(
+ "Unable to determine target principal from service account impersonation URL.");
+ }
+ }
+
/**
* Returns the email field of the serviceAccount that is being impersonated.
*
@@ -189,10 +252,33 @@ public String getAccount() {
return this.targetPrincipal;
}
+ @Override
+ public String getQuotaProjectId() {
+ return this.quotaProjectId;
+ }
+
+ @VisibleForTesting
+ List getDelegates() {
+ return delegates;
+ }
+
+ @VisibleForTesting
+ List getScopes() {
+ return scopes;
+ }
+
+ public GoogleCredentials getSourceCredentials() {
+ return sourceCredentials;
+ }
+
int getLifetime() {
return this.lifetime;
}
+ public void setTransportFactory(HttpTransportFactory httpTransportFactory) {
+ this.transportFactory = httpTransportFactory;
+ }
+
/**
* Signs the provided bytes using the private key associated with the impersonated service account
*
@@ -213,6 +299,89 @@ public byte[] sign(byte[] toSign) {
ImmutableMap.of("delegates", this.delegates));
}
+ /**
+ * Returns impersonation account credentials defined by JSON using the format generated by gCloud.
+ * The source credentials in the JSON should be either user account credentials or service account
+ * credentials.
+ *
+ * @param json a map from the JSON representing the credentials
+ * @param transportFactory HTTP transport factory, creates the transport used to get access tokens
+ * @return the credentials defined by the JSON
+ * @throws IOException if the credential cannot be created from the JSON.
+ */
+ static ImpersonatedCredentials fromJson(
+ Map json, HttpTransportFactory transportFactory) throws IOException {
+
+ checkNotNull(json);
+ checkNotNull(transportFactory);
+
+ List delegates = null;
+ Map sourceCredentialsJson;
+ String sourceCredentialsType;
+ String quotaProjectId;
+ String targetPrincipal;
+ try {
+ String serviceAccountImpersonationUrl =
+ (String) json.get("service_account_impersonation_url");
+ if (json.containsKey("delegates")) {
+ delegates = (List) json.get("delegates");
+ }
+ sourceCredentialsJson = (Map) json.get("source_credentials");
+ sourceCredentialsType = (String) sourceCredentialsJson.get("type");
+ quotaProjectId = (String) json.get("quota_project_id");
+ targetPrincipal = extractTargetPrincipal(serviceAccountImpersonationUrl);
+ } catch (ClassCastException | NullPointerException | IllegalArgumentException e) {
+ throw new CredentialFormatException("An invalid input stream was provided.", e);
+ }
+
+ GoogleCredentials sourceCredentials;
+ if (GoogleCredentials.USER_FILE_TYPE.equals(sourceCredentialsType)) {
+ sourceCredentials = UserCredentials.fromJson(sourceCredentialsJson, transportFactory);
+ } else if (GoogleCredentials.SERVICE_ACCOUNT_FILE_TYPE.equals(sourceCredentialsType)) {
+ sourceCredentials =
+ ServiceAccountCredentials.fromJson(sourceCredentialsJson, transportFactory);
+ } else {
+ throw new IOException(
+ String.format(
+ "A credential of type %s is not supported as source credential for impersonation.",
+ sourceCredentialsType));
+ }
+ return ImpersonatedCredentials.newBuilder()
+ .setSourceCredentials(sourceCredentials)
+ .setTargetPrincipal(targetPrincipal)
+ .setDelegates(delegates)
+ .setScopes(new ArrayList())
+ .setLifetime(DEFAULT_LIFETIME_IN_SECONDS)
+ .setHttpTransportFactory(transportFactory)
+ .setQuotaProjectId(quotaProjectId)
+ .build();
+ }
+
+ @Override
+ public boolean createScopedRequired() {
+ return this.scopes == null || this.scopes.isEmpty();
+ }
+
+ @Override
+ public GoogleCredentials createScoped(Collection scopes) {
+ return toBuilder()
+ .setScopes((List) scopes)
+ .setLifetime(this.lifetime)
+ .setDelegates(this.delegates)
+ .setHttpTransportFactory(this.transportFactory)
+ .setQuotaProjectId(this.quotaProjectId)
+ .build();
+ }
+
+ @Override
+ protected Map> getAdditionalHeaders() {
+ Map> headers = super.getAdditionalHeaders();
+ if (quotaProjectId != null) {
+ return addQuotaProjectIdToRequestMetadata(quotaProjectId, headers);
+ }
+ return headers;
+ }
+
private ImpersonatedCredentials(Builder builder) {
this.sourceCredentials = builder.getSourceCredentials();
this.targetPrincipal = builder.getTargetPrincipal();
@@ -223,6 +392,7 @@ private ImpersonatedCredentials(Builder builder) {
firstNonNull(
builder.getHttpTransportFactory(),
getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY));
+ this.quotaProjectId = builder.quotaProjectId;
this.transportFactoryClassName = this.transportFactory.getClass().getName();
if (this.delegates == null) {
this.delegates = new ArrayList();
@@ -318,7 +488,8 @@ public IdToken idTokenWithAudience(String targetAudience, List scopes;
private int lifetime = DEFAULT_LIFETIME_IN_SECONDS;
private HttpTransportFactory transportFactory;
+ private String quotaProjectId;
protected Builder() {}
@@ -425,6 +599,11 @@ public HttpTransportFactory getHttpTransportFactory() {
return transportFactory;
}
+ public Builder setQuotaProjectId(String quotaProjectId) {
+ this.quotaProjectId = quotaProjectId;
+ return this;
+ }
+
public ImpersonatedCredentials build() {
return new ImpersonatedCredentials(this);
}
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java
index a87dc84fe..36774de58 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java
@@ -32,6 +32,7 @@
package com.google.auth.oauth2;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -41,6 +42,7 @@
import com.google.auth.TestUtils;
import com.google.auth.http.HttpTransportFactory;
import com.google.auth.oauth2.IdentityPoolCredentialsTest.MockExternalAccountCredentialsTransportFactory;
+import com.google.auth.oauth2.ImpersonatedCredentialsTest.MockIAMCredentialsServiceTransportFactory;
import com.google.common.collect.ImmutableList;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -270,6 +272,71 @@ public void fromStream_awsCredentials_providesToken() throws IOException {
TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken());
}
+ @Test
+ public void fromStream_Impersonation_providesToken_WithQuotaProject() throws IOException {
+ MockTokenServerTransportFactory transportFactoryForSource =
+ new MockTokenServerTransportFactory();
+ transportFactoryForSource.transport.addServiceAccount(
+ ImpersonatedCredentialsTest.SA_CLIENT_EMAIL, ImpersonatedCredentialsTest.ACCESS_TOKEN);
+
+ MockIAMCredentialsServiceTransportFactory transportFactory =
+ new MockIAMCredentialsServiceTransportFactory();
+ transportFactory.transport.setTargetPrincipal(
+ ImpersonatedCredentialsTest.IMPERSONATED_CLIENT_EMAIL);
+ transportFactory.transport.setAccessToken(ImpersonatedCredentialsTest.ACCESS_TOKEN);
+ transportFactory.transport.setExpireTime(ImpersonatedCredentialsTest.getDefaultExpireTime());
+
+ InputStream impersonationCredentialsStream =
+ ImpersonatedCredentialsTest.writeImpersonationCredentialsStream(
+ ImpersonatedCredentialsTest.IMPERSONATION_URL,
+ ImpersonatedCredentialsTest.DELEGATES,
+ ImpersonatedCredentialsTest.QUOTA_PROJECT_ID);
+
+ ImpersonatedCredentials credentials =
+ (ImpersonatedCredentials)
+ GoogleCredentials.fromStream(impersonationCredentialsStream, transportFactoryForSource);
+ credentials.setTransportFactory(transportFactory);
+
+ Map> metadata = credentials.getRequestMetadata(CALL_URI);
+ TestUtils.assertContainsBearerToken(metadata, ImpersonatedCredentialsTest.ACCESS_TOKEN);
+
+ assertTrue(metadata.containsKey("x-goog-user-project"));
+ List headerValues = metadata.get("x-goog-user-project");
+ assertEquals(1, headerValues.size());
+ assertEquals(ImpersonatedCredentialsTest.QUOTA_PROJECT_ID, headerValues.get(0));
+ }
+
+ @Test
+ public void fromStream_Impersonation_providesToken_WithoutQuotaProject() throws IOException {
+ MockTokenServerTransportFactory transportFactoryForSource =
+ new MockTokenServerTransportFactory();
+ transportFactoryForSource.transport.addServiceAccount(
+ ImpersonatedCredentialsTest.SA_CLIENT_EMAIL, ImpersonatedCredentialsTest.ACCESS_TOKEN);
+
+ MockIAMCredentialsServiceTransportFactory transportFactory =
+ new MockIAMCredentialsServiceTransportFactory();
+ transportFactory.transport.setTargetPrincipal(
+ ImpersonatedCredentialsTest.IMPERSONATED_CLIENT_EMAIL);
+ transportFactory.transport.setAccessToken(ImpersonatedCredentialsTest.ACCESS_TOKEN);
+ transportFactory.transport.setExpireTime(ImpersonatedCredentialsTest.getDefaultExpireTime());
+
+ InputStream impersonationCredentialsStream =
+ ImpersonatedCredentialsTest.writeImpersonationCredentialsStream(
+ ImpersonatedCredentialsTest.IMPERSONATION_URL,
+ ImpersonatedCredentialsTest.DELEGATES,
+ null);
+
+ ImpersonatedCredentials credentials =
+ (ImpersonatedCredentials)
+ GoogleCredentials.fromStream(impersonationCredentialsStream, transportFactoryForSource);
+ credentials.setTransportFactory(transportFactory);
+
+ Map> metadata = credentials.getRequestMetadata(CALL_URI);
+ TestUtils.assertContainsBearerToken(metadata, ImpersonatedCredentialsTest.ACCESS_TOKEN);
+
+ assertFalse(metadata.containsKey("x-goog-user-project"));
+ }
+
@Test
public void createScoped_overloadCallsImplementation() {
final AtomicReference> called = new AtomicReference<>();
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java
index b7c3bd29e..8d834abde 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java
@@ -33,7 +33,9 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -48,11 +50,13 @@
import com.google.api.client.testing.http.MockLowLevelHttpRequest;
import com.google.api.client.util.Clock;
import com.google.auth.ServiceAccountSigner.SigningException;
+import com.google.auth.TestUtils;
import com.google.auth.http.HttpTransportFactory;
import com.google.auth.oauth2.GoogleCredentialsTest.MockTokenServerTransportFactory;
import com.google.common.collect.ImmutableList;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.PrivateKey;
import java.text.SimpleDateFormat;
@@ -61,6 +65,8 @@
import java.util.Calendar;
import java.util.Date;
import java.util.List;
+import java.util.Map;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -69,7 +75,7 @@
@RunWith(JUnit4.class)
public class ImpersonatedCredentialsTest extends BaseSerializationTest {
- private static final String SA_CLIENT_EMAIL =
+ public static final String SA_CLIENT_EMAIL =
"36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr@developer.gserviceaccount.com";
private static final String SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d";
static final String SA_PRIVATE_KEY_PKCS8 =
@@ -102,18 +108,29 @@ public class ImpersonatedCredentialsTest extends BaseSerializationTest {
+ "lZC1yYXktMTA0MTE3LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV4cC"
+ "I6MTU2NDUzMzA0MiwiaWF0IjoxNTY0NTI5NDQyLCJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iL"
+ "CJzdWIiOiIxMDIxMDE1NTA4MzQyMDA3MDg1NjgifQ.redacted";
+ public static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2";
private static final String PROJECT_ID = "project-id";
- private static final String IMPERSONATED_CLIENT_EMAIL =
+ public static final String IMPERSONATED_CLIENT_EMAIL =
"impersonated-account@iam.gserviceaccount.com";
private static final List SCOPES =
Arrays.asList("https://www.googleapis.com/auth/devstorage.read_only");
- private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2";
private static final int VALID_LIFETIME = 300;
private static final int INVALID_LIFETIME = 43210;
private static JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
private static final String RFC3339 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+ public static final String IMPERSONATION_URL =
+ "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/"
+ + IMPERSONATED_CLIENT_EMAIL
+ + ":generateAccessToken";
+ private static final String USER_ACCOUNT_CLIENT_ID =
+ "76408650-6qr441hur.apps.googleusercontent.com";
+ private static final String USER_ACCOUNT_CLIENT_SECRET = "d-F499q74hFpdHD0T5";
+ public static final String QUOTA_PROJECT_ID = "quota-project-id";
+ private static final String REFRESH_TOKEN = "dasdfasdffa4ffdfadgyjirasdfadsft";
+ public static final List DELEGATES =
+ Arrays.asList("sa1@developer.gserviceaccount.com", "sa2@developer.gserviceaccount.com");
static class MockIAMCredentialsServiceTransportFactory implements HttpTransportFactory {
@@ -125,6 +142,15 @@ public HttpTransport create() {
}
}
+ private GoogleCredentials sourceCredentials;
+ private MockIAMCredentialsServiceTransportFactory mockTransportFactory;
+
+ @Before
+ public void setup() throws IOException {
+ sourceCredentials = getSourceCredentials();
+ mockTransportFactory = new MockIAMCredentialsServiceTransportFactory();
+ }
+
private GoogleCredentials getSourceCredentials() throws IOException {
MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory();
PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8);
@@ -142,16 +168,153 @@ private GoogleCredentials getSourceCredentials() throws IOException {
return sourceCredentials;
}
+ @Test()
+ public void fromJson_userAsSource_WithQuotaProjectId() throws IOException {
+ GenericJson json =
+ buildImpersonationCredentialsJson(
+ IMPERSONATION_URL,
+ DELEGATES,
+ QUOTA_PROJECT_ID,
+ USER_ACCOUNT_CLIENT_ID,
+ USER_ACCOUNT_CLIENT_SECRET,
+ REFRESH_TOKEN);
+ ImpersonatedCredentials credentials =
+ ImpersonatedCredentials.fromJson(json, mockTransportFactory);
+ assertEquals(IMPERSONATED_CLIENT_EMAIL, credentials.getAccount());
+ assertEquals(QUOTA_PROJECT_ID, credentials.getQuotaProjectId());
+ assertEquals(DELEGATES, credentials.getDelegates());
+ assertEquals(new ArrayList(), credentials.getScopes());
+ assertEquals(3600, credentials.getLifetime());
+ GoogleCredentials sourceCredentials = credentials.getSourceCredentials();
+ assertTrue(sourceCredentials instanceof UserCredentials);
+ }
+
+ @Test()
+ public void fromJson_userAsSource_WithoutQuotaProjectId() throws IOException {
+ GenericJson json =
+ buildImpersonationCredentialsJson(
+ IMPERSONATION_URL,
+ DELEGATES,
+ null,
+ USER_ACCOUNT_CLIENT_ID,
+ USER_ACCOUNT_CLIENT_SECRET,
+ REFRESH_TOKEN);
+ ImpersonatedCredentials credentials =
+ ImpersonatedCredentials.fromJson(json, mockTransportFactory);
+ assertEquals(IMPERSONATED_CLIENT_EMAIL, credentials.getAccount());
+ assertNull(credentials.getQuotaProjectId());
+ assertEquals(DELEGATES, credentials.getDelegates());
+ assertEquals(new ArrayList(), credentials.getScopes());
+ assertEquals(3600, credentials.getLifetime());
+ GoogleCredentials sourceCredentials = credentials.getSourceCredentials();
+ assertTrue(sourceCredentials instanceof UserCredentials);
+ }
+
+ @Test()
+ public void fromJson_userAsSource_MissingDelegatesField() throws IOException {
+ GenericJson json =
+ buildImpersonationCredentialsJson(
+ IMPERSONATION_URL,
+ DELEGATES,
+ null,
+ USER_ACCOUNT_CLIENT_ID,
+ USER_ACCOUNT_CLIENT_SECRET,
+ REFRESH_TOKEN);
+ json.remove("delegates");
+ ImpersonatedCredentials credentials =
+ ImpersonatedCredentials.fromJson(json, mockTransportFactory);
+ assertEquals(IMPERSONATED_CLIENT_EMAIL, credentials.getAccount());
+ assertNull(credentials.getQuotaProjectId());
+ assertEquals(new ArrayList(), credentials.getDelegates());
+ assertEquals(new ArrayList(), credentials.getScopes());
+ assertEquals(3600, credentials.getLifetime());
+ GoogleCredentials sourceCredentials = credentials.getSourceCredentials();
+ assertTrue(sourceCredentials instanceof UserCredentials);
+ }
+
+ @Test()
+ public void fromJson_ServiceAccountAsSource() throws IOException {
+ GenericJson json =
+ buildImpersonationCredentialsJson(IMPERSONATION_URL, DELEGATES, QUOTA_PROJECT_ID);
+ ImpersonatedCredentials credentials =
+ ImpersonatedCredentials.fromJson(json, mockTransportFactory);
+ assertEquals(IMPERSONATED_CLIENT_EMAIL, credentials.getAccount());
+ assertEquals(QUOTA_PROJECT_ID, credentials.getQuotaProjectId());
+ assertEquals(DELEGATES, credentials.getDelegates());
+ assertEquals(new ArrayList(), credentials.getScopes());
+ assertEquals(3600, credentials.getLifetime());
+ GoogleCredentials sourceCredentials = credentials.getSourceCredentials();
+ assertTrue(sourceCredentials instanceof ServiceAccountCredentials);
+ }
+
+ @Test()
+ public void fromJson_InvalidFormat() throws IOException {
+ GenericJson json = buildInvalidCredentialsJson();
+ try {
+ ImpersonatedCredentials.fromJson(json, mockTransportFactory);
+ fail("An exception should be thrown.");
+ } catch (CredentialFormatException e) {
+ assertEquals("An invalid input stream was provided.", e.getMessage());
+ }
+ }
+
+ @Test()
+ public void createScopedRequired_True() {
+ ImpersonatedCredentials targetCredentials =
+ ImpersonatedCredentials.create(
+ sourceCredentials,
+ IMPERSONATED_CLIENT_EMAIL,
+ null,
+ new ArrayList(),
+ VALID_LIFETIME,
+ mockTransportFactory);
+ assertTrue(targetCredentials.createScopedRequired());
+ }
+
+ @Test()
+ public void createScopedRequired_False() {
+ ImpersonatedCredentials targetCredentials =
+ ImpersonatedCredentials.create(
+ sourceCredentials,
+ IMPERSONATED_CLIENT_EMAIL,
+ null,
+ SCOPES,
+ VALID_LIFETIME,
+ mockTransportFactory);
+ assertFalse(targetCredentials.createScopedRequired());
+ }
+
+ @Test()
+ public void createScoped() {
+ ImpersonatedCredentials targetCredentials =
+ ImpersonatedCredentials.create(
+ sourceCredentials,
+ IMPERSONATED_CLIENT_EMAIL,
+ DELEGATES,
+ SCOPES,
+ VALID_LIFETIME,
+ mockTransportFactory,
+ QUOTA_PROJECT_ID);
+
+ ImpersonatedCredentials scoped_credentials =
+ (ImpersonatedCredentials) targetCredentials.createScoped(Arrays.asList("scope1", "scope2"));
+ assertEquals(targetCredentials.getAccount(), scoped_credentials.getAccount());
+ assertEquals(targetCredentials.getDelegates(), scoped_credentials.getDelegates());
+ assertEquals(targetCredentials.getLifetime(), scoped_credentials.getLifetime());
+ assertEquals(
+ targetCredentials.getSourceCredentials(), scoped_credentials.getSourceCredentials());
+ assertEquals(targetCredentials.getQuotaProjectId(), scoped_credentials.getQuotaProjectId());
+ assertEquals(Arrays.asList("scope1", "scope2"), scoped_credentials.getScopes());
+ }
+
@Test()
public void refreshAccessToken_unauthorized() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
String expectedMessage = "The caller does not have permission";
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setTokenResponseErrorCode(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
- mtransportFactory.transport.setTokenResponseErrorContent(
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setTokenResponseErrorCode(
+ HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
+ mockTransportFactory.transport.setTokenResponseErrorContent(
generateErrorJson(
HttpStatusCodes.STATUS_CODE_UNAUTHORIZED, expectedMessage, "global", "forbidden"));
ImpersonatedCredentials targetCredentials =
@@ -161,7 +324,7 @@ public void refreshAccessToken_unauthorized() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
try {
targetCredentials.refreshAccessToken().getTokenValue();
@@ -175,19 +338,22 @@ public void refreshAccessToken_unauthorized() throws IOException {
@Test()
public void refreshAccessToken_malformedTarget() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
String invalidTargetEmail = "foo";
String expectedMessage = "Request contains an invalid argument";
- mtransportFactory.transport.setTargetPrincipal(invalidTargetEmail);
- mtransportFactory.transport.setTokenResponseErrorCode(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
- mtransportFactory.transport.setTokenResponseErrorContent(
+ mockTransportFactory.transport.setTargetPrincipal(invalidTargetEmail);
+ mockTransportFactory.transport.setTokenResponseErrorCode(
+ HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
+ mockTransportFactory.transport.setTokenResponseErrorContent(
generateErrorJson(
HttpStatusCodes.STATUS_CODE_BAD_REQUEST, expectedMessage, "global", "badRequest"));
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
- sourceCredentials, invalidTargetEmail, null, SCOPES, VALID_LIFETIME, mtransportFactory);
+ sourceCredentials,
+ invalidTargetEmail,
+ null,
+ SCOPES,
+ VALID_LIFETIME,
+ mockTransportFactory);
try {
targetCredentials.refreshAccessToken().getTokenValue();
@@ -199,8 +365,7 @@ public void refreshAccessToken_malformedTarget() throws IOException {
}
@Test()
- public void credential_with_zero_lifetime() throws IOException, IllegalStateException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
+ public void credential_with_zero_lifetime() throws IllegalStateException {
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials, IMPERSONATED_CLIENT_EMAIL, null, SCOPES, 0);
@@ -210,7 +375,6 @@ public void credential_with_zero_lifetime() throws IOException, IllegalStateExce
@Test()
public void credential_with_invalid_lifetime() throws IOException, IllegalStateException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
try {
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -228,7 +392,6 @@ public void credential_with_invalid_lifetime() throws IOException, IllegalStateE
@Test()
public void credential_with_invalid_scope() throws IOException, IllegalStateException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
try {
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -245,12 +408,9 @@ public void credential_with_invalid_scope() throws IOException, IllegalStateExce
@Test()
public void refreshAccessToken_success() throws IOException, IllegalStateException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -258,20 +418,59 @@ public void refreshAccessToken_success() throws IOException, IllegalStateExcepti
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
assertEquals(ACCESS_TOKEN, targetCredentials.refreshAccessToken().getTokenValue());
}
+ @Test()
+ public void getRequestMetadata_withQuotaProjectId() throws IOException, IllegalStateException {
+
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ ImpersonatedCredentials targetCredentials =
+ ImpersonatedCredentials.create(
+ sourceCredentials,
+ IMPERSONATED_CLIENT_EMAIL,
+ null,
+ SCOPES,
+ VALID_LIFETIME,
+ mockTransportFactory,
+ QUOTA_PROJECT_ID);
+
+ Map> metadata = targetCredentials.getRequestMetadata();
+ assertTrue(metadata.containsKey("x-goog-user-project"));
+ List headerValues = metadata.get("x-goog-user-project");
+ assertEquals(1, headerValues.size());
+ assertEquals(QUOTA_PROJECT_ID, headerValues.get(0));
+ }
+
+ @Test()
+ public void getRequestMetadata_withoutQuotaProjectId() throws IOException, IllegalStateException {
+
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ ImpersonatedCredentials targetCredentials =
+ ImpersonatedCredentials.create(
+ sourceCredentials,
+ IMPERSONATED_CLIENT_EMAIL,
+ null,
+ SCOPES,
+ VALID_LIFETIME,
+ mockTransportFactory);
+
+ Map> metadata = targetCredentials.getRequestMetadata();
+ assertFalse(metadata.containsKey("x-goog-user-project"));
+ }
+
@Test()
public void refreshAccessToken_delegates_success() throws IOException, IllegalStateException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
List delegates = Arrays.asList("delegate-account@iam.gserviceaccount.com");
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -280,21 +479,18 @@ public void refreshAccessToken_delegates_success() throws IOException, IllegalSt
delegates,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
assertEquals(ACCESS_TOKEN, targetCredentials.refreshAccessToken().getTokenValue());
}
@Test()
- public void refreshAccessToken_invalidDate() throws IOException, IllegalStateException {
+ public void refreshAccessToken_invalidDate() throws IllegalStateException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
String expectedMessage = "Unparseable date";
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken("foo");
- mtransportFactory.transport.setExpireTime("1973-09-29T15:01:23");
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken("foo");
+ mockTransportFactory.transport.setExpireTime("1973-09-29T15:01:23");
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -302,7 +498,7 @@ public void refreshAccessToken_invalidDate() throws IOException, IllegalStateExc
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
try {
targetCredentials.refreshAccessToken().getTokenValue();
@@ -313,13 +509,10 @@ public void refreshAccessToken_invalidDate() throws IOException, IllegalStateExc
}
@Test
- public void getAccount_sameAs() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ public void getAccount_sameAs() {
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -327,19 +520,16 @@ public void getAccount_sameAs() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
assertEquals(IMPERSONATED_CLIENT_EMAIL, targetCredentials.getAccount());
}
@Test
- public void sign_sameAs() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ public void sign_sameAs() {
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -347,24 +537,21 @@ public void sign_sameAs() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
byte[] expectedSignature = {0xD, 0xE, 0xA, 0xD};
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setSignedBlob(expectedSignature);
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setSignedBlob(expectedSignature);
assertArrayEquals(expectedSignature, targetCredentials.sign(expectedSignature));
}
@Test
public void sign_requestIncludesDelegates() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -372,16 +559,16 @@ public void sign_requestIncludesDelegates() throws IOException {
ImmutableList.of("delegate@example.com"),
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
byte[] expectedSignature = {0xD, 0xE, 0xA, 0xD};
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setSignedBlob(expectedSignature);
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setSignedBlob(expectedSignature);
assertArrayEquals(expectedSignature, targetCredentials.sign(expectedSignature));
- MockLowLevelHttpRequest request = mtransportFactory.transport.getRequest();
+ MockLowLevelHttpRequest request = mockTransportFactory.transport.getRequest();
GenericJson body =
JSON_FACTORY
.createJsonParser(request.getContentAsString())
@@ -392,22 +579,18 @@ public void sign_requestIncludesDelegates() throws IOException {
}
@Test
- public void sign_usesSourceCredentials() throws IOException {
- Date expiry = new Date();
+ public void sign_usesSourceCredentials() {
Calendar c = Calendar.getInstance();
- c.setTime(expiry);
c.add(Calendar.DATE, 1);
- expiry = c.getTime();
+ Date expiry = c.getTime();
GoogleCredentials sourceCredentials =
new GoogleCredentials.Builder()
.setAccessToken(new AccessToken("source-token", expiry))
.build();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -415,27 +598,24 @@ public void sign_usesSourceCredentials() throws IOException {
ImmutableList.of("delegate@example.com"),
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
byte[] expectedSignature = {0xD, 0xE, 0xA, 0xD};
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setSignedBlob(expectedSignature);
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setSignedBlob(expectedSignature);
assertArrayEquals(expectedSignature, targetCredentials.sign(expectedSignature));
- MockLowLevelHttpRequest request = mtransportFactory.transport.getRequest();
+ MockLowLevelHttpRequest request = mockTransportFactory.transport.getRequest();
assertEquals("Bearer source-token", request.getFirstHeaderValue("Authorization"));
}
@Test
- public void sign_accessDenied_throws() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ public void sign_accessDenied_throws() {
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -443,13 +623,13 @@ public void sign_accessDenied_throws() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
byte[] expectedSignature = {0xD, 0xE, 0xA, 0xD};
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setSignedBlob(expectedSignature);
- mtransportFactory.transport.setErrorResponseCodeAndMessage(
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setSignedBlob(expectedSignature);
+ mockTransportFactory.transport.setErrorResponseCodeAndMessage(
HttpStatusCodes.STATUS_CODE_FORBIDDEN, "Sign Error");
try {
@@ -464,13 +644,10 @@ public void sign_accessDenied_throws() throws IOException {
}
@Test
- public void sign_serverError_throws() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ public void sign_serverError_throws() {
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
sourceCredentials,
@@ -478,13 +655,13 @@ public void sign_serverError_throws() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
byte[] expectedSignature = {0xD, 0xE, 0xA, 0xD};
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setSignedBlob(expectedSignature);
- mtransportFactory.transport.setErrorResponseCodeAndMessage(
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setSignedBlob(expectedSignature);
+ mockTransportFactory.transport.setErrorResponseCodeAndMessage(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, "Sign Error");
try {
@@ -500,12 +677,9 @@ public void sign_serverError_throws() throws IOException {
@Test
public void idTokenWithAudience_sameAs() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -514,9 +688,9 @@ public void idTokenWithAudience_sameAs() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
- mtransportFactory.transport.setIdToken(STANDARD_ID_TOKEN);
+ mockTransportFactory.transport.setIdToken(STANDARD_ID_TOKEN);
String targetAudience = "https://foo.bar";
IdTokenCredentials tokenCredential =
@@ -534,12 +708,9 @@ public void idTokenWithAudience_sameAs() throws IOException {
@Test
public void idTokenWithAudience_withEmail() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -548,9 +719,9 @@ public void idTokenWithAudience_withEmail() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
- mtransportFactory.transport.setIdToken(TOKEN_WITH_EMAIL);
+ mockTransportFactory.transport.setIdToken(TOKEN_WITH_EMAIL);
String targetAudience = "https://foo.bar";
IdTokenCredentials tokenCredential =
@@ -566,13 +737,10 @@ public void idTokenWithAudience_withEmail() throws IOException {
}
@Test
- public void idToken_withServerError() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ public void idToken_withServerError() {
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -581,10 +749,10 @@ public void idToken_withServerError() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
- mtransportFactory.transport.setIdToken(STANDARD_ID_TOKEN);
- mtransportFactory.transport.setErrorResponseCodeAndMessage(
+ mockTransportFactory.transport.setIdToken(STANDARD_ID_TOKEN);
+ mockTransportFactory.transport.setErrorResponseCodeAndMessage(
HttpStatusCodes.STATUS_CODE_SERVER_ERROR, "Internal Server Error");
String targetAudience = "https://foo.bar";
@@ -601,13 +769,10 @@ public void idToken_withServerError() throws IOException {
}
@Test
- public void idToken_withOtherError() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ public void idToken_withOtherError() {
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -616,10 +781,10 @@ public void idToken_withOtherError() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
- mtransportFactory.transport.setIdToken(STANDARD_ID_TOKEN);
- mtransportFactory.transport.setErrorResponseCodeAndMessage(
+ mockTransportFactory.transport.setIdToken(STANDARD_ID_TOKEN);
+ mockTransportFactory.transport.setErrorResponseCodeAndMessage(
HttpStatusCodes.STATUS_CODE_MOVED_PERMANENTLY, "Redirect");
String targetAudience = "https://foo.bar";
@@ -637,12 +802,9 @@ public void idToken_withOtherError() throws IOException {
@Test
public void hashCode_equals() throws IOException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials credentials =
ImpersonatedCredentials.create(
@@ -651,7 +813,7 @@ public void hashCode_equals() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
ImpersonatedCredentials otherCredentials =
ImpersonatedCredentials.create(
@@ -660,7 +822,7 @@ public void hashCode_equals() throws IOException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
assertEquals(credentials.hashCode(), otherCredentials.hashCode());
}
@@ -668,12 +830,9 @@ public void hashCode_equals() throws IOException {
@Test
public void serialize() throws IOException, ClassNotFoundException {
- GoogleCredentials sourceCredentials = getSourceCredentials();
- MockIAMCredentialsServiceTransportFactory mtransportFactory =
- new MockIAMCredentialsServiceTransportFactory();
- mtransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
- mtransportFactory.transport.setAccessToken(ACCESS_TOKEN);
- mtransportFactory.transport.setExpireTime(getDefaultExpireTime());
+ mockTransportFactory.transport.setTargetPrincipal(IMPERSONATED_CLIENT_EMAIL);
+ mockTransportFactory.transport.setAccessToken(ACCESS_TOKEN);
+ mockTransportFactory.transport.setExpireTime(getDefaultExpireTime());
ImpersonatedCredentials targetCredentials =
ImpersonatedCredentials.create(
@@ -682,7 +841,7 @@ public void serialize() throws IOException, ClassNotFoundException {
null,
SCOPES,
VALID_LIFETIME,
- mtransportFactory);
+ mockTransportFactory);
GoogleCredentials deserializedCredentials = serializeAndDeserialize(targetCredentials);
assertEquals(targetCredentials, deserializedCredentials);
assertEquals(targetCredentials.hashCode(), deserializedCredentials.hashCode());
@@ -690,10 +849,8 @@ public void serialize() throws IOException, ClassNotFoundException {
assertSame(deserializedCredentials.clock, Clock.SYSTEM);
}
- private String getDefaultExpireTime() {
- Date currentDate = new Date();
+ public static String getDefaultExpireTime() {
Calendar c = Calendar.getInstance();
- c.setTime(currentDate);
c.add(Calendar.SECOND, VALID_LIFETIME);
return new SimpleDateFormat(RFC3339).format(c.getTime());
}
@@ -736,4 +893,69 @@ private String generateErrorJson(
generator.close();
return bout.toString();
}
+
+ static GenericJson buildImpersonationCredentialsJson(
+ String impersonationUrl,
+ List delegates,
+ String quotaProjectId,
+ String sourceClientId,
+ String sourceClientSecret,
+ String sourceRefreshToken) {
+ GenericJson sourceJson = new GenericJson();
+
+ sourceJson.put("client_id", sourceClientId);
+ sourceJson.put("client_secret", sourceClientSecret);
+ sourceJson.put("refresh_token", sourceRefreshToken);
+ sourceJson.put("type", "authorized_user");
+ GenericJson json = new GenericJson();
+
+ json.put("service_account_impersonation_url", impersonationUrl);
+ json.put("delegates", delegates);
+ if (quotaProjectId != null) {
+ json.put("quota_project_id", quotaProjectId);
+ }
+ json.put("source_credentials", sourceJson);
+ json.put("type", "impersonated_service_account");
+ return json;
+ }
+
+ static GenericJson buildImpersonationCredentialsJson(
+ String impersonationUrl, List delegates, String quotaProjectId) {
+ GenericJson sourceJson = new GenericJson();
+ sourceJson.put("type", "service_account");
+ sourceJson.put("project_id", PROJECT_ID);
+ sourceJson.put("private_key_id", SA_PRIVATE_KEY_ID);
+ sourceJson.put("private_key", SA_PRIVATE_KEY_PKCS8);
+ sourceJson.put("client_email", SA_CLIENT_EMAIL);
+ sourceJson.put("client_id", "10848832332323213");
+ sourceJson.put("auth_uri", "https://oauth2.googleapis.com/o/oauth2/auth");
+ sourceJson.put("token_uri", "https://oauth2.googleapis.com/token");
+ sourceJson.put("auth_provider_x509_cert_url", "https://www.googleapis.com/oauth2/v1/certs");
+ sourceJson.put(
+ "client_x509_cert_url",
+ "https://www.googleapis.com/robot/v1/metadata/x509/chaoren-test-sc%40cloudsdktest.iam.gserviceaccount.com");
+
+ GenericJson json = new GenericJson();
+ json.put("source_credentials", sourceJson);
+ json.put("service_account_impersonation_url", impersonationUrl);
+ json.put("delegates", delegates);
+ if (quotaProjectId != null) {
+ json.put("quota_project_id", quotaProjectId);
+ }
+ json.put("type", "impersonated_service_account");
+ return json;
+ }
+
+ static GenericJson buildInvalidCredentialsJson() {
+ GenericJson json = new GenericJson();
+ json.put("service_account_impersonation_url", "mock_url");
+ return json;
+ }
+
+ static InputStream writeImpersonationCredentialsStream(
+ String impersonationUrl, List delegates, String quotaProjectId) throws IOException {
+ GenericJson json =
+ buildImpersonationCredentialsJson(impersonationUrl, delegates, quotaProjectId);
+ return TestUtils.jsonToInputStream(json);
+ }
}