auth: GoogleAuthLibraryCallCredentials uses Credentials Builder

This commit is contained in:
Solomon Duskis 2019-04-04 20:41:15 -04:00 committed by Eric Anderson
parent f25fe1fe6a
commit 09d9c4a919
1 changed files with 66 additions and 20 deletions

View File

@ -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<? extends Credentials> serviceAccountClass;
private final Constructor<? extends Credentials> 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<MethodPair> 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<? extends Credentials> 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:
* <ul>
* <li> The Credentials is not a ServiceAccountCredentials</li>
* <li> The ServiceAccountCredentials has scopes</li>
* <li> Something unexpected happens </li>
* </ul>
* @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