All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.auth.oauth2.ExternalAccountCredentials Maven / Gradle / Ivy

There is a newer version: 1.30.0
Show newest version
/*
 * Copyright 2021 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;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.api.client.http.HttpHeaders;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonObjectParser;
import com.google.auth.RequestMetadataCallback;
import com.google.auth.http.HttpTransportFactory;
import com.google.common.base.MoreObjects;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.regex.Pattern;
import javax.annotation.Nullable;

/**
 * Base external account credentials class.
 *
 * 

Handles initializing external credentials, calls to the Security Token Service, and service * account impersonation. */ public abstract class ExternalAccountCredentials extends GoogleCredentials { private static final long serialVersionUID = 8049126194174465023L; private static final String CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform"; static final String EXTERNAL_ACCOUNT_FILE_TYPE = "external_account"; static final String EXECUTABLE_SOURCE_KEY = "executable"; static final String DEFAULT_TOKEN_URL = "https://sts.{UNIVERSE_DOMAIN}/v1/token"; static final String PROGRAMMATIC_METRICS_HEADER_VALUE = "programmatic"; private final String transportFactoryClassName; private final String audience; private final String subjectTokenType; private final String tokenUrl; private final CredentialSource credentialSource; private final Collection scopes; private final ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; private ExternalAccountMetricsHandler metricsHandler; @Nullable private final String tokenInfoUrl; @Nullable private final String serviceAccountImpersonationUrl; @Nullable private final String clientId; @Nullable private final String clientSecret; // This is used for Workforce Pools. It is passed to the Security Token Service during token // exchange in the `options` param and will be embedded in the token by the Security Token // Service. @Nullable private final String workforcePoolUserProject; protected transient HttpTransportFactory transportFactory; @Nullable protected ImpersonatedCredentials impersonatedCredentials; private EnvironmentProvider environmentProvider; /** * Constructor with minimum identifying information and custom HTTP transport. Does not support * workforce credentials. * * @param transportFactory HTTP transport factory, creates the transport used to get access tokens * @param audience the Security Token Service audience, which is usually the fully specified * resource name of the workload/workforce pool provider * @param subjectTokenType the Security Token Service subject token type based on the OAuth 2.0 * token exchange spec. Indicates the type of the security token in the credential file * @param tokenUrl the Security Token Service token exchange endpoint * @param tokenInfoUrl the endpoint used to retrieve account related information. Required for * gCloud session account identification. * @param credentialSource the external credential source * @param serviceAccountImpersonationUrl the URL for the service account impersonation request. * This URL is required for some APIs. If this URL is not available, the access token from the * Security Token Service is used directly. May be null. * @param quotaProjectId the project used for quota and billing purposes. May be null. * @param clientId client ID of the service account from the console. May be null. * @param clientSecret client secret of the service account from the console. May be null. * @param scopes the scopes to request during the authorization grant. May be null. */ protected ExternalAccountCredentials( HttpTransportFactory transportFactory, String audience, String subjectTokenType, String tokenUrl, CredentialSource credentialSource, @Nullable String tokenInfoUrl, @Nullable String serviceAccountImpersonationUrl, @Nullable String quotaProjectId, @Nullable String clientId, @Nullable String clientSecret, @Nullable Collection scopes) { this( transportFactory, audience, subjectTokenType, tokenUrl, credentialSource, tokenInfoUrl, serviceAccountImpersonationUrl, quotaProjectId, clientId, clientSecret, scopes, /* environmentProvider= */ null); } /** * Constructor with minimum identifying information and custom HTTP transport. Does not support * workforce credentials. * * @param transportFactory HTTP transport factory, creates the transport used to get access tokens * @param audience the Security Token Service audience, which is usually the fully specified * resource name of the workload/workforce pool provider * @param subjectTokenType the Security Token Service subject token type based on the OAuth 2.0 * token exchange spec. Indicates the type of the security token in the credential file * @param tokenUrl the Security Token Service token exchange endpoint * @param tokenInfoUrl the endpoint used to retrieve account related information. Required for * gCloud session account identification. * @param credentialSource the external credential source * @param serviceAccountImpersonationUrl the URL for the service account impersonation request. * This URL is required for some APIs. If this URL is not available, the access token from the * Security Token Service is used directly. May be null. * @param quotaProjectId the project used for quota and billing purposes. May be null. * @param clientId client ID of the service account from the console. May be null. * @param clientSecret client secret of the service account from the console. May be null. * @param scopes the scopes to request during the authorization grant. May be null. * @param environmentProvider the environment provider. May be null. Defaults to {@link * SystemEnvironmentProvider}. */ protected ExternalAccountCredentials( HttpTransportFactory transportFactory, String audience, String subjectTokenType, String tokenUrl, CredentialSource credentialSource, @Nullable String tokenInfoUrl, @Nullable String serviceAccountImpersonationUrl, @Nullable String quotaProjectId, @Nullable String clientId, @Nullable String clientSecret, @Nullable Collection scopes, @Nullable EnvironmentProvider environmentProvider) { super(/* accessToken= */ null, quotaProjectId); this.transportFactory = MoreObjects.firstNonNull( transportFactory, getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY)); this.transportFactoryClassName = checkNotNull(this.transportFactory.getClass().getName()); this.audience = checkNotNull(audience); this.subjectTokenType = checkNotNull(subjectTokenType); this.tokenUrl = checkNotNull(tokenUrl); this.credentialSource = checkNotNull(credentialSource); this.tokenInfoUrl = tokenInfoUrl; this.serviceAccountImpersonationUrl = serviceAccountImpersonationUrl; this.clientId = clientId; this.clientSecret = clientSecret; this.scopes = (scopes == null || scopes.isEmpty()) ? Arrays.asList(CLOUD_PLATFORM_SCOPE) : scopes; this.environmentProvider = environmentProvider == null ? SystemEnvironmentProvider.getInstance() : environmentProvider; this.workforcePoolUserProject = null; this.serviceAccountImpersonationOptions = new ServiceAccountImpersonationOptions(new HashMap()); validateTokenUrl(tokenUrl); if (serviceAccountImpersonationUrl != null) { validateServiceAccountImpersonationInfoUrl(serviceAccountImpersonationUrl); } this.metricsHandler = new ExternalAccountMetricsHandler(this); } /** * Internal constructor with minimum identifying information and custom HTTP transport. See {@link * ExternalAccountCredentials.Builder}. * * @param builder the {@code Builder} object used to construct the credentials. */ protected ExternalAccountCredentials(ExternalAccountCredentials.Builder builder) { super(builder); this.transportFactory = MoreObjects.firstNonNull( builder.transportFactory, getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY)); this.transportFactoryClassName = checkNotNull(this.transportFactory.getClass().getName()); this.audience = checkNotNull(builder.audience); this.subjectTokenType = checkNotNull(builder.subjectTokenType); this.credentialSource = builder.credentialSource; this.tokenInfoUrl = builder.tokenInfoUrl; this.serviceAccountImpersonationUrl = builder.serviceAccountImpersonationUrl; this.clientId = builder.clientId; this.clientSecret = builder.clientSecret; if (builder.tokenUrl == null) { this.tokenUrl = DEFAULT_TOKEN_URL.replace("{UNIVERSE_DOMAIN}", this.getUniverseDomain()); } else { this.tokenUrl = builder.tokenUrl; } this.scopes = (builder.scopes == null || builder.scopes.isEmpty()) ? Arrays.asList(CLOUD_PLATFORM_SCOPE) : builder.scopes; this.environmentProvider = builder.environmentProvider == null ? SystemEnvironmentProvider.getInstance() : builder.environmentProvider; this.serviceAccountImpersonationOptions = builder.serviceAccountImpersonationOptions == null ? new ServiceAccountImpersonationOptions(new HashMap()) : builder.serviceAccountImpersonationOptions; this.workforcePoolUserProject = builder.workforcePoolUserProject; if (workforcePoolUserProject != null && !isWorkforcePoolConfiguration()) { throw new IllegalArgumentException( "The workforce_pool_user_project parameter should only be provided for a Workforce Pool configuration."); } validateTokenUrl(tokenUrl); if (serviceAccountImpersonationUrl != null) { validateServiceAccountImpersonationInfoUrl(serviceAccountImpersonationUrl); } this.metricsHandler = builder.metricsHandler == null ? new ExternalAccountMetricsHandler(this) : builder.metricsHandler; } ImpersonatedCredentials buildImpersonatedCredentials() { if (serviceAccountImpersonationUrl == null) { return null; } // Create a copy of this instance without service account impersonation. ExternalAccountCredentials sourceCredentials; if (this instanceof AwsCredentials) { sourceCredentials = AwsCredentials.newBuilder((AwsCredentials) this) .setServiceAccountImpersonationUrl(null) .build(); } else if (this instanceof PluggableAuthCredentials) { sourceCredentials = PluggableAuthCredentials.newBuilder((PluggableAuthCredentials) this) .setServiceAccountImpersonationUrl(null) .build(); } else { sourceCredentials = IdentityPoolCredentials.newBuilder((IdentityPoolCredentials) this) .setServiceAccountImpersonationUrl(null) .build(); } String targetPrincipal = ImpersonatedCredentials.extractTargetPrincipal(serviceAccountImpersonationUrl); return ImpersonatedCredentials.newBuilder() .setSourceCredentials(sourceCredentials) .setHttpTransportFactory(transportFactory) .setTargetPrincipal(targetPrincipal) .setScopes(new ArrayList<>(scopes)) .setLifetime(this.serviceAccountImpersonationOptions.lifetime) .setIamEndpointOverride(serviceAccountImpersonationUrl) .build(); } @Override public void getRequestMetadata( URI uri, Executor executor, final RequestMetadataCallback callback) { super.getRequestMetadata( uri, executor, new RequestMetadataCallback() { @Override public void onSuccess(Map> metadata) { metadata = addQuotaProjectIdToRequestMetadata(quotaProjectId, metadata); callback.onSuccess(metadata); } @Override public void onFailure(Throwable exception) { callback.onFailure(exception); } }); } @Override public String getUniverseDomain() { try { return super.getUniverseDomain(); } catch (IOException e) { // Throwing an IOException would be a breaking change, so wrap it here. // This should not happen for this credential type. throw new IllegalStateException(e); } } @Override public Map> getRequestMetadata(URI uri) throws IOException { Map> requestMetadata = super.getRequestMetadata(uri); return addQuotaProjectIdToRequestMetadata(quotaProjectId, requestMetadata); } /** * Returns credentials defined by a JSON file stream. * *

Returns {@link IdentityPoolCredentials} or {@link AwsCredentials}. * * @param credentialsStream the stream with the credential definition * @return the credential defined by the credentialsStream * @throws IOException if the credential cannot be created from the stream */ public static ExternalAccountCredentials fromStream(InputStream credentialsStream) throws IOException { return fromStream(credentialsStream, OAuth2Utils.HTTP_TRANSPORT_FACTORY); } /** * Returns credentials defined by a JSON file stream. * *

Returns a {@link IdentityPoolCredentials} or {@link AwsCredentials}. * * @param credentialsStream the stream with the credential definition * @param transportFactory the HTTP transport factory used to create the transport to get access * tokens * @return the credential defined by the credentialsStream * @throws IOException if the credential cannot be created from the stream */ public static ExternalAccountCredentials fromStream( InputStream credentialsStream, HttpTransportFactory transportFactory) throws IOException { checkNotNull(credentialsStream); checkNotNull(transportFactory); JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); GenericJson fileContents = parser.parseAndClose(credentialsStream, StandardCharsets.UTF_8, GenericJson.class); try { return fromJson(fileContents, transportFactory); } catch (ClassCastException | IllegalArgumentException e) { throw new CredentialFormatException("An invalid input stream was provided.", e); } } /** * Returns external account credentials defined by JSON using the format generated by gCloud. * * @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 */ @SuppressWarnings("unchecked") static ExternalAccountCredentials fromJson( Map json, HttpTransportFactory transportFactory) { checkNotNull(json); checkNotNull(transportFactory); String audience = (String) json.get("audience"); String subjectTokenType = (String) json.get("subject_token_type"); String tokenUrl = (String) json.get("token_url"); Map credentialSourceMap = (Map) json.get("credential_source"); // Optional params. String serviceAccountImpersonationUrl = (String) json.get("service_account_impersonation_url"); String tokenInfoUrl = (String) json.get("token_info_url"); String clientId = (String) json.get("client_id"); String clientSecret = (String) json.get("client_secret"); String quotaProjectId = (String) json.get("quota_project_id"); String userProject = (String) json.get("workforce_pool_user_project"); String universeDomain = (String) json.get("universe_domain"); Map impersonationOptionsMap = (Map) json.get("service_account_impersonation"); if (impersonationOptionsMap == null) { impersonationOptionsMap = new HashMap(); } if (isAwsCredential(credentialSourceMap)) { return AwsCredentials.newBuilder() .setHttpTransportFactory(transportFactory) .setAudience(audience) .setSubjectTokenType(subjectTokenType) .setTokenUrl(tokenUrl) .setTokenInfoUrl(tokenInfoUrl) .setCredentialSource(new AwsCredentialSource(credentialSourceMap)) .setServiceAccountImpersonationUrl(serviceAccountImpersonationUrl) .setQuotaProjectId(quotaProjectId) .setClientId(clientId) .setClientSecret(clientSecret) .setServiceAccountImpersonationOptions(impersonationOptionsMap) .setUniverseDomain(universeDomain) .build(); } else if (isPluggableAuthCredential(credentialSourceMap)) { return PluggableAuthCredentials.newBuilder() .setHttpTransportFactory(transportFactory) .setAudience(audience) .setSubjectTokenType(subjectTokenType) .setTokenUrl(tokenUrl) .setTokenInfoUrl(tokenInfoUrl) .setCredentialSource(new PluggableAuthCredentialSource(credentialSourceMap)) .setServiceAccountImpersonationUrl(serviceAccountImpersonationUrl) .setQuotaProjectId(quotaProjectId) .setClientId(clientId) .setClientSecret(clientSecret) .setWorkforcePoolUserProject(userProject) .setServiceAccountImpersonationOptions(impersonationOptionsMap) .setUniverseDomain(universeDomain) .build(); } return IdentityPoolCredentials.newBuilder() .setHttpTransportFactory(transportFactory) .setAudience(audience) .setSubjectTokenType(subjectTokenType) .setTokenUrl(tokenUrl) .setTokenInfoUrl(tokenInfoUrl) .setCredentialSource(new IdentityPoolCredentialSource(credentialSourceMap)) .setServiceAccountImpersonationUrl(serviceAccountImpersonationUrl) .setQuotaProjectId(quotaProjectId) .setClientId(clientId) .setClientSecret(clientSecret) .setWorkforcePoolUserProject(userProject) .setServiceAccountImpersonationOptions(impersonationOptionsMap) .setUniverseDomain(universeDomain) .build(); } private static boolean isPluggableAuthCredential(Map credentialSource) { // Pluggable Auth is enabled via a nested executable field in the credential source. return credentialSource.containsKey(EXECUTABLE_SOURCE_KEY); } private static boolean isAwsCredential(Map credentialSource) { return credentialSource.containsKey("environment_id") && ((String) credentialSource.get("environment_id")).startsWith("aws"); } private boolean shouldBuildImpersonatedCredential() { return this.serviceAccountImpersonationUrl != null && this.impersonatedCredentials == null; } /** * Exchanges the external credential for a Google Cloud access token. * * @param stsTokenExchangeRequest the Security Token Service token exchange request * @return the access token returned by the Security Token Service * @throws OAuthException if the call to the Security Token Service fails */ protected AccessToken exchangeExternalCredentialForAccessToken( StsTokenExchangeRequest stsTokenExchangeRequest) throws IOException { // Handle service account impersonation if necessary. if (this.shouldBuildImpersonatedCredential()) { this.impersonatedCredentials = this.buildImpersonatedCredentials(); } if (this.impersonatedCredentials != null) { return this.impersonatedCredentials.refreshAccessToken(); } StsRequestHandler.Builder requestHandler = StsRequestHandler.newBuilder( tokenUrl, stsTokenExchangeRequest, transportFactory.create().createRequestFactory()); // If this credential was initialized with a Workforce configuration then the // workforcePoolUserProject must be passed to the Security Token Service via the internal // options param. if (isWorkforcePoolConfiguration()) { GenericJson options = new GenericJson(); options.setFactory(OAuth2Utils.JSON_FACTORY); options.put("userProject", workforcePoolUserProject); requestHandler.setInternalOptions(options.toString()); } // Set BYOID Metrics header. HttpHeaders additionalHeaders = new HttpHeaders(); additionalHeaders.set( MetricsUtils.API_CLIENT_HEADER, this.metricsHandler.getExternalAccountMetricsHeader()); requestHandler.setHeaders(additionalHeaders); if (stsTokenExchangeRequest.getInternalOptions() != null) { // Overwrite internal options. Let subclass handle setting options. requestHandler.setInternalOptions(stsTokenExchangeRequest.getInternalOptions()); } StsTokenExchangeResponse response = requestHandler.build().exchangeToken(); return response.getAccessToken(); } /** * Retrieves the external subject token to be exchanged for a Google Cloud access token. * *

Must be implemented by subclasses as the retrieval method is dependent on the credential * source. * * @return the external subject token * @throws IOException if the subject token cannot be retrieved */ public abstract String retrieveSubjectToken() throws IOException; public String getAudience() { return audience; } public String getSubjectTokenType() { return subjectTokenType; } public String getTokenUrl() { return tokenUrl; } public String getTokenInfoUrl() { return tokenInfoUrl; } public CredentialSource getCredentialSource() { return credentialSource; } @SuppressWarnings("unused") private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException { // Properly deserialize the transient transportFactory. input.defaultReadObject(); transportFactory = newInstance(transportFactoryClassName); } @Nullable public String getServiceAccountImpersonationUrl() { return serviceAccountImpersonationUrl; } /** @return The service account email to be impersonated, if available */ @Nullable public String getServiceAccountEmail() { if (serviceAccountImpersonationUrl == null || serviceAccountImpersonationUrl.isEmpty()) { return null; } return ImpersonatedCredentials.extractTargetPrincipal(serviceAccountImpersonationUrl); } @Nullable public String getClientId() { return clientId; } @Nullable public String getClientSecret() { return clientSecret; } @Nullable public Collection getScopes() { return scopes; } @Nullable public String getWorkforcePoolUserProject() { return workforcePoolUserProject; } @Nullable public ServiceAccountImpersonationOptions getServiceAccountImpersonationOptions() { return serviceAccountImpersonationOptions; } String getCredentialSourceType() { return "unknown"; } EnvironmentProvider getEnvironmentProvider() { return environmentProvider; } /** * @return whether the current configuration is for Workforce Pools (which enable 3p user * identities, rather than workloads) */ public boolean isWorkforcePoolConfiguration() { Pattern workforceAudiencePattern = Pattern.compile("^//iam.googleapis.com/locations/.+/workforcePools/.+/providers/.+$"); return workforcePoolUserProject != null && workforceAudiencePattern.matcher(getAudience()).matches(); } static void validateTokenUrl(String tokenUrl) { if (!isValidUrl(tokenUrl)) { throw new IllegalArgumentException("The provided token URL is invalid."); } } static void validateServiceAccountImpersonationInfoUrl(String serviceAccountImpersonationUrl) { if (!isValidUrl(serviceAccountImpersonationUrl)) { throw new IllegalArgumentException( "The provided service account impersonation URL is invalid."); } } /** Returns true if the provided URL's scheme is valid and is HTTPS. */ private static boolean isValidUrl(String url) { URI uri; try { uri = URI.create(url); } catch (Exception e) { return false; } // Scheme must be https and host must not be null. if (uri.getScheme() == null || uri.getHost() == null || !"https".equals(uri.getScheme().toLowerCase(Locale.US))) { return false; } return true; } /** * Encapsulates the service account impersonation options portion of the configuration for * ExternalAccountCredentials. * *

If token_lifetime_seconds is not specified, the library will default to a 1-hour lifetime. * *

   * Sample configuration:
   * {
   *   ...
   *   "service_account_impersonation": {
   *     "token_lifetime_seconds": 2800
   *    }
   * }
   * 
*/ static final class ServiceAccountImpersonationOptions implements java.io.Serializable { private static final long serialVersionUID = 4250771921886280953L; private static final int DEFAULT_TOKEN_LIFETIME_SECONDS = 3600; private static final int MAXIMUM_TOKEN_LIFETIME_SECONDS = 43200; private static final int MINIMUM_TOKEN_LIFETIME_SECONDS = 600; private static final String TOKEN_LIFETIME_SECONDS_KEY = "token_lifetime_seconds"; private final int lifetime; final boolean customTokenLifetimeRequested; ServiceAccountImpersonationOptions(Map optionsMap) { customTokenLifetimeRequested = optionsMap.containsKey(TOKEN_LIFETIME_SECONDS_KEY); if (!customTokenLifetimeRequested) { lifetime = DEFAULT_TOKEN_LIFETIME_SECONDS; return; } try { Object lifetimeValue = optionsMap.get(TOKEN_LIFETIME_SECONDS_KEY); if (lifetimeValue instanceof BigDecimal) { lifetime = ((BigDecimal) lifetimeValue).intValue(); } else if (optionsMap.get(TOKEN_LIFETIME_SECONDS_KEY) instanceof Integer) { lifetime = (int) lifetimeValue; } else { lifetime = Integer.parseInt((String) lifetimeValue); } } catch (NumberFormatException | ArithmeticException e) { throw new IllegalArgumentException( "Value of \"token_lifetime_seconds\" field could not be parsed into an integer.", e); } if (lifetime < MINIMUM_TOKEN_LIFETIME_SECONDS || lifetime > MAXIMUM_TOKEN_LIFETIME_SECONDS) { throw new IllegalArgumentException( String.format( "The \"token_lifetime_seconds\" field must be between %s and %s seconds.", MINIMUM_TOKEN_LIFETIME_SECONDS, MAXIMUM_TOKEN_LIFETIME_SECONDS)); } } int getLifetime() { return lifetime; } } /** Base builder for external account credentials. */ public abstract static class Builder extends GoogleCredentials.Builder { protected String audience; protected String subjectTokenType; protected String tokenUrl; protected String tokenInfoUrl; protected CredentialSource credentialSource; protected EnvironmentProvider environmentProvider; protected HttpTransportFactory transportFactory; @Nullable protected String serviceAccountImpersonationUrl; @Nullable protected String clientId; @Nullable protected String clientSecret; @Nullable protected Collection scopes; @Nullable protected String workforcePoolUserProject; @Nullable protected ServiceAccountImpersonationOptions serviceAccountImpersonationOptions; /* The field is not being used and value not set. Superseded by the same field in the {@link GoogleCredential.Builder}. */ @Nullable @Deprecated protected String universeDomain; @Nullable protected ExternalAccountMetricsHandler metricsHandler; protected Builder() {} protected Builder(ExternalAccountCredentials credentials) { super(credentials); this.transportFactory = credentials.transportFactory; this.audience = credentials.audience; this.subjectTokenType = credentials.subjectTokenType; this.tokenUrl = credentials.tokenUrl; this.tokenInfoUrl = credentials.tokenInfoUrl; this.serviceAccountImpersonationUrl = credentials.serviceAccountImpersonationUrl; this.credentialSource = credentials.credentialSource; this.clientId = credentials.clientId; this.clientSecret = credentials.clientSecret; this.scopes = credentials.scopes; this.environmentProvider = credentials.environmentProvider; this.workforcePoolUserProject = credentials.workforcePoolUserProject; this.serviceAccountImpersonationOptions = credentials.serviceAccountImpersonationOptions; this.metricsHandler = credentials.metricsHandler; } /** * Sets the HTTP transport factory, creates the transport used to get access tokens. * * @param transportFactory the {@code HttpTransportFactory} to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) { this.transportFactory = transportFactory; return this; } /** * Sets the Security Token Service audience, which is usually the fully specified resource name * of the workload/workforce pool provider. * * @param audience the Security Token Service audience to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setAudience(String audience) { this.audience = audience; return this; } /** * Sets the Security Token Service subject token type based on the OAuth 2.0 token exchange * spec. Indicates the type of the security token in the credential file. * * @param subjectTokenType the Security Token Service subject token type to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setSubjectTokenType(String subjectTokenType) { this.subjectTokenType = subjectTokenType; return this; } /** * Sets the Security Token Service subject token type based on the OAuth 2.0 token exchange * spec. Indicates the type of the security token in the credential file. * * @param subjectTokenType the {@code SubjectTokenType} to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setSubjectTokenType(SubjectTokenTypes subjectTokenType) { this.subjectTokenType = subjectTokenType.value; return this; } /** * Sets the Security Token Service token exchange endpoint. * * @param tokenUrl the Security Token Service token exchange url to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setTokenUrl(String tokenUrl) { this.tokenUrl = tokenUrl; return this; } /** * Sets the external credential source. * * @param credentialSource the {@code CredentialSource} to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setCredentialSource(CredentialSource credentialSource) { this.credentialSource = credentialSource; return this; } /** * Sets the optional URL used for service account impersonation, which is required for some * APIs. If this URL is not available, the access token from the Security Token Service is used * directly. * * @param serviceAccountImpersonationUrl the service account impersonation url to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setServiceAccountImpersonationUrl(String serviceAccountImpersonationUrl) { this.serviceAccountImpersonationUrl = serviceAccountImpersonationUrl; return this; } /** * Sets the optional endpoint used to retrieve account related information. Required for gCloud * session account identification. * * @param tokenInfoUrl the token info url to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setTokenInfoUrl(String tokenInfoUrl) { this.tokenInfoUrl = tokenInfoUrl; return this; } /** * Sets the optional project used for quota and billing purposes. * * @param quotaProjectId the quota and billing project id to set * @return this {@code Builder} object */ @Override @CanIgnoreReturnValue public Builder setQuotaProjectId(String quotaProjectId) { super.setQuotaProjectId(quotaProjectId); return this; } /** * Sets the optional client ID of the service account from the console. * * @param clientId the service account client id to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setClientId(String clientId) { this.clientId = clientId; return this; } /** * Sets the optional client secret of the service account from the console. * * @param clientSecret the service account client secret to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setClientSecret(String clientSecret) { this.clientSecret = clientSecret; return this; } /** * Sets the optional scopes to request during the authorization grant. * * @param scopes the request scopes to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setScopes(Collection scopes) { this.scopes = scopes; return this; } /** * Sets the optional workforce pool user project number when the credential corresponds to a * workforce pool and not a workload identity pool. The underlying principal must still have * serviceusage.services.use IAM permission to use the project for billing/quota. * * @param workforcePoolUserProject the workforce pool user project number to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setWorkforcePoolUserProject(String workforcePoolUserProject) { this.workforcePoolUserProject = workforcePoolUserProject; return this; } /** * Sets the optional service account impersonation options. * * @param optionsMap the service account impersonation options to set * @return this {@code Builder} object */ @CanIgnoreReturnValue public Builder setServiceAccountImpersonationOptions(Map optionsMap) { this.serviceAccountImpersonationOptions = new ServiceAccountImpersonationOptions(optionsMap); return this; } /** * Sets the optional universe domain. * * @param universeDomain the universe domain to set * @return this {@code Builder} object */ @CanIgnoreReturnValue @Override public Builder setUniverseDomain(String universeDomain) { super.setUniverseDomain(universeDomain); return this; } /** * Sets the optional Environment Provider. * * @param environmentProvider the {@code EnvironmentProvider} to set * @return this {@code Builder} object */ @CanIgnoreReturnValue Builder setEnvironmentProvider(EnvironmentProvider environmentProvider) { this.environmentProvider = environmentProvider; return this; } @Override public abstract ExternalAccountCredentials build(); } /** * Enum specifying values for the subjectTokenType field in {@code ExternalAccountCredentials}. */ public enum SubjectTokenTypes { AWS4("urn:ietf:params:aws:token-type:aws4_request"), JWT("urn:ietf:params:oauth:token-type:jwt"), SAML2("urn:ietf:params:oauth:token-type:saml2"), ID_TOKEN("urn:ietf:params:oauth:token-type:id_token"); public final String value; private SubjectTokenTypes(String value) { this.value = value; } } /** Base credential source class. Dictates the retrieval method of the external credential. */ abstract static class CredentialSource implements java.io.Serializable { private static final long serialVersionUID = 8204657811562399944L; CredentialSource(Map credentialSourceMap) { checkNotNull(credentialSourceMap); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy