Skip to content

Commit

Permalink
Remove dependency on http initializer in AuthCredentials and remove d…
Browse files Browse the repository at this point in the history
…ependency on com.google.api.client.googleapis.auth.oauth2.GoogleCredential
  • Loading branch information
Ajay Kannan committed Dec 1, 2015
1 parent 80c7a96 commit 7b1373d
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 33 deletions.
113 changes: 82 additions & 31 deletions gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,17 @@

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

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.security.PrivateKey;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;

/**
* Credentials for accessing Google Cloud services.
Expand All @@ -42,8 +38,66 @@ public abstract class AuthCredentials implements Restorable<AuthCredentials> {
private static class AppEngineAuthCredentials extends AuthCredentials {

private static final AuthCredentials INSTANCE = new AppEngineAuthCredentials();
private static final AppEngineAuthCredentialsState STATE =
new AppEngineAuthCredentialsState();
private static final AppEngineAuthCredentialsState STATE = new AppEngineAuthCredentialsState();

private static class AppEngineCredentials extends GoogleCredentials {

private final Object appIdentityService;
private final Collection<String> scopes;
private final boolean scopesRequired;

AppEngineCredentials() {
try {
Class<?> factoryClass =
Class.forName("com.google.appengine.api.appidentity.AppIdentityServiceFactory");
Method method = factoryClass.getMethod("getAppIdentityService");
this.appIdentityService = method.invoke(null);
this.scopes = null;
this.scopesRequired = true;
} catch (Exception e) {
throw new RuntimeException("Could not create AppEngineCredentials using reflection.");
}
}

AppEngineCredentials(Collection<String> scopes, Object appIdentityService) {
this.appIdentityService = appIdentityService;
this.scopes = scopes;
this.scopesRequired = (scopes == null || scopes.isEmpty());
}

/**
* Refresh the access token by getting it from the App Identity service
*/
@Override
public AccessToken refreshAccessToken() throws IOException {
if (createScopedRequired()) {
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) {
throw new RuntimeException("Could not get the access token using reflection.");
}
}

@Override
public boolean createScopedRequired() {
return scopesRequired;
}

@Override
public GoogleCredentials createScoped(Collection<String> scopes) {
return new AppEngineCredentials(scopes, appIdentityService);
}
}

private static class AppEngineAuthCredentialsState
implements RestorableState<AuthCredentials>, Serializable {
Expand All @@ -67,9 +121,8 @@ public boolean equals(Object obj) {
}

@Override
protected HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
Set<String> scopes) {
return new AppIdentityCredential(scopes);
protected GoogleCredentials credentials() {
return new AppEngineCredentials();
}

@Override
Expand Down Expand Up @@ -133,17 +186,9 @@ public boolean equals(Object obj) {
}

@Override
protected HttpRequestInitializer httpRequestInitializer(
HttpTransport transport, Set<String> scopes) {
GoogleCredential.Builder builder = new GoogleCredential.Builder()
.setTransport(transport)
.setJsonFactory(new JacksonFactory());
if (privateKey != null) {
builder.setServiceAccountPrivateKey(privateKey);
builder.setServiceAccountId(account);
builder.setServiceAccountScopes(scopes);
}
return builder.build();
protected GoogleCredentials credentials() {
return (privateKey == null)
? null : new ServiceAccountCredentials(null, account, privateKey, null, null);
}

public String account() {
Expand Down Expand Up @@ -198,9 +243,8 @@ public boolean equals(Object obj) {
}

@Override
protected HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
Set<String> scopes) {
return new HttpCredentialsAdapter(googleCredentials.createScoped(scopes));
protected GoogleCredentials credentials() {
return googleCredentials;
}

public ServiceAccountAuthCredentials toServiceAccountCredentials() {
Expand All @@ -218,8 +262,7 @@ public RestorableState<AuthCredentials> capture() {
}
}

protected abstract HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
Set<String> scopes);
protected abstract GoogleCredentials credentials();

public static AuthCredentials createForAppEngine() {
return AppEngineAuthCredentials.INSTANCE;
Expand Down Expand Up @@ -271,9 +314,17 @@ public static ServiceAccountAuthCredentials createFor(String account, PrivateKey
*/
public static ServiceAccountAuthCredentials createForJson(InputStream jsonCredentialStream)
throws IOException {
GoogleCredential tempCredentials = GoogleCredential.fromStream(jsonCredentialStream);
return new ServiceAccountAuthCredentials(tempCredentials.getServiceAccountId(),
tempCredentials.getServiceAccountPrivateKey());
GoogleCredentials tempCredentials = GoogleCredentials.fromStream(jsonCredentialStream);
if (tempCredentials instanceof ServiceAccountCredentials) {
ServiceAccountCredentials tempServiceAccountCredentials =
(ServiceAccountCredentials) tempCredentials;
return new ServiceAccountAuthCredentials(
tempServiceAccountCredentials.getClientEmail(),
tempServiceAccountCredentials.getPrivateKey());
} else {
throw new IOException(
"The given JSON Credentials Stream is not a service account credential.");
}
}

public static AuthCredentials noCredentials() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.common.collect.Iterables;
import com.google.gcloud.spi.ServiceRpcFactory;

Expand Down Expand Up @@ -508,9 +509,8 @@ public RetryParams retryParams() {
* options.
*/
public HttpRequestInitializer httpRequestInitializer() {
HttpTransport httpTransport = httpTransportFactory.create();
final HttpRequestInitializer baseRequestInitializer =
authCredentials().httpRequestInitializer(httpTransport, scopes());
new HttpCredentialsAdapter(authCredentials().credentials().createScoped(scopes()));
return new HttpRequestInitializer() {
@Override
public void initialize(HttpRequest httpRequest) throws IOException {
Expand Down

0 comments on commit 7b1373d

Please sign in to comment.