From 09d9c4a91959c371d6c6ee9778dff4d3cdb6c457 Mon Sep 17 00:00:00 2001 From: Solomon Duskis Date: Thu, 4 Apr 2019 20:41:15 -0400 Subject: [PATCH] auth: GoogleAuthLibraryCallCredentials uses Credentials Builder --- .../GoogleAuthLibraryCallCredentials.java | 86 ++++++++++++++----- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java b/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java index 125fe5c831..ef8cd38627 100644 --- a/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java +++ b/auth/src/main/java/io/grpc/auth/GoogleAuthLibraryCallCredentials.java @@ -28,12 +28,11 @@ import io.grpc.SecurityLevel; import io.grpc.Status; import io.grpc.StatusException; import java.io.IOException; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; -import java.security.PrivateKey; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -245,31 +244,75 @@ final class GoogleAuthLibraryCallCredentials extends io.grpc.CallCredentials2 { return rawGoogleCredentialsClass.asSubclass(Credentials.class); } + private static class MethodPair { + private final Method getter; + private final Method builderSetter; + + private MethodPair(Method getter, Method builderSetter) { + this.getter = getter; + this.builderSetter = builderSetter; + } + + private void apply(Credentials credentials, Object builder) + throws InvocationTargetException, IllegalAccessException { + builderSetter.invoke(builder, getter.invoke(credentials)); + } + } + @VisibleForTesting static class JwtHelper { private final Class serviceAccountClass; - private final Constructor jwtConstructor; + private final Method newJwtBuilder; + private final Method build; private final Method getScopes; - private final Method getClientId; - private final Method getClientEmail; - private final Method getPrivateKey; - private final Method getPrivateKeyId; + private final List methodPairs; public JwtHelper(Class rawServiceAccountClass, ClassLoader loader) throws ClassNotFoundException, NoSuchMethodException { serviceAccountClass = rawServiceAccountClass.asSubclass(Credentials.class); getScopes = serviceAccountClass.getMethod("getScopes"); - getClientId = serviceAccountClass.getMethod("getClientId"); - getClientEmail = serviceAccountClass.getMethod("getClientEmail"); - getPrivateKey = serviceAccountClass.getMethod("getPrivateKey"); - getPrivateKeyId = serviceAccountClass.getMethod("getPrivateKeyId"); Class jwtClass = Class.forName( "com.google.auth.oauth2.ServiceAccountJwtAccessCredentials", false, loader) .asSubclass(Credentials.class); - jwtConstructor - = jwtClass.getConstructor(String.class, String.class, PrivateKey.class, String.class); + newJwtBuilder = jwtClass.getDeclaredMethod("newBuilder"); + Class builderClass = newJwtBuilder.getReturnType(); + build = builderClass.getMethod("build"); + + methodPairs = new ArrayList<>(); + + { + Method getter = serviceAccountClass.getMethod("getClientId"); + Method setter = builderClass.getMethod("setClientId", getter.getReturnType()); + methodPairs.add(new MethodPair(getter, setter)); + } + { + Method getter = serviceAccountClass.getMethod("getClientEmail"); + Method setter = builderClass.getMethod("setClientEmail", getter.getReturnType()); + methodPairs.add(new MethodPair(getter, setter)); + } + { + Method getter = serviceAccountClass.getMethod("getPrivateKey"); + Method setter = builderClass.getMethod("setPrivateKey", getter.getReturnType()); + methodPairs.add(new MethodPair(getter, setter)); + } + { + Method getter = serviceAccountClass.getMethod("getPrivateKey"); + Method setter = builderClass.getMethod("setPrivateKey", getter.getReturnType()); + methodPairs.add(new MethodPair(getter, setter)); + } } + /** + * This method tries to convert a {@link Credentials} object to a + * ServiceAccountJwtAccessCredentials. The original credentials will be returned if: + * + * @param creds the Credentials to convert + * @return either the original Credentials or a fully formed ServiceAccountJwtAccessCredentials. + */ public Credentials tryServiceAccountToJwt(Credentials creds) { if (!serviceAccountClass.isInstance(creds)) { return creds; @@ -282,17 +325,20 @@ final class GoogleAuthLibraryCallCredentials extends io.grpc.CallCredentials2 { // Leave as-is, since the scopes may limit access within the service. return creds; } - return jwtConstructor.newInstance( - getClientId.invoke(creds), - getClientEmail.invoke(creds), - getPrivateKey.invoke(creds), - getPrivateKeyId.invoke(creds)); + // Create the JWT Credentials Builder + Object builder = newJwtBuilder.invoke(null); + + // Get things from the credentials, and set them on the builder. + for (MethodPair pair : this.methodPairs) { + pair.apply(creds, builder); + } + + // Call builder.build() + return (Credentials) build.invoke(builder); } catch (IllegalAccessException ex) { caughtException = ex; } catch (InvocationTargetException ex) { caughtException = ex; - } catch (InstantiationException ex) { - caughtException = ex; } if (caughtException != null) { // Failure is a bug in this class, but we still choose to gracefully recover