From a6bfd48724b44f9d36b9c82ad4fa26cff5f88c74 Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Tue, 1 Dec 2015 14:07:31 -0800 Subject: [PATCH] Make AppEngineAuthCredentials Restorable --- .../com/google/gcloud/AuthCredentials.java | 71 ++++++++++++------- .../google/gcloud/storage/StorageImpl.java | 25 +++---- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java b/gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java index 9aaee77ea243..1a2b0fcfd674 100644 --- a/gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java +++ b/gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java @@ -21,6 +21,7 @@ import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; +import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.io.InputStream; @@ -37,12 +38,14 @@ public abstract class AuthCredentials implements Restorable { private static class AppEngineAuthCredentials extends AuthCredentials { - private static final AuthCredentials INSTANCE = new AppEngineAuthCredentials(); - private static final AppEngineAuthCredentialsState STATE = new AppEngineAuthCredentialsState(); + private final Collection scopes; + private final boolean scopesRequired; private static class AppEngineCredentials extends GoogleCredentials { private final Object appIdentityService; + private final Method getAccessToken; + private final Method getAccessTokenResult; private final Collection scopes; private final boolean scopesRequired; @@ -52,6 +55,12 @@ private static class AppEngineCredentials extends GoogleCredentials { Class.forName("com.google.appengine.api.appidentity.AppIdentityServiceFactory"); Method method = factoryClass.getMethod("getAppIdentityService"); this.appIdentityService = method.invoke(null); + Class serviceClass = + Class.forName("com.google.appengine.api.appidentity.AppIdentityService"); + Class tokenResultClass = Class.forName( + "com.google.appengine.api.appidentity.AppIdentityService$GetAccessTokenResult"); + this.getAccessTokenResult = serviceClass.getMethod("getAccessToken", Iterable.class); + this.getAccessToken = tokenResultClass.getMethod("getAccessToken"); this.scopes = null; this.scopesRequired = true; } catch (Exception e) { @@ -59,10 +68,13 @@ private static class AppEngineCredentials extends GoogleCredentials { } } - AppEngineCredentials(Collection scopes, Object appIdentityService) { - this.appIdentityService = appIdentityService; - this.scopes = scopes; - this.scopesRequired = (scopes == null || scopes.isEmpty()); + AppEngineCredentials(Collection scopes, Object appIdentityService, + Method getAccessToken, Method getAccessTokenResult) { + this.appIdentityService = appIdentityService; + this.getAccessToken = getAccessToken; + this.getAccessTokenResult = getAccessTokenResult; + this.scopes = scopes; + this.scopesRequired = (scopes == null || scopes.isEmpty()); } /** @@ -74,13 +86,7 @@ public AccessToken refreshAccessToken() throws IOException { throw new IOException("AppEngineCredentials requires createScoped call before use."); } try { - Class serviceClass = - Class.forName("com.google.appengine.api.appidentity.AppIdentityService"); - Class tokenResultClass = Class.forName( - "com.google.appengine.api.appidentity.AppIdentityService$GetAccessTokenResult"); - Method getAccessTokenResult = serviceClass.getMethod("getAccessToken", Iterable.class); Object accessTokenResult = getAccessTokenResult.invoke(appIdentityService, scopes); - Method getAccessToken = tokenResultClass.getMethod("getAccessToken"); String accessToken = (String) getAccessToken.invoke(accessTokenResult); return new AccessToken(accessToken, null); } catch (Exception e) { @@ -95,7 +101,8 @@ public boolean createScopedRequired() { @Override public GoogleCredentials createScoped(Collection scopes) { - return new AppEngineCredentials(scopes, appIdentityService); + return new AppEngineCredentials( + scopes, appIdentityService, getAccessToken, getAccessTokenResult); } } @@ -104,9 +111,17 @@ private static class AppEngineAuthCredentialsState private static final long serialVersionUID = 3558563960848658928L; + private final boolean scopesRequired; + private final Collection scopes; + + private AppEngineAuthCredentialsState(Collection scopes, boolean scopesRequired) { + this.scopes = scopes; + this.scopesRequired = scopesRequired; + } + @Override public AuthCredentials restore() { - return INSTANCE; + return new AppEngineAuthCredentials(scopes, scopesRequired); } @Override @@ -120,14 +135,19 @@ public boolean equals(Object obj) { } } + AppEngineAuthCredentials(Collection scopes, boolean scopesRequired) { + this.scopes = scopes != null ? ImmutableSet.copyOf(checkNotNull(scopes)) : null; + this.scopesRequired = scopesRequired; + } + @Override - protected GoogleCredentials credentials() { + public GoogleCredentials credentials() { return new AppEngineCredentials(); } @Override public RestorableState capture() { - return STATE; + return new AppEngineAuthCredentialsState(scopes, scopesRequired); } } @@ -176,7 +196,7 @@ public boolean equals(Object obj) { } @Override - protected GoogleCredentials credentials() { + public GoogleCredentials credentials() { return new ServiceAccountCredentials(null, account, privateKey, null, null); } @@ -232,7 +252,7 @@ public boolean equals(Object obj) { } @Override - protected GoogleCredentials credentials() { + public GoogleCredentials credentials() { return googleCredentials; } @@ -251,10 +271,10 @@ public RestorableState capture() { } } - protected abstract GoogleCredentials credentials(); + public abstract GoogleCredentials credentials(); public static AuthCredentials createForAppEngine() { - return AppEngineAuthCredentials.INSTANCE; + return new AppEngineAuthCredentials(null, true); } /** @@ -297,11 +317,12 @@ public static ServiceAccountAuthCredentials createFor(String account, PrivateKey * Account Authentication. *

* - * @param jsonCredentialStream stream for Service Account Credentials in JSON format + * @param jsonCredentialStream stream for Service Account Credentials or User Credentials in JSON + * format * @return the credentials instance. * @throws IOException if the credentials cannot be created from the stream. */ - public static ServiceAccountAuthCredentials createForJson(InputStream jsonCredentialStream) + public static AuthCredentials createForJson(InputStream jsonCredentialStream) throws IOException { GoogleCredentials tempCredentials = GoogleCredentials.fromStream(jsonCredentialStream); if (tempCredentials instanceof ServiceAccountCredentials) { @@ -310,9 +331,9 @@ public static ServiceAccountAuthCredentials createForJson(InputStream jsonCreden return new ServiceAccountAuthCredentials( tempServiceAccountCredentials.getClientEmail(), tempServiceAccountCredentials.getPrivateKey()); - } else { - throw new IOException( - "The given JSON Credentials Stream is not a service account credential."); } + throw new IOException( + "The given JSON credentials stream could not be parsed as service account credentials or" + + " user credentials."); } } diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java index 91a408657847..fdb643c725ac 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java @@ -31,6 +31,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; import com.google.api.services.storage.model.StorageObject; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.collect.ImmutableList; @@ -38,19 +40,17 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.google.common.hash.Hashing; import com.google.common.io.BaseEncoding; import com.google.common.primitives.Ints; import com.google.gcloud.AuthCredentials; -import com.google.gcloud.AuthCredentials.ApplicationDefaultAuthCredentials; import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials; -import com.google.gcloud.PageImpl; import com.google.gcloud.BaseService; import com.google.gcloud.ExceptionHandler; import com.google.gcloud.ExceptionHandler.Interceptor; -import com.google.gcloud.RetryHelper.RetryHelperException; import com.google.gcloud.Page; +import com.google.gcloud.PageImpl; +import com.google.gcloud.RetryHelper.RetryHelperException; import com.google.gcloud.spi.StorageRpc; import com.google.gcloud.spi.StorageRpc.RewriteResponse; import com.google.gcloud.spi.StorageRpc.Tuple; @@ -71,7 +71,6 @@ import java.util.EnumMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -566,15 +565,13 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio ServiceAccountAuthCredentials cred = (ServiceAccountAuthCredentials) optionMap.get(SignUrlOption.Option.SERVICE_ACCOUNT_CRED); if (cred == null) { - AuthCredentials serviceCred = this.options().authCredentials(); - if (serviceCred instanceof ServiceAccountAuthCredentials) { - cred = (ServiceAccountAuthCredentials) serviceCred; - } else { - if (serviceCred instanceof ApplicationDefaultAuthCredentials) { - cred = ((ApplicationDefaultAuthCredentials) serviceCred).toServiceAccountCredentials(); - } - } - checkArgument(cred != null, "Signing key was not provided and could not be derived"); + AuthCredentials authCredentials = this.options().authCredentials(); + GoogleCredentials serviceCred = + authCredentials != null ? authCredentials.credentials() : null; + checkArgument( + serviceCred instanceof ServiceAccountCredentials, + "Signing key was not provided and could not be derived"); + cred = (ServiceAccountAuthCredentials) authCredentials; } // construct signature - see https://cloud.google.com/storage/docs/access-control#Signed-URLs StringBuilder stBuilder = new StringBuilder();