Skip to content

Commit

Permalink
feat: support reading in quotaProjectId for billing
Browse files Browse the repository at this point in the history
  • Loading branch information
codyoss committed Dec 9, 2019
1 parent 7267f3a commit c9c1f7b
Show file tree
Hide file tree
Showing 9 changed files with 325 additions and 64 deletions.
19 changes: 18 additions & 1 deletion oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
Expand Up @@ -39,12 +39,14 @@
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.*;

/** 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";

Expand Down Expand Up @@ -166,6 +168,21 @@ 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, or else returns the original requestMetadata
*/
static Map<String, List<String>> addQuotaProjectIdToRequestMetadata(String quotaProjectId, Map<String, List<String>> requestMetadata) {
Preconditions.checkNotNull(requestMetadata, "requestMetadata");
if (quotaProjectId != null && !requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) {
Map<String, List<String>> newRequestMetadata = new HashMap<>(requestMetadata);
newRequestMetadata.put(QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId));
return Collections.unmodifiableMap(newRequestMetadata);
}
return requestMetadata;
}

/** Default constructor. */
protected GoogleCredentials() {
this(null);
Expand Down
102 changes: 87 additions & 15 deletions oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java
Expand Up @@ -75,11 +75,7 @@
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;

/**
* OAuth2 credentials representing a Service Account for calling Google APIs.
Expand All @@ -102,6 +98,7 @@ public class ServiceAccountCredentials extends GoogleCredentials
private final String transportFactoryClassName;
private final URI tokenServerUri;
private final Collection<String> scopes;
private final String quotaProjectId;

private transient HttpTransportFactory transportFactory;

Expand All @@ -119,6 +116,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,
Expand All @@ -129,7 +128,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);
Expand All @@ -143,6 +143,7 @@ public class ServiceAccountCredentials extends GoogleCredentials
this.tokenServerUri = (tokenServerUri == null) ? OAuth2Utils.TOKEN_SERVER_URI : tokenServerUri;
this.serviceAccountUser = serviceAccountUser;
this.projectId = projectId;
this.quotaProjectId = quotaProjectId;
}

/**
Expand All @@ -163,6 +164,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 quotaProject = (String) json.get("quota_project_id");
URI tokenServerUriFromCreds = null;
try {
if (tokenServerUriStringFromCreds != null) {
Expand All @@ -189,7 +191,8 @@ static ServiceAccountCredentials fromJson(
transportFactory,
tokenServerUriFromCreds,
null,
projectId);
projectId,
quotaProject);
}

/**
Expand All @@ -212,7 +215,7 @@ public static ServiceAccountCredentials fromPkcs8(
Collection<String> scopes)
throws IOException {
return fromPkcs8(
clientId, clientEmail, privateKeyPkcs8, privateKeyId, scopes, null, null, null);
clientId, clientEmail, privateKeyPkcs8, privateKeyId, scopes, null, null, null, null);
}

/**
Expand Down Expand Up @@ -248,6 +251,7 @@ public static ServiceAccountCredentials fromPkcs8(
scopes,
transportFactory,
tokenServerUri,
null,
null);
}

Expand Down Expand Up @@ -291,6 +295,49 @@ public static ServiceAccountCredentials fromPkcs8(
null);
}

/**
* Factory with minimum identifying information and custom transport using PKCS#8 for the private
* key.
*
* @param clientId Client ID of the service account from the console. May be null.
* @param clientEmail Client email address of the service account from the console.
* @param privateKeyPkcs8 RSA private key object for the service account in PKCS#8 format.
* @param privateKeyId Private key identifier for the service account. May be null.
* @param scopes Scope strings for the APIs to be called. May be null or an empty collection,
* which results in a credential that must have createScoped called before use.
* @param transportFactory HTTP transport factory, creates the transport used to get access
* tokens.
* @param tokenServerUri URI of the end point that provides tokens.
* @param serviceAccountUser The email of the user account to impersonate, if delegating
* domain-wide authority to the service account.
* @param quotaProjectId The project used for quota and billing purposes. May be null.
* @return New ServiceAccountCredentials created from a private key.
* @throws IOException if the credential cannot be created from the private key.
*/
public static ServiceAccountCredentials fromPkcs8(
String clientId,
String clientEmail,
String privateKeyPkcs8,
String privateKeyId,
Collection<String> scopes,
HttpTransportFactory transportFactory,
URI tokenServerUri,
String serviceAccountUser,
String quotaProjectId)
throws IOException {
return fromPkcs8(
clientId,
clientEmail,
privateKeyPkcs8,
privateKeyId,
scopes,
transportFactory,
tokenServerUri,
serviceAccountUser,
null,
quotaProjectId);
}

static ServiceAccountCredentials fromPkcs8(
String clientId,
String clientEmail,
Expand All @@ -300,7 +347,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(
Expand All @@ -312,7 +360,8 @@ static ServiceAccountCredentials fromPkcs8(
transportFactory,
tokenServerUri,
serviceAccountUser,
projectId);
projectId,
quotaProject);
}

/** Helper to convert from a PKCS#8 String to an RSA private key */
Expand Down Expand Up @@ -499,7 +548,8 @@ public GoogleCredentials createScoped(Collection<String> newScopes) {
transportFactory,
tokenServerUri,
serviceAccountUser,
projectId);
projectId,
quotaProjectId);
}

@Override
Expand All @@ -513,7 +563,8 @@ public GoogleCredentials createDelegated(String user) {
transportFactory,
tokenServerUri,
user,
projectId);
projectId,
quotaProjectId);
}

public final String getClientId() {
Expand Down Expand Up @@ -584,6 +635,12 @@ public JwtCredentials jwtWithClaims(JwtClaims newClaims) {
.build();
}

@Override
public Map<String, List<String>> getRequestMetadata(URI uri) throws IOException {
Map<String, List<String>> requestMetadata = super.getRequestMetadata(uri);
return addQuotaProjectIdToRequestMetadata(quotaProjectId, requestMetadata);
}

@Override
public int hashCode() {
return Objects.hash(
Expand All @@ -593,7 +650,8 @@ public int hashCode() {
privateKeyId,
transportFactoryClassName,
tokenServerUri,
scopes);
scopes,
quotaProjectId);
}

@Override
Expand All @@ -606,6 +664,7 @@ public String toString() {
.add("tokenServerUri", tokenServerUri)
.add("scopes", scopes)
.add("serviceAccountUser", serviceAccountUser)
.add("quotaProjectId", quotaProjectId)
.toString();
}

Expand All @@ -621,7 +680,8 @@ public boolean equals(Object obj) {
&& Objects.equals(this.privateKeyId, other.privateKeyId)
&& Objects.equals(this.transportFactoryClassName, other.transportFactoryClassName)
&& Objects.equals(this.tokenServerUri, other.tokenServerUri)
&& Objects.equals(this.scopes, other.scopes);
&& Objects.equals(this.scopes, other.scopes)
&& Objects.equals(this.quotaProjectId, other.quotaProjectId);
}

String createAssertion(JsonFactory jsonFactory, long currentTime, String audience)
Expand Down Expand Up @@ -713,6 +773,7 @@ public static class Builder extends GoogleCredentials.Builder {
private URI tokenServerUri;
private Collection<String> scopes;
private HttpTransportFactory transportFactory;
private String quotaProjectId;

protected Builder() {}

Expand All @@ -726,6 +787,7 @@ protected Builder(ServiceAccountCredentials credentials) {
this.tokenServerUri = credentials.tokenServerUri;
this.serviceAccountUser = credentials.serviceAccountUser;
this.projectId = credentials.projectId;
this.quotaProjectId = credentials.quotaProjectId;
}

public Builder setClientId(String clientId) {
Expand Down Expand Up @@ -773,6 +835,11 @@ public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {
return this;
}

public Builder setQuotaProjectId(String quotaProjectId) {
this.quotaProjectId = quotaProjectId;
return this;
}

public String getClientId() {
return clientId;
}
Expand Down Expand Up @@ -809,6 +876,10 @@ public HttpTransportFactory getHttpTransportFactory() {
return transportFactory;
}

public String getQuotaProjectId() {
return quotaProjectId;
}

public ServiceAccountCredentials build() {
return new ServiceAccountCredentials(
clientId,
Expand All @@ -819,7 +890,8 @@ public ServiceAccountCredentials build() {
transportFactory,
tokenServerUri,
serviceAccountUser,
projectId);
projectId,
quotaProjectId);
}
}
}

0 comments on commit c9c1f7b

Please sign in to comment.