diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java index a9b3ef9eb..aa4d7c698 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java @@ -39,10 +39,13 @@ import com.google.auth.RequestMetadataCallback; import com.google.auth.http.HttpTransportFactory; import com.google.common.base.MoreObjects; +import com.google.common.reflect.Reflection; import com.google.errorprone.annotations.CanIgnoreReturnValue; + import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; +import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -402,6 +405,8 @@ static ExternalAccountCredentials fromJson( String tokenUrl = (String) json.get("token_url"); Map credentialSourceMap = (Map) json.get("credential_source"); + String awsSecurityCredentialsSupplierClass = + (String) json.get("security_credentials_supplier_class"); // Optional params. String serviceAccountImpersonationUrl = (String) json.get("service_account_impersonation_url"); @@ -419,20 +424,26 @@ static ExternalAccountCredentials fromJson( } 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(); + AwsCredentials.Builder builder = + AwsCredentials.newBuilder() + .setHttpTransportFactory(transportFactory) + .setAudience(audience) + .setSubjectTokenType(subjectTokenType) + .setTokenUrl(tokenUrl) + .setTokenInfoUrl(tokenInfoUrl) + .setServiceAccountImpersonationUrl(serviceAccountImpersonationUrl) + .setQuotaProjectId(quotaProjectId) + .setClientId(clientId) + .setClientSecret(clientSecret) + .setServiceAccountImpersonationOptions(impersonationOptionsMap) + .setUniverseDomain(universeDomain); + if (awsSecurityCredentialsSupplierClass != null) { + builder.setAwsSecurityCredentialsSupplier( + createAwsSecurityCredentialsSupplierClass(awsSecurityCredentialsSupplierClass)); + } else { + builder.setCredentialSource(new AwsCredentialSource(credentialSourceMap)); + } + return builder.build(); } else if (isPluggableAuthCredential(credentialSourceMap)) { return PluggableAuthCredentials.newBuilder() .setHttpTransportFactory(transportFactory) @@ -467,6 +478,21 @@ static ExternalAccountCredentials fromJson( .build(); } + private static AwsSecurityCredentialsSupplier createAwsSecurityCredentialsSupplierClass( + String awsSecurityCredentialsSupplierClass) { + try { + return (AwsSecurityCredentialsSupplier) + Class.forName(awsSecurityCredentialsSupplierClass).getConstructor().newInstance(); + } catch (ClassNotFoundException + | NoSuchMethodException + | InstantiationException + | IllegalAccessException + | InvocationTargetException e) { + throw new IllegalArgumentException( + "AwsCredentials can not initialize an AwsSecurityCredentialsSupplier", e); + } + } + 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); @@ -570,7 +596,9 @@ public String getServiceAccountImpersonationUrl() { return serviceAccountImpersonationUrl; } - /** @return The service account email to be impersonated, if available */ + /** + * @return The service account email to be impersonated, if available + */ @Nullable public String getServiceAccountEmail() { if (serviceAccountImpersonationUrl == null || serviceAccountImpersonationUrl.isEmpty()) {