diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index e7f275b1b..c32e72f47 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -40,11 +40,17 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** Base type for credentials for authorizing calls to Google APIs using OAuth2. */ public class GoogleCredentials extends OAuth2Credentials { private static final long serialVersionUID = -1522852442442473691L; + static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project"; + static final String USER_FILE_TYPE = "authorized_user"; static final String SERVICE_ACCOUNT_FILE_TYPE = "service_account"; @@ -166,6 +172,22 @@ public static GoogleCredentials fromStream( fileType, USER_FILE_TYPE, SERVICE_ACCOUNT_FILE_TYPE)); } + /** + * Adds quota project ID to requestMetadata if present. + * + * @return a new map with quotaProjectId added if needed + */ + static Map> addQuotaProjectIdToRequestMetadata( + String quotaProjectId, Map> requestMetadata) { + Preconditions.checkNotNull(requestMetadata); + Map> newRequestMetadata = new HashMap<>(requestMetadata); + if (quotaProjectId != null && !requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { + newRequestMetadata.put( + QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId)); + } + return Collections.unmodifiableMap(newRequestMetadata); + } + /** Default constructor. */ protected GoogleCredentials() { this(null); diff --git a/oauth2_http/java/com/google/auth/oauth2/QuotaProjectIdProvider.java b/oauth2_http/java/com/google/auth/oauth2/QuotaProjectIdProvider.java new file mode 100644 index 000000000..5456823e0 --- /dev/null +++ b/oauth2_http/java/com/google/auth/oauth2/QuotaProjectIdProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright 2019, Google LLC + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.google.auth.oauth2; + +/** Interface for {@link GoogleCredentials} that return a quota project ID. */ +public interface QuotaProjectIdProvider { + /** @return the quota project ID used for quota and billing purposes */ + String getQuotaProjectId(); +} diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index 1aac83a60..f26448545 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -87,7 +87,7 @@ *

By default uses a JSON Web Token (JWT) to fetch access tokens. */ public class ServiceAccountCredentials extends GoogleCredentials - implements ServiceAccountSigner, IdTokenProvider, JwtProvider { + implements ServiceAccountSigner, IdTokenProvider, JwtProvider, QuotaProjectIdProvider { private static final long serialVersionUID = 7807543542681217978L; private static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer"; @@ -102,6 +102,7 @@ public class ServiceAccountCredentials extends GoogleCredentials private final String transportFactoryClassName; private final URI tokenServerUri; private final Collection scopes; + private final String quotaProjectId; private transient HttpTransportFactory transportFactory; @@ -119,6 +120,8 @@ public class ServiceAccountCredentials extends GoogleCredentials * @param tokenServerUri URI of the end point that provides tokens. * @param serviceAccountUser Email of the user account to impersonate, if delegating domain-wide * authority to the service account. + * @param projectId the project used for billing + * @param quotaProjectId The project used for quota and billing purposes. May be null. */ ServiceAccountCredentials( String clientId, @@ -129,7 +132,8 @@ public class ServiceAccountCredentials extends GoogleCredentials HttpTransportFactory transportFactory, URI tokenServerUri, String serviceAccountUser, - String projectId) { + String projectId, + String quotaProjectId) { this.clientId = clientId; this.clientEmail = Preconditions.checkNotNull(clientEmail); this.privateKey = Preconditions.checkNotNull(privateKey); @@ -143,6 +147,7 @@ public class ServiceAccountCredentials extends GoogleCredentials this.tokenServerUri = (tokenServerUri == null) ? OAuth2Utils.TOKEN_SERVER_URI : tokenServerUri; this.serviceAccountUser = serviceAccountUser; this.projectId = projectId; + this.quotaProjectId = quotaProjectId; } /** @@ -163,6 +168,7 @@ static ServiceAccountCredentials fromJson( String privateKeyId = (String) json.get("private_key_id"); String projectId = (String) json.get("project_id"); String tokenServerUriStringFromCreds = (String) json.get("token_uri"); + String quotaProjectId = (String) json.get("quota_project_id"); URI tokenServerUriFromCreds = null; try { if (tokenServerUriStringFromCreds != null) { @@ -189,7 +195,8 @@ static ServiceAccountCredentials fromJson( transportFactory, tokenServerUriFromCreds, null, - projectId); + projectId, + quotaProjectId); } /** @@ -212,7 +219,7 @@ public static ServiceAccountCredentials fromPkcs8( Collection scopes) throws IOException { return fromPkcs8( - clientId, clientEmail, privateKeyPkcs8, privateKeyId, scopes, null, null, null); + clientId, clientEmail, privateKeyPkcs8, privateKeyId, scopes, null, null, null, null, null); } /** @@ -248,6 +255,8 @@ public static ServiceAccountCredentials fromPkcs8( scopes, transportFactory, tokenServerUri, + null, + null, null); } @@ -288,6 +297,7 @@ public static ServiceAccountCredentials fromPkcs8( transportFactory, tokenServerUri, serviceAccountUser, + null, null); } @@ -300,7 +310,8 @@ static ServiceAccountCredentials fromPkcs8( HttpTransportFactory transportFactory, URI tokenServerUri, String serviceAccountUser, - String projectId) + String projectId, + String quotaProject) throws IOException { PrivateKey privateKey = privateKeyFromPkcs8(privateKeyPkcs8); return new ServiceAccountCredentials( @@ -312,7 +323,8 @@ static ServiceAccountCredentials fromPkcs8( transportFactory, tokenServerUri, serviceAccountUser, - projectId); + projectId, + quotaProject); } /** Helper to convert from a PKCS#8 String to an RSA private key */ @@ -452,7 +464,7 @@ public boolean isRequired(HttpResponse response) { */ @Beta @Override - public IdToken idTokenWithAudience(String targetAudience, List options) + public IdToken idTokenWithAudience(String targetAudience, List

Uses a JSON Web Token (JWT) directly in the request metadata to provide authorization. */ public class ServiceAccountJwtAccessCredentials extends Credentials - implements JwtProvider, ServiceAccountSigner { + implements JwtProvider, ServiceAccountSigner, QuotaProjectIdProvider { private static final long serialVersionUID = -7274955171379494197L; static final String JWT_ACCESS_PREFIX = OAuth2Utils.BEARER_PREFIX; @@ -84,6 +85,7 @@ public class ServiceAccountJwtAccessCredentials extends Credentials private final PrivateKey privateKey; private final String privateKeyId; private final URI defaultAudience; + private final String quotaProjectId; private transient LoadingCache credentialsCache; @@ -103,7 +105,7 @@ public class ServiceAccountJwtAccessCredentials extends Credentials @Deprecated public ServiceAccountJwtAccessCredentials( String clientId, String clientEmail, PrivateKey privateKey, String privateKeyId) { - this(clientId, clientEmail, privateKey, privateKeyId, null); + this(clientId, clientEmail, privateKey, privateKeyId, null, null); } /** @@ -120,13 +122,15 @@ private ServiceAccountJwtAccessCredentials( String clientEmail, PrivateKey privateKey, String privateKeyId, - URI defaultAudience) { + URI defaultAudience, + String quotaProjectId) { this.clientId = clientId; this.clientEmail = Preconditions.checkNotNull(clientEmail); this.privateKey = Preconditions.checkNotNull(privateKey); this.privateKeyId = privateKeyId; this.defaultAudience = defaultAudience; this.credentialsCache = createCache(); + this.quotaProjectId = quotaProjectId; } /** @@ -156,6 +160,7 @@ static ServiceAccountJwtAccessCredentials fromJson(Map json, URI String clientEmail = (String) json.get("client_email"); String privateKeyPkcs8 = (String) json.get("private_key"); String privateKeyId = (String) json.get("private_key_id"); + String quoataProjectId = (String) json.get("quota_project_id"); if (clientId == null || clientEmail == null || privateKeyPkcs8 == null @@ -164,7 +169,8 @@ static ServiceAccountJwtAccessCredentials fromJson(Map json, URI "Error reading service account credential from JSON, " + "expecting 'client_id', 'client_email', 'private_key' and 'private_key_id'."); } - return fromPkcs8(clientId, clientEmail, privateKeyPkcs8, privateKeyId, defaultAudience); + return ServiceAccountJwtAccessCredentials.fromPkcs8( + clientId, clientEmail, privateKeyPkcs8, privateKeyId, defaultAudience, quoataProjectId); } /** @@ -201,9 +207,21 @@ public static ServiceAccountJwtAccessCredentials fromPkcs8( String privateKeyId, URI defaultAudience) throws IOException { + return ServiceAccountJwtAccessCredentials.fromPkcs8( + clientId, clientEmail, privateKeyPkcs8, privateKeyId, defaultAudience, null); + } + + static ServiceAccountJwtAccessCredentials fromPkcs8( + String clientId, + String clientEmail, + String privateKeyPkcs8, + String privateKeyId, + URI defaultAudience, + String quotaProjectId) + throws IOException { PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(privateKeyPkcs8); return new ServiceAccountJwtAccessCredentials( - clientId, clientEmail, privateKey, privateKeyId, defaultAudience); + clientId, clientEmail, privateKey, privateKeyId, defaultAudience, quotaProjectId); } /** @@ -344,7 +362,8 @@ public Map> getRequestMetadata(URI uri) throws IOException .setSubject(clientEmail) .build(); JwtCredentials credentials = credentialsCache.get(defaultClaims); - return credentials.getRequestMetadata(uri); + Map> requestMetadata = credentials.getRequestMetadata(uri); + return addQuotaProjectIdToRequestMetadata(quotaProjectId, requestMetadata); } catch (ExecutionException e) { Throwables.propagateIfPossible(e.getCause(), IOException.class); // Should never happen @@ -400,7 +419,8 @@ public byte[] sign(byte[] toSign) { @Override public int hashCode() { - return Objects.hash(clientId, clientEmail, privateKey, privateKeyId, defaultAudience); + return Objects.hash( + clientId, clientEmail, privateKey, privateKeyId, defaultAudience, quotaProjectId); } @Override @@ -410,6 +430,7 @@ public String toString() { .add("clientEmail", clientEmail) .add("privateKeyId", privateKeyId) .add("defaultAudience", defaultAudience) + .add("quotaProjectId", quotaProjectId) .toString(); } @@ -423,7 +444,8 @@ public boolean equals(Object obj) { && Objects.equals(this.clientEmail, other.clientEmail) && Objects.equals(this.privateKey, other.privateKey) && Objects.equals(this.privateKeyId, other.privateKeyId) - && Objects.equals(this.defaultAudience, other.defaultAudience); + && Objects.equals(this.defaultAudience, other.defaultAudience) + && Objects.equals(this.quotaProjectId, other.quotaProjectId); } private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException { @@ -440,6 +462,11 @@ public Builder toBuilder() { return new Builder(this); } + @Override + public String getQuotaProjectId() { + return quotaProjectId; + } + public static class Builder { private String clientId; @@ -447,6 +474,7 @@ public static class Builder { private PrivateKey privateKey; private String privateKeyId; private URI defaultAudience; + private String quotaProjectId; protected Builder() {} @@ -456,6 +484,7 @@ protected Builder(ServiceAccountJwtAccessCredentials credentials) { this.privateKey = credentials.privateKey; this.privateKeyId = credentials.privateKeyId; this.defaultAudience = credentials.defaultAudience; + this.quotaProjectId = credentials.quotaProjectId; } public Builder setClientId(String clientId) { @@ -483,6 +512,11 @@ public Builder setDefaultAudience(URI defaultAudience) { return this; } + public Builder setQuotaProjectId(String quotaProjectId) { + this.quotaProjectId = quotaProjectId; + return this; + } + public String getClientId() { return clientId; } @@ -503,9 +537,13 @@ public URI getDefaultAudience() { return defaultAudience; } + public String getQuotaProjectId() { + return quotaProjectId; + } + public ServiceAccountJwtAccessCredentials build() { return new ServiceAccountJwtAccessCredentials( - clientId, clientEmail, privateKey, privateKeyId, defaultAudience); + clientId, clientEmail, privateKey, privateKeyId, defaultAudience, quotaProjectId); } } } diff --git a/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java b/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java index e2f3fce84..5010a9ae6 100644 --- a/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/UserCredentials.java @@ -53,11 +53,12 @@ import java.io.ObjectInputStream; import java.net.URI; import java.util.Date; +import java.util.List; import java.util.Map; import java.util.Objects; /** OAuth2 Credentials representing a user's identity and consent. */ -public class UserCredentials extends GoogleCredentials { +public class UserCredentials extends GoogleCredentials implements QuotaProjectIdProvider { private static final String GRANT_TYPE = "refresh_token"; private static final String PARSE_ERROR_PREFIX = "Error parsing token refresh response. "; @@ -68,6 +69,7 @@ public class UserCredentials extends GoogleCredentials { private final String refreshToken; private final URI tokenServerUri; private final String transportFactoryClassName; + private final String quotaProjectId; private transient HttpTransportFactory transportFactory; @@ -88,7 +90,8 @@ private UserCredentials( String refreshToken, AccessToken accessToken, HttpTransportFactory transportFactory, - URI tokenServerUri) { + URI tokenServerUri, + String quotaProjectId) { super(accessToken); this.clientId = Preconditions.checkNotNull(clientId); this.clientSecret = Preconditions.checkNotNull(clientSecret); @@ -99,6 +102,7 @@ private UserCredentials( getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY)); this.tokenServerUri = (tokenServerUri == null) ? OAuth2Utils.TOKEN_SERVER_URI : tokenServerUri; this.transportFactoryClassName = this.transportFactory.getClass().getName(); + this.quotaProjectId = quotaProjectId; Preconditions.checkState( accessToken != null || refreshToken != null, "Either accessToken or refreshToken must not be null"); @@ -118,6 +122,7 @@ static UserCredentials fromJson(Map json, HttpTransportFactory t String clientId = (String) json.get("client_id"); String clientSecret = (String) json.get("client_secret"); String refreshToken = (String) json.get("refresh_token"); + String quotaProjectId = (String) json.get("quota_project_id"); if (clientId == null || clientSecret == null || refreshToken == null) { throw new IOException( "Error reading user credential from JSON, " @@ -130,6 +135,7 @@ static UserCredentials fromJson(Map json, HttpTransportFactory t .setAccessToken(null) .setHttpTransportFactory(transportFactory) .setTokenServerUri(null) + .setQuotaProjectId(quotaProjectId) .build(); } @@ -252,6 +258,9 @@ private InputStream getUserCredentialsStream() throws IOException { if (clientSecret != null) { json.put("client_secret", clientSecret); } + if (quotaProjectId != null) { + json.put("quota_project", clientSecret); + } json.setFactory(JSON_FACTORY); String text = json.toPrettyString(); return new ByteArrayInputStream(text.getBytes(UTF_8)); @@ -267,6 +276,12 @@ public void save(String filePath) throws IOException { OAuth2Utils.writeInputStreamToFile(getUserCredentialsStream(), filePath); } + @Override + public Map> getRequestMetadata(URI uri) throws IOException { + Map> requestMetadata = super.getRequestMetadata(uri); + return addQuotaProjectIdToRequestMetadata(quotaProjectId, requestMetadata); + } + @Override public int hashCode() { return Objects.hash( @@ -275,7 +290,8 @@ public int hashCode() { clientSecret, refreshToken, tokenServerUri, - transportFactoryClassName); + transportFactoryClassName, + quotaProjectId); } @Override @@ -287,6 +303,7 @@ public String toString() { .add("refreshToken", refreshToken) .add("tokenServerUri", tokenServerUri) .add("transportFactoryClassName", transportFactoryClassName) + .add("quotaProjectId", quotaProjectId) .toString(); } @@ -301,7 +318,8 @@ public boolean equals(Object obj) { && Objects.equals(this.clientSecret, other.clientSecret) && Objects.equals(this.refreshToken, other.refreshToken) && Objects.equals(this.tokenServerUri, other.tokenServerUri) - && Objects.equals(this.transportFactoryClassName, other.transportFactoryClassName); + && Objects.equals(this.transportFactoryClassName, other.transportFactoryClassName) + && Objects.equals(this.quotaProjectId, other.quotaProjectId); } private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException { @@ -317,6 +335,11 @@ public Builder toBuilder() { return new Builder(this); } + @Override + public String getQuotaProjectId() { + return quotaProjectId; + } + public static class Builder extends GoogleCredentials.Builder { private String clientId; @@ -324,6 +347,7 @@ public static class Builder extends GoogleCredentials.Builder { private String refreshToken; private URI tokenServerUri; private HttpTransportFactory transportFactory; + private String quotaProjectId; protected Builder() {} @@ -333,6 +357,7 @@ protected Builder(UserCredentials credentials) { this.refreshToken = credentials.refreshToken; this.transportFactory = credentials.transportFactory; this.tokenServerUri = credentials.tokenServerUri; + this.quotaProjectId = credentials.quotaProjectId; } public Builder setClientId(String clientId) { @@ -365,6 +390,11 @@ public Builder setAccessToken(AccessToken token) { return this; } + public Builder setQuotaProjectId(String quotaProjectId) { + this.quotaProjectId = quotaProjectId; + return this; + } + public String getClientId() { return clientId; } @@ -385,9 +415,19 @@ public HttpTransportFactory getHttpTransportFactory() { return transportFactory; } + public String getQuotaProjectId() { + return quotaProjectId; + } + public UserCredentials build() { return new UserCredentials( - clientId, clientSecret, refreshToken, getAccessToken(), transportFactory, tokenServerUri); + clientId, + clientSecret, + refreshToken, + getAccessToken(), + transportFactory, + tokenServerUri, + quotaProjectId); } } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/DefaultCredentialsProviderTest.java b/oauth2_http/javatests/com/google/auth/oauth2/DefaultCredentialsProviderTest.java index 00a3d0387..8db555318 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/DefaultCredentialsProviderTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/DefaultCredentialsProviderTest.java @@ -85,9 +85,10 @@ public class DefaultCredentialsProviderTest { "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com"; private static final String SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; private static final String SA_PRIVATE_KEY_PKCS8 = - ServiceAccountCredentialsTest.SA_PRIVATE_KEY_PKCS8; + ServiceAccountCredentialsTest.PRIVATE_KEY_PKCS8; private static final Collection SCOPES = Collections.singletonList("dummy.scope"); private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); + private static final String QUOTA_PROJECT = "sample-quota-project-id"; static class MockRequestCountingTransportFactory implements HttpTransportFactory { @@ -132,7 +133,8 @@ public void getDefaultCredentials_noCredentialsSandbox_throwsNonSecurity() throw public void getDefaultCredentials_envValidSandbox_throwsNonSecurity() throws Exception { MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); testProvider.setFileSandbox(true); String userPath = tempFilePath("user.json"); @@ -314,7 +316,8 @@ public void getDefaultCredentials_envServiceAccount_providesToken() throws IOExc @Test public void getDefaultCredentials_envUser_providesToken() throws IOException { InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); String userPath = tempFilePath("user.json"); testProvider.addFile(userPath, userStream); @@ -361,7 +364,8 @@ public void getDefaultCredentials_envGceMetadataHost_setsTokenServerUrl() { public void getDefaultCredentials_wellKnownFileEnv_providesToken() throws IOException { File cloudConfigDir = getTempDirectory(); InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); File wellKnownFile = new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); @@ -377,7 +381,8 @@ public void getDefaultCredentials_wellKnownFileNonWindows_providesToken() throws File configDir = new File(homeDir, ".config"); File cloudConfigDir = new File(configDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); File wellKnownFile = new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); @@ -393,7 +398,8 @@ public void getDefaultCredentials_wellKnownFileWindows_providesToken() throws IO File homeDir = getTempDirectory(); File cloudConfigDir = new File(homeDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); File wellKnownFile = new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); @@ -413,7 +419,8 @@ public void getDefaultCredentials_envAndWellKnownFile_envPrecedence() throws IOE TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); InputStream envStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, refreshTokenEnv); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, refreshTokenEnv, QUOTA_PROJECT); String envPath = tempFilePath("env.json"); testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, envPath); testProvider.addFile(envPath, envStream); @@ -422,7 +429,8 @@ public void getDefaultCredentials_envAndWellKnownFile_envPrecedence() throws IOE File configDir = new File(homeDir, ".config"); File cloudConfigDir = new File(configDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); InputStream wkfStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, refreshTokenWkf); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, refreshTokenWkf, QUOTA_PROJECT); File wellKnownFile = new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); testProvider.setProperty("os.name", "linux"); @@ -480,7 +488,8 @@ private LogRecord getCredentialsAndReturnLogMessage(boolean suppressWarning) thr File configDir = new File(homeDir, ".config"); File cloudConfigDir = new File(configDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); InputStream userStream = - UserCredentialsTest.writeUserStream(GCLOUDSDK_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + GCLOUDSDK_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); File wellKnownFile = new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index 99d0bc9aa..ebf60a8ce 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -65,7 +65,7 @@ public class GoogleCredentialsTest { "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com"; private static final String SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; private static final String SA_PRIVATE_KEY_PKCS8 = - ServiceAccountCredentialsTest.SA_PRIVATE_KEY_PKCS8; + ServiceAccountCredentialsTest.PRIVATE_KEY_PKCS8; private static final String USER_CLIENT_SECRET = "jakuaL9YyieakhECKL2SwZcu"; private static final String USER_CLIENT_ID = "ya29.1.AADtN_UtlxN3PuGAxrN2XQnZTVRvDyVWnYq4I6dws"; private static final String REFRESH_TOKEN = "1/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY"; @@ -73,6 +73,7 @@ public class GoogleCredentialsTest { private static final HttpTransportFactory DUMMY_TRANSPORT_FACTORY = new MockTokenServerTransportFactory(); private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); + private static final String QUOTA_PROJECT = "sample-quota-project-id"; private static final Collection SCOPES = Collections.unmodifiableCollection(Arrays.asList("scope1", "scope2")); @@ -188,7 +189,8 @@ public void fromStream_user_providesToken() throws IOException { transportFactory.transport.addClient(USER_CLIENT_ID, USER_CLIENT_SECRET); transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN); InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, null); GoogleCredentials credentials = GoogleCredentials.fromStream(userStream, transportFactory); @@ -200,7 +202,7 @@ public void fromStream_user_providesToken() throws IOException { @Test public void fromStream_userNoClientId_throws() throws IOException { InputStream userStream = - UserCredentialsTest.writeUserStream(null, USER_CLIENT_SECRET, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream(null, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); testFromStreamException(userStream, "client_id"); } @@ -208,7 +210,7 @@ public void fromStream_userNoClientId_throws() throws IOException { @Test public void fromStream_userNoClientSecret_throws() throws IOException { InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, null, REFRESH_TOKEN); + UserCredentialsTest.writeUserStream(USER_CLIENT_ID, null, REFRESH_TOKEN, QUOTA_PROJECT); testFromStreamException(userStream, "client_secret"); } @@ -216,7 +218,8 @@ public void fromStream_userNoClientSecret_throws() throws IOException { @Test public void fromStream_userNoRefreshToken_throws() throws IOException { InputStream userStream = - UserCredentialsTest.writeUserStream(USER_CLIENT_ID, USER_CLIENT_SECRET, null); + UserCredentialsTest.writeUserStream( + USER_CLIENT_ID, USER_CLIENT_SECRET, null, QUOTA_PROJECT); testFromStreamException(userStream, "refresh_token"); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/OAuth2CredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/OAuth2CredentialsTest.java index 353b7b48b..2f8c7d68a 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/OAuth2CredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/OAuth2CredentialsTest.java @@ -335,7 +335,7 @@ public void getRequestMetadata_async_refreshRace() throws IOException { // When the task is run, the cached data is used. assertEquals(1, executor.runTasksExhaustively()); assertEquals(0, transportFactory.transport.buildRequestCount); - assertSame(metadata, callback.metadata); + assertEquals(metadata, callback.metadata); } @Test diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index be12fc7f1..779c7f006 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -76,12 +76,12 @@ @RunWith(JUnit4.class) public class ServiceAccountCredentialsTest extends BaseSerializationTest { - private static final String SA_CLIENT_EMAIL = + private static final String CLIENT_EMAIL = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr@developer.gserviceaccount.com"; - private static final String SA_CLIENT_ID = + private static final String CLIENT_ID = "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com"; - private static final String SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; - static final String SA_PRIVATE_KEY_PKCS8 = + private static final String PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; + static final String PRIVATE_KEY_PKCS8 = "-----BEGIN PRIVATE KEY-----\n" + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX0PQoe1igW12i" + "kv1bN/r9lN749y2ijmbc/mFHPyS3hNTyOCjDvBbXYbDhQJzWVUikh4mvGBA07qTj79Xc3yBDfKP2IeyYQIFe0t0" @@ -96,7 +96,7 @@ public class ServiceAccountCredentialsTest extends BaseSerializationTest { + "==\n-----END PRIVATE KEY-----\n"; private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2"; private static final Collection SCOPES = Collections.singletonList("dummy.scope"); - private static final String SERVICE_ACCOUNT_USER = "user@example.com"; + private static final String USER = "user@example.com"; private static final String PROJECT_ID = "project-id"; private static final Collection EMPTY_SCOPES = Collections.emptyList(); private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); @@ -108,18 +108,19 @@ public class ServiceAccountCredentialsTest extends BaseSerializationTest { + "CJhenAiOiIxMDIxMDE1NTA4MzQyMDA3MDg1NjgiLCJleHAiOjE1NjQ0NzUwNTEsImlhdCI6MTU2NDQ3MTQ1MSwi" + "aXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTAyMTAxNTUwODM0MjAwNzA4NTY4In0" + ".redacted"; + private static final String QUOTA_PROJECT = "sample-quota-project-id"; @Test public void createdScoped_clones() throws IOException { - PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); GoogleCredentials credentials = ServiceAccountCredentials.newBuilder() - .setClientId(SA_CLIENT_ID) - .setClientEmail(SA_CLIENT_EMAIL) + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) - .setPrivateKeyId(SA_PRIVATE_KEY_ID) + .setPrivateKeyId(PRIVATE_KEY_ID) .setScopes(SCOPES) - .setServiceAccountUser(SERVICE_ACCOUNT_USER) + .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) .build(); List newScopes = Arrays.asList("scope1", "scope2"); @@ -127,12 +128,12 @@ public void createdScoped_clones() throws IOException { ServiceAccountCredentials newCredentials = (ServiceAccountCredentials) credentials.createScoped(newScopes); - assertEquals(SA_CLIENT_ID, newCredentials.getClientId()); - assertEquals(SA_CLIENT_EMAIL, newCredentials.getClientEmail()); + assertEquals(CLIENT_ID, newCredentials.getClientId()); + assertEquals(CLIENT_EMAIL, newCredentials.getClientEmail()); assertEquals(privateKey, newCredentials.getPrivateKey()); - assertEquals(SA_PRIVATE_KEY_ID, newCredentials.getPrivateKeyId()); + assertEquals(PRIVATE_KEY_ID, newCredentials.getPrivateKeyId()); assertArrayEquals(newScopes.toArray(), newCredentials.getScopes().toArray()); - assertEquals(SERVICE_ACCOUNT_USER, newCredentials.getServiceAccountUser()); + assertEquals(USER, newCredentials.getServiceAccountUser()); assertEquals(PROJECT_ID, newCredentials.getProjectId()); assertArrayEquals( @@ -141,46 +142,47 @@ public void createdScoped_clones() throws IOException { @Test public void createdDelegated_clones() throws IOException { - PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); ServiceAccountCredentials credentials = ServiceAccountCredentials.newBuilder() - .setClientId(SA_CLIENT_ID) - .setClientEmail(SA_CLIENT_EMAIL) + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) - .setPrivateKeyId(SA_PRIVATE_KEY_ID) + .setPrivateKeyId(PRIVATE_KEY_ID) .setScopes(SCOPES) - .setServiceAccountUser(SERVICE_ACCOUNT_USER) + .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) + .setQuotaProjectId(QUOTA_PROJECT) .build(); String newServiceAccountUser = "stranger@other.org"; ServiceAccountCredentials newCredentials = (ServiceAccountCredentials) credentials.createDelegated(newServiceAccountUser); - assertEquals(SA_CLIENT_ID, newCredentials.getClientId()); - assertEquals(SA_CLIENT_EMAIL, newCredentials.getClientEmail()); + assertEquals(CLIENT_ID, newCredentials.getClientId()); + assertEquals(CLIENT_EMAIL, newCredentials.getClientEmail()); assertEquals(privateKey, newCredentials.getPrivateKey()); - assertEquals(SA_PRIVATE_KEY_ID, newCredentials.getPrivateKeyId()); + assertEquals(PRIVATE_KEY_ID, newCredentials.getPrivateKeyId()); assertArrayEquals(SCOPES.toArray(), newCredentials.getScopes().toArray()); assertEquals(newServiceAccountUser, newCredentials.getServiceAccountUser()); assertEquals(PROJECT_ID, newCredentials.getProjectId()); + assertEquals(QUOTA_PROJECT, newCredentials.getQuotaProjectId()); - assertEquals( - SERVICE_ACCOUNT_USER, ((ServiceAccountCredentials) credentials).getServiceAccountUser()); + assertEquals(USER, ((ServiceAccountCredentials) credentials).getServiceAccountUser()); } @Test public void createAssertion_correct() throws IOException { - PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); List scopes = Arrays.asList("scope1", "scope2"); ServiceAccountCredentials credentials = ServiceAccountCredentials.newBuilder() - .setClientId(SA_CLIENT_ID) - .setClientEmail(SA_CLIENT_EMAIL) + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) - .setPrivateKeyId(SA_PRIVATE_KEY_ID) + .setPrivateKeyId(PRIVATE_KEY_ID) .setScopes(scopes) - .setServiceAccountUser(SERVICE_ACCOUNT_USER) + .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) .build(); @@ -190,25 +192,25 @@ public void createAssertion_correct() throws IOException { JsonWebSignature signature = JsonWebSignature.parse(jsonFactory, assertion); JsonWebToken.Payload payload = signature.getPayload(); - assertEquals(SA_CLIENT_EMAIL, payload.getIssuer()); + assertEquals(CLIENT_EMAIL, payload.getIssuer()); assertEquals(OAuth2Utils.TOKEN_SERVER_URI.toString(), payload.getAudience()); assertEquals(currentTimeMillis / 1000, (long) payload.getIssuedAtTimeSeconds()); assertEquals(currentTimeMillis / 1000 + 3600, (long) payload.getExpirationTimeSeconds()); - assertEquals(SERVICE_ACCOUNT_USER, payload.getSubject()); + assertEquals(USER, payload.getSubject()); assertEquals(Joiner.on(' ').join(scopes), payload.get("scope")); } @Test public void createAssertionForIdToken_correct() throws IOException { - PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); ServiceAccountCredentials credentials = ServiceAccountCredentials.newBuilder() - .setClientId(SA_CLIENT_ID) - .setClientEmail(SA_CLIENT_EMAIL) + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) - .setPrivateKeyId(SA_PRIVATE_KEY_ID) - .setServiceAccountUser(SERVICE_ACCOUNT_USER) + .setPrivateKeyId(PRIVATE_KEY_ID) + .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) .build(); @@ -220,24 +222,24 @@ public void createAssertionForIdToken_correct() throws IOException { JsonWebSignature signature = JsonWebSignature.parse(jsonFactory, assertion); JsonWebToken.Payload payload = signature.getPayload(); - assertEquals(SA_CLIENT_EMAIL, payload.getIssuer()); + assertEquals(CLIENT_EMAIL, payload.getIssuer()); assertEquals("https://foo.com/bar", (String) (payload.getUnknownKeys().get("target_audience"))); assertEquals(currentTimeMillis / 1000, (long) payload.getIssuedAtTimeSeconds()); assertEquals(currentTimeMillis / 1000 + 3600, (long) payload.getExpirationTimeSeconds()); - assertEquals(SERVICE_ACCOUNT_USER, payload.getSubject()); + assertEquals(USER, payload.getSubject()); } @Test public void createAssertionForIdToken_incorrect() throws IOException { - PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); ServiceAccountCredentials credentials = ServiceAccountCredentials.newBuilder() - .setClientId(SA_CLIENT_ID) - .setClientEmail(SA_CLIENT_EMAIL) + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) - .setPrivateKeyId(SA_PRIVATE_KEY_ID) - .setServiceAccountUser(SERVICE_ACCOUNT_USER) + .setPrivateKeyId(PRIVATE_KEY_ID) + .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) .build(); @@ -249,26 +251,26 @@ public void createAssertionForIdToken_incorrect() throws IOException { JsonWebSignature signature = JsonWebSignature.parse(jsonFactory, assertion); JsonWebToken.Payload payload = signature.getPayload(); - assertEquals(SA_CLIENT_EMAIL, payload.getIssuer()); + assertEquals(CLIENT_EMAIL, payload.getIssuer()); assertNotEquals( "https://bar.com/foo", (String) (payload.getUnknownKeys().get("target_audience"))); assertEquals(currentTimeMillis / 1000, (long) payload.getIssuedAtTimeSeconds()); assertEquals(currentTimeMillis / 1000 + 3600, (long) payload.getExpirationTimeSeconds()); - assertEquals(SERVICE_ACCOUNT_USER, payload.getSubject()); + assertEquals(USER, payload.getSubject()); } @Test public void createAssertion_withTokenUri_correct() throws IOException { - PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(PRIVATE_KEY_PKCS8); List scopes = Arrays.asList("scope1", "scope2"); ServiceAccountCredentials credentials = ServiceAccountCredentials.newBuilder() - .setClientId(SA_CLIENT_ID) - .setClientEmail(SA_CLIENT_EMAIL) + .setClientId(CLIENT_ID) + .setClientEmail(CLIENT_EMAIL) .setPrivateKey(privateKey) - .setPrivateKeyId(SA_PRIVATE_KEY_ID) + .setPrivateKeyId(PRIVATE_KEY_ID) .setScopes(scopes) - .setServiceAccountUser(SERVICE_ACCOUNT_USER) + .setServiceAccountUser(USER) .setProjectId(PROJECT_ID) .build(); @@ -279,24 +281,24 @@ public void createAssertion_withTokenUri_correct() throws IOException { JsonWebSignature signature = JsonWebSignature.parse(jsonFactory, assertion); JsonWebToken.Payload payload = signature.getPayload(); - assertEquals(SA_CLIENT_EMAIL, payload.getIssuer()); + assertEquals(CLIENT_EMAIL, payload.getIssuer()); assertEquals("https://foo.com/bar", payload.getAudience()); assertEquals(currentTimeMillis / 1000, (long) payload.getIssuedAtTimeSeconds()); assertEquals(currentTimeMillis / 1000 + 3600, (long) payload.getExpirationTimeSeconds()); - assertEquals(SERVICE_ACCOUNT_USER, payload.getSubject()); + assertEquals(USER, payload.getSubject()); assertEquals(Joiner.on(' ').join(scopes), payload.get("scope")); } @Test public void createdScoped_enablesAccessTokens() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GoogleCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, null, transportFactory, null); @@ -318,7 +320,7 @@ public void createdScoped_enablesAccessTokens() throws IOException { public void createScopedRequired_emptyScopes_true() throws IOException { GoogleCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, EMPTY_SCOPES); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, EMPTY_SCOPES); assertTrue(credentials.createScopedRequired()); } @@ -327,7 +329,7 @@ public void createScopedRequired_emptyScopes_true() throws IOException { public void createScopedRequired_nonEmptyScopes_false() throws IOException { GoogleCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, SCOPES); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, SCOPES); assertFalse(credentials.createScopedRequired()); } @@ -335,10 +337,10 @@ public void createScopedRequired_nonEmptyScopes_false() throws IOException { @Test public void fromJSON_getProjectId() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, PROJECT_ID); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -348,10 +350,10 @@ public void fromJSON_getProjectId() throws IOException { @Test public void fromJSON_getProjectIdNull() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null, null); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -361,10 +363,10 @@ public void fromJSON_getProjectIdNull() throws IOException { @Test public void fromJSON_hasAccessToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, PROJECT_ID); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null); GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); @@ -377,26 +379,43 @@ public void fromJSON_hasAccessToken() throws IOException { public void fromJSON_tokenServerUri() throws IOException { final String tokenServerUri = "https://foo.com/bar"; MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); GenericJson json = writeServiceAccountJson( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, PROJECT_ID); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, null); json.put("token_uri", tokenServerUri); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); assertEquals(URI.create(tokenServerUri), credentials.getTokenServerUri()); } + @Test + public void fromJson_hasQuotaProjectId() throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); + GenericJson json = + writeServiceAccountJson( + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, PROJECT_ID, QUOTA_PROJECT); + GoogleCredentials credentials = ServiceAccountCredentials.fromJson(json, transportFactory); + credentials = credentials.createScoped(SCOPES); + Map> metadata = credentials.getRequestMetadata(CALL_URI); + + assertTrue(metadata.containsKey(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY)); + assertEquals( + metadata.get(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY), + Collections.singletonList(QUOTA_PROJECT)); + } + @Test public void getRequestMetadata_hasAccessToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); @@ -410,14 +429,14 @@ public void getRequestMetadata_hasAccessToken() throws IOException { public void getRequestMetadata_customTokenServer_hasAccessToken() throws IOException { final URI TOKEN_SERVER = URI.create("https://foo.com/bar"); MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); transportFactory.transport.setTokenServerUri(TOKEN_SERVER); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, TOKEN_SERVER); @@ -435,18 +454,18 @@ public void refreshAccessToken_refreshesToken() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken2); + transport.addServiceAccount(CLIENT_EMAIL, accessToken2); credentials.refresh(); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken2); } @@ -458,16 +477,16 @@ public void refreshAccessToken_tokenExpiry() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); credentials.clock = new FixedClock(0L); - transport.addServiceAccount(SA_CLIENT_EMAIL, tokenString); + transport.addServiceAccount(CLIENT_EMAIL, tokenString); AccessToken accessToken = credentials.refreshAccessToken(); assertEquals(tokenString, accessToken.getTokenValue()); assertEquals(3600 * 1000L, accessToken.getExpirationTimeMillis().longValue()); @@ -487,19 +506,19 @@ public void refreshAccessToken_retriesIOException() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); transport.addResponseErrorSequence(new IOException()); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken2); + transport.addServiceAccount(CLIENT_EMAIL, accessToken2); credentials.refresh(); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken2); } @@ -512,19 +531,19 @@ public void refreshAccessToken_retriesForbiddenError() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); transport.addResponseSequence(new MockLowLevelHttpResponse().setStatusCode(403)); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken2); + transport.addServiceAccount(CLIENT_EMAIL, accessToken2); credentials.refresh(); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken2); } @@ -537,19 +556,19 @@ public void refreshAccessToken_retriesServerError() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); transport.addResponseSequence(new MockLowLevelHttpResponse().setStatusCode(500)); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken2); + transport.addServiceAccount(CLIENT_EMAIL, accessToken2); credentials.refresh(); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken2); } @@ -562,20 +581,20 @@ public void refreshAccessToken_failsNotFoundError() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); try { transport.addResponseSequence(new MockLowLevelHttpResponse().setStatusCode(404)); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken2); + transport.addServiceAccount(CLIENT_EMAIL, accessToken2); credentials.refresh(); fail("Should not retry on Not Found"); } catch (IOException expected) { @@ -590,15 +609,15 @@ public void idTokenWithAudience_correct() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); String targetAudience = "https://foo.bar"; @@ -622,15 +641,15 @@ public void idTokenWithAudience_incorrect() throws IOException { MockTokenServerTransport transport = transportFactory.transport; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, null); - transport.addServiceAccount(SA_CLIENT_EMAIL, accessToken1); + transport.addServiceAccount(CLIENT_EMAIL, accessToken1); TestUtils.assertContainsBearerToken(credentials.getRequestMetadata(CALL_URI), accessToken1); String targetAudience = "https://bar"; @@ -649,7 +668,7 @@ public void idTokenWithAudience_incorrect() throws IOException { public void getScopes_nullReturnsEmpty() throws IOException { ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null); Collection scopes = credentials.getScopes(); @@ -661,8 +680,8 @@ public void getScopes_nullReturnsEmpty() throws IOException { public void getAccount_sameAs() throws IOException { ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, null); - assertEquals(SA_CLIENT_EMAIL, credentials.getAccount()); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null); + assertEquals(CLIENT_EMAIL, credentials.getAccount()); } @Test @@ -671,7 +690,7 @@ public void sign_sameAs() byte[] toSign = {0xD, 0xE, 0xA, 0xD}; ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID, null); + CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID, null); byte[] signedBytes = credentials.sign(toSign); Signature signature = Signature.getInstance(OAuth2Utils.SIGNATURE_ALGORITHM); signature.initSign(credentials.getPrivateKey()); @@ -685,19 +704,19 @@ public void equals_true() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, tokenServer); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, tokenServer); @@ -711,19 +730,19 @@ public void equals_false_clientId() throws IOException { MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( "otherClientId", - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); @@ -737,19 +756,19 @@ public void equals_false_email() throws IOException { MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, + CLIENT_ID, "otherEmail", - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); @@ -763,18 +782,18 @@ public void equals_false_keyId() throws IOException { MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, "otherId", SCOPES, serverTransportFactory, @@ -789,19 +808,19 @@ public void equals_false_scopes() throws IOException { MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, ImmutableSet.of(), serverTransportFactory, tokenServer1); @@ -816,19 +835,19 @@ public void equals_false_transportFactory() throws IOException { MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, httpTransportFactory, tokenServer1); @@ -843,19 +862,19 @@ public void equals_false_tokenServer() throws IOException { MockTokenServerTransportFactory serverTransportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer1); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, serverTransportFactory, tokenServer2); @@ -869,25 +888,29 @@ public void toString_containsFields() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, tokenServer, - SERVICE_ACCOUNT_USER); + USER, + null, + QUOTA_PROJECT); String expectedToString = String.format( "ServiceAccountCredentials{clientId=%s, clientEmail=%s, privateKeyId=%s, " - + "transportFactoryClassName=%s, tokenServerUri=%s, scopes=%s, serviceAccountUser=%s}", - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_ID, + + "transportFactoryClassName=%s, tokenServerUri=%s, scopes=%s, serviceAccountUser=%s, " + + "quotaProjectId=%s}", + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_ID, MockTokenServerTransportFactory.class.getName(), tokenServer, SCOPES, - SERVICE_ACCOUNT_USER); + USER, + QUOTA_PROJECT); assertEquals(expectedToString, credentials.toString()); } @@ -897,19 +920,19 @@ public void hashCode_equals() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); OAuth2Credentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, tokenServer); OAuth2Credentials otherCredentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, tokenServer); @@ -922,10 +945,10 @@ public void serialize() throws IOException, ClassNotFoundException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); ServiceAccountCredentials credentials = ServiceAccountCredentials.fromPkcs8( - SA_CLIENT_ID, - SA_CLIENT_EMAIL, - SA_PRIVATE_KEY_PKCS8, - SA_PRIVATE_KEY_ID, + CLIENT_ID, + CLIENT_EMAIL, + PRIVATE_KEY_PKCS8, + PRIVATE_KEY_ID, SCOPES, transportFactory, tokenServer); @@ -964,10 +987,9 @@ public void fromStream_nullStream_throws() throws IOException { @Test public void fromStream_providesToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); - transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); + transportFactory.transport.addServiceAccount(CLIENT_EMAIL, ACCESS_TOKEN); InputStream serviceAccountStream = - writeServiceAccountStream( - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID); + writeServiceAccountStream(CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID); GoogleCredentials credentials = ServiceAccountCredentials.fromStream(serviceAccountStream, transportFactory); @@ -981,7 +1003,7 @@ public void fromStream_providesToken() throws IOException { @Test public void fromStream_noClientId_throws() throws IOException { InputStream serviceAccountStream = - writeServiceAccountStream(null, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID); + writeServiceAccountStream(null, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID); testFromStreamException(serviceAccountStream, "client_id"); } @@ -989,7 +1011,7 @@ public void fromStream_noClientId_throws() throws IOException { @Test public void fromStream_noClientEmail_throws() throws IOException { InputStream serviceAccountStream = - writeServiceAccountStream(SA_CLIENT_ID, null, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID); + writeServiceAccountStream(CLIENT_ID, null, PRIVATE_KEY_PKCS8, PRIVATE_KEY_ID); testFromStreamException(serviceAccountStream, "client_email"); } @@ -997,7 +1019,7 @@ public void fromStream_noClientEmail_throws() throws IOException { @Test public void fromStream_noPrivateKey_throws() throws IOException { InputStream serviceAccountStream = - writeServiceAccountStream(SA_CLIENT_ID, SA_CLIENT_EMAIL, null, SA_PRIVATE_KEY_ID); + writeServiceAccountStream(CLIENT_ID, CLIENT_EMAIL, null, PRIVATE_KEY_ID); testFromStreamException(serviceAccountStream, "private_key"); } @@ -1005,7 +1027,7 @@ public void fromStream_noPrivateKey_throws() throws IOException { @Test public void fromStream_noPrivateKeyId_throws() throws IOException { InputStream serviceAccountStream = - writeServiceAccountStream(SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, null); + writeServiceAccountStream(CLIENT_ID, CLIENT_EMAIL, PRIVATE_KEY_PKCS8, null); testFromStreamException(serviceAccountStream, "private_key_id"); } @@ -1015,7 +1037,8 @@ static GenericJson writeServiceAccountJson( String clientEmail, String privateKeyPkcs8, String privateKeyId, - String projectId) { + String projectId, + String quotaProjectId) { GenericJson json = new GenericJson(); if (clientId != null) { json.put("client_id", clientId); @@ -1032,6 +1055,9 @@ static GenericJson writeServiceAccountJson( if (projectId != null) { json.put("project_id", projectId); } + if (quotaProjectId != null) { + json.put("quota_project_id", quotaProjectId); + } json.put("type", GoogleCredentials.SERVICE_ACCOUNT_FILE_TYPE); return json; } @@ -1040,7 +1066,7 @@ static InputStream writeServiceAccountStream( String clientId, String clientEmail, String privateKeyPkcs8, String privateKeyId) throws IOException { GenericJson json = - writeServiceAccountJson(clientId, clientEmail, privateKeyPkcs8, privateKeyId, null); + writeServiceAccountJson(clientId, clientEmail, privateKeyPkcs8, privateKeyId, null, null); return TestUtils.jsonToInputStream(json); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountJwtAccessCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountJwtAccessCredentialsTest.java index 5435148c6..64ca7d408 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountJwtAccessCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountJwtAccessCredentialsTest.java @@ -57,6 +57,7 @@ import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -90,6 +91,7 @@ public class ServiceAccountJwtAccessCredentialsTest extends BaseSerializationTes ServiceAccountJwtAccessCredentials.JWT_ACCESS_PREFIX; private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); + private static final String QUOTA_PROJECT = "sample-quota-project-id"; @Test public void constructor_allParameters_constructs() throws IOException { @@ -100,12 +102,14 @@ public void constructor_allParameters_constructs() throws IOException { .setClientEmail(SA_CLIENT_EMAIL) .setPrivateKey(privateKey) .setPrivateKeyId(SA_PRIVATE_KEY_ID) + .setQuotaProjectId(QUOTA_PROJECT) .build(); assertEquals(SA_CLIENT_ID, credentials.getClientId()); assertEquals(SA_CLIENT_EMAIL, credentials.getClientEmail()); assertEquals(privateKey, credentials.getPrivateKey()); assertEquals(SA_PRIVATE_KEY_ID, credentials.getPrivateKeyId()); + assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); } @Test @@ -396,6 +400,26 @@ public void getRequestMetadata_async_cached() throws IOException { assertEquals(callback1.metadata, callback2.metadata); } + @Test + public void getRequestMetadata_contains_quotaProjectId() throws IOException { + PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); + Credentials credentials = + ServiceAccountJwtAccessCredentials.newBuilder() + .setClientId(SA_CLIENT_ID) + .setClientEmail(SA_CLIENT_EMAIL) + .setPrivateKey(privateKey) + .setPrivateKeyId(SA_PRIVATE_KEY_ID) + .setDefaultAudience(CALL_URI) + .setQuotaProjectId(QUOTA_PROJECT) + .build(); + + Map> metadata = credentials.getRequestMetadata(CALL_URI); + assertTrue(metadata.containsKey(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY)); + assertEquals( + metadata.get(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY), + Collections.singletonList(QUOTA_PROJECT)); + } + @Test public void getAccount_sameAs() throws IOException { PrivateKey privateKey = ServiceAccountCredentials.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); @@ -554,12 +578,13 @@ public void toString_containsFields() throws IOException { .setPrivateKey(privateKey) .setPrivateKeyId(SA_PRIVATE_KEY_ID) .setDefaultAudience(CALL_URI) + .setQuotaProjectId(QUOTA_PROJECT) .build(); String expectedToString = String.format( "ServiceAccountJwtAccessCredentials{clientId=%s, clientEmail=%s, privateKeyId=%s, " - + "defaultAudience=%s}", - SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_ID, CALL_URI); + + "defaultAudience=%s, quotaProjectId=%s}", + SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_ID, CALL_URI, QUOTA_PROJECT); assertEquals(expectedToString, credentials.toString()); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java index f34fa6c87..92e8ebe73 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/UserCredentialsTest.java @@ -68,6 +68,7 @@ public class UserCredentialsTest extends BaseSerializationTest { private static final String CLIENT_ID = "ya29.1.AADtN_UtlxN3PuGAxrN2XQnZTVRvDyVWnYq4I6dws"; private static final String REFRESH_TOKEN = "1/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY"; private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2"; + private static final String QUOTA_PROJECT = "sample-quota-project-id"; private static final Collection SCOPES = Collections.singletonList("dummy.scope"); private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); @@ -77,14 +78,18 @@ public void constructor_accessAndRefreshTokenNull_throws() { } @Test - public void constructor_storesRefreshToken() { + public void constructor() { UserCredentials credentials = UserCredentials.newBuilder() .setClientId(CLIENT_ID) .setClientSecret(CLIENT_SECRET) .setRefreshToken(REFRESH_TOKEN) + .setQuotaProjectId(QUOTA_PROJECT) .build(); + assertEquals(CLIENT_ID, credentials.getClientId()); + assertEquals(CLIENT_SECRET, credentials.getClientSecret()); assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); + assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); } @Test @@ -114,7 +119,7 @@ public void fromJson_hasAccessToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addClient(CLIENT_ID, CLIENT_SECRET); transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN); - GenericJson json = writeUserJson(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN); + GenericJson json = writeUserJson(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, null); GoogleCredentials credentials = UserCredentials.fromJson(json, transportFactory); @@ -122,6 +127,22 @@ public void fromJson_hasAccessToken() throws IOException { TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); } + @Test + public void fromJson_hasQuotaProjectId() throws IOException { + MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); + transportFactory.transport.addClient(CLIENT_ID, CLIENT_SECRET); + transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN); + GenericJson json = writeUserJson(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); + + GoogleCredentials credentials = UserCredentials.fromJson(json, transportFactory); + + Map> metadata = credentials.getRequestMetadata(CALL_URI); + assertTrue(metadata.containsKey(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY)); + assertEquals( + metadata.get(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY), + Collections.singletonList(QUOTA_PROJECT)); + } + @Test public void getRequestMetadata_initialToken_hasAccessToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); @@ -213,6 +234,7 @@ public void equals_true() throws IOException { .setAccessToken(accessToken) .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServer) + .setQuotaProjectId(QUOTA_PROJECT) .build(); UserCredentials otherCredentials = UserCredentials.newBuilder() @@ -222,6 +244,7 @@ public void equals_true() throws IOException { .setAccessToken(accessToken) .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServer) + .setQuotaProjectId(QUOTA_PROJECT) .build(); assertTrue(credentials.equals(otherCredentials)); assertTrue(otherCredentials.equals(credentials)); @@ -392,6 +415,34 @@ public void equals_false_tokenServer() throws IOException { assertFalse(otherCredentials.equals(credentials)); } + @Test + public void equals_false_quotaProjectId() throws IOException { + final String quotaProject1 = "sample-id-1"; + final String quotaProject2 = "sample-id-2"; + AccessToken accessToken = new AccessToken(ACCESS_TOKEN, null); + MockHttpTransportFactory httpTransportFactory = new MockHttpTransportFactory(); + UserCredentials credentials = + UserCredentials.newBuilder() + .setClientId(CLIENT_ID) + .setClientSecret(CLIENT_SECRET) + .setRefreshToken(REFRESH_TOKEN) + .setAccessToken(accessToken) + .setHttpTransportFactory(httpTransportFactory) + .setQuotaProjectId(quotaProject1) + .build(); + UserCredentials otherCredentials = + UserCredentials.newBuilder() + .setClientId(CLIENT_ID) + .setClientSecret(CLIENT_SECRET) + .setRefreshToken(REFRESH_TOKEN) + .setAccessToken(accessToken) + .setHttpTransportFactory(httpTransportFactory) + .setQuotaProjectId(quotaProject2) + .build(); + assertFalse(credentials.equals(otherCredentials)); + assertFalse(otherCredentials.equals(credentials)); + } + @Test public void toString_containsFields() throws IOException { AccessToken accessToken = new AccessToken(ACCESS_TOKEN, null); @@ -405,12 +456,13 @@ public void toString_containsFields() throws IOException { .setAccessToken(accessToken) .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServer) + .setQuotaProjectId(QUOTA_PROJECT) .build(); String expectedToString = String.format( "UserCredentials{requestMetadata=%s, temporaryAccess=%s, clientId=%s, refreshToken=%s, " - + "tokenServerUri=%s, transportFactoryClassName=%s}", + + "tokenServerUri=%s, transportFactoryClassName=%s, quotaProjectId=%s}", ImmutableMap.of( AuthHttpConstants.AUTHORIZATION, ImmutableList.of(OAuth2Utils.BEARER_PREFIX + accessToken.getTokenValue())), @@ -418,7 +470,8 @@ public void toString_containsFields() throws IOException { CLIENT_ID, REFRESH_TOKEN, tokenServer, - MockTokenServerTransportFactory.class.getName()); + MockTokenServerTransportFactory.class.getName(), + QUOTA_PROJECT); assertEquals(expectedToString, credentials.toString()); } @@ -435,6 +488,7 @@ public void hashCode_equals() throws IOException { .setAccessToken(accessToken) .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServer) + .setQuotaProjectId(QUOTA_PROJECT) .build(); UserCredentials otherCredentials = UserCredentials.newBuilder() @@ -444,6 +498,7 @@ public void hashCode_equals() throws IOException { .setAccessToken(accessToken) .setHttpTransportFactory(transportFactory) .setTokenServerUri(tokenServer) + .setQuotaProjectId(QUOTA_PROJECT) .build(); assertEquals(credentials.hashCode(), otherCredentials.hashCode()); } @@ -496,7 +551,8 @@ public void fromStream_user_providesToken() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); transportFactory.transport.addClient(CLIENT_ID, CLIENT_SECRET); transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN); - InputStream userStream = writeUserStream(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN); + InputStream userStream = + writeUserStream(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); UserCredentials credentials = UserCredentials.fromStream(userStream, transportFactory); @@ -507,21 +563,21 @@ public void fromStream_user_providesToken() throws IOException { @Test public void fromStream_userNoClientId_throws() throws IOException { - InputStream userStream = writeUserStream(null, CLIENT_SECRET, REFRESH_TOKEN); + InputStream userStream = writeUserStream(null, CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); testFromStreamException(userStream, "client_id"); } @Test public void fromStream_userNoClientSecret_throws() throws IOException { - InputStream userStream = writeUserStream(CLIENT_ID, null, REFRESH_TOKEN); + InputStream userStream = writeUserStream(CLIENT_ID, null, REFRESH_TOKEN, QUOTA_PROJECT); testFromStreamException(userStream, "client_secret"); } @Test public void fromStream_userNoRefreshToken_throws() throws IOException { - InputStream userStream = writeUserStream(CLIENT_ID, CLIENT_SECRET, null); + InputStream userStream = writeUserStream(CLIENT_ID, CLIENT_SECRET, null, QUOTA_PROJECT); testFromStreamException(userStream, "refresh_token"); } @@ -566,7 +622,8 @@ public void saveAndRestoreUserCredential_saveAndRestored_throws() throws IOExcep assertEquals(userCredentials.getRefreshToken(), restoredCredentials.getRefreshToken()); } - static GenericJson writeUserJson(String clientId, String clientSecret, String refreshToken) { + static GenericJson writeUserJson( + String clientId, String clientSecret, String refreshToken, String quotaProjectId) { GenericJson json = new GenericJson(); if (clientId != null) { json.put("client_id", clientId); @@ -577,13 +634,17 @@ static GenericJson writeUserJson(String clientId, String clientSecret, String re if (refreshToken != null) { json.put("refresh_token", refreshToken); } + if (quotaProjectId != null) { + json.put("quota_project_id", quotaProjectId); + } json.put("type", GoogleCredentials.USER_FILE_TYPE); return json; } - static InputStream writeUserStream(String clientId, String clientSecret, String refreshToken) + static InputStream writeUserStream( + String clientId, String clientSecret, String refreshToken, String quotaProjectId) throws IOException { - GenericJson json = writeUserJson(clientId, clientSecret, refreshToken); + GenericJson json = writeUserJson(clientId, clientSecret, refreshToken, quotaProjectId); return TestUtils.jsonToInputStream(json); }