Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove http initializer from AuthCredentials #430

Merged
merged 6 commits into from
Dec 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 81 additions & 54 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,67 @@ public abstract class AuthCredentials implements Restorable<AuthCredentials> {
private static class AppEngineAuthCredentials extends AuthCredentials {

private static final AuthCredentials INSTANCE = new AppEngineAuthCredentials();

This comment was marked as spam.

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 Method getAccessToken;
private final Method getAccessTokenResult;
private final Collection<String> scopes;

AppEngineCredentials() {
try {
Class<?> factoryClass =
Class.forName("com.google.appengine.api.appidentity.AppIdentityServiceFactory");

This comment was marked as spam.

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;
} catch (Exception e) {
throw new RuntimeException("Could not create AppEngineCredentials.", e);
}
}

AppEngineCredentials(Collection<String> scopes, AppEngineCredentials unscoped) {
this.appIdentityService = unscoped.appIdentityService;
this.getAccessToken = unscoped.getAccessToken;
this.getAccessTokenResult = unscoped.getAccessTokenResult;
this.scopes = scopes;
}

/**
* 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 {
Object accessTokenResult = getAccessTokenResult.invoke(appIdentityService, scopes);
String accessToken = (String) getAccessToken.invoke(accessTokenResult);
return new AccessToken(accessToken, null);
} catch (Exception e) {
throw new IOException("Could not get the access token.", e);
}
}

@Override
public boolean createScopedRequired() {
return scopes == null || scopes.isEmpty();
}

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

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

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

@Override
Expand All @@ -83,8 +137,6 @@ public static class ServiceAccountAuthCredentials extends AuthCredentials {
private final String account;
private final PrivateKey privateKey;

private static final AuthCredentials NO_CREDENTIALS = new ServiceAccountAuthCredentials();

private static class ServiceAccountAuthCredentialsState
implements RestorableState<AuthCredentials>, Serializable {

Expand All @@ -100,9 +152,6 @@ private ServiceAccountAuthCredentialsState(String account, PrivateKey privateKey

@Override
public AuthCredentials restore() {
if (account == null && privateKey == null) {
return NO_CREDENTIALS;
}
return new ServiceAccountAuthCredentials(account, privateKey);
}

Expand All @@ -127,23 +176,9 @@ public boolean equals(Object obj) {
this.privateKey = checkNotNull(privateKey);
}

ServiceAccountAuthCredentials() {
account = null;
privateKey = null;
}

@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();
public ServiceAccountCredentials credentials() {
return new ServiceAccountCredentials(null, account, privateKey, null, null);
}

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

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

public ServiceAccountAuthCredentials toServiceAccountCredentials() {
if (googleCredentials instanceof ServiceAccountCredentials) {
ServiceAccountCredentials credentials = (ServiceAccountCredentials) googleCredentials;
return new ServiceAccountAuthCredentials(credentials.getClientEmail(),
credentials.getPrivateKey());
}
return null;
public GoogleCredentials credentials() {
return googleCredentials;
}

@Override
Expand All @@ -218,8 +243,7 @@ public RestorableState<AuthCredentials> capture() {
}
}

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

public static AuthCredentials createForAppEngine() {
return AppEngineAuthCredentials.INSTANCE;
Expand Down Expand Up @@ -271,12 +295,15 @@ 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());
}

public static AuthCredentials noCredentials() {
return ServiceAccountAuthCredentials.NO_CREDENTIALS;
GoogleCredentials tempCredentials = GoogleCredentials.fromStream(jsonCredentialStream);

This comment was marked as spam.

if (tempCredentials instanceof ServiceAccountCredentials) {
ServiceAccountCredentials tempServiceAccountCredentials =
(ServiceAccountCredentials) tempCredentials;
return new ServiceAccountAuthCredentials(
tempServiceAccountCredentials.getClientEmail(),
tempServiceAccountCredentials.getPrivateKey());
}
throw new IOException(
"The given JSON Credentials Stream is not for a service account credential.");
}
}
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 @@ -311,8 +312,9 @@ protected ServiceOptions(Class<? extends ServiceFactory<ServiceT, OptionsT>> ser
httpTransportFactory = firstNonNull(builder.httpTransportFactory,
getFromServiceLoader(HttpTransportFactory.class, DefaultHttpTransportFactory.INSTANCE));
httpTransportFactoryClassName = httpTransportFactory.getClass().getName();
authCredentials = firstNonNull(builder.authCredentials, defaultAuthCredentials());
authCredentialsState = authCredentials.capture();
authCredentials =
builder.authCredentials != null ? builder.authCredentials : defaultAuthCredentials();
authCredentialsState = authCredentials != null ? authCredentials.capture() : null;
retryParams = builder.retryParams;
serviceFactory = firstNonNull(builder.serviceFactory,
getFromServiceLoader(serviceFactoryClass, defaultServiceFactory()));
Expand Down Expand Up @@ -348,7 +350,7 @@ private static AuthCredentials defaultAuthCredentials() {
try {
return AuthCredentials.createApplicationDefaults();
} catch (Exception ex) {
return AuthCredentials.noCredentials();
return null;
}
}

Expand Down Expand Up @@ -508,13 +510,15 @@ public RetryParams retryParams() {
* options.
*/
public HttpRequestInitializer httpRequestInitializer() {
HttpTransport httpTransport = httpTransportFactory.create();
final HttpRequestInitializer baseRequestInitializer =
authCredentials().httpRequestInitializer(httpTransport, scopes());
final HttpRequestInitializer delegate = authCredentials() != null
? new HttpCredentialsAdapter(authCredentials().credentials().createScoped(scopes()))
: null;
return new HttpRequestInitializer() {
@Override
public void initialize(HttpRequest httpRequest) throws IOException {
baseRequestInitializer.initialize(httpRequest);
if (delegate != null) {
delegate.initialize(httpRequest);
}
if (connectTimeout >= 0) {
httpRequest.setConnectTimeout(connectTimeout);
}
Expand Down Expand Up @@ -580,7 +584,7 @@ private void readObject(ObjectInputStream input) throws IOException, ClassNotFou
httpTransportFactory = newInstance(httpTransportFactoryClassName);
serviceFactory = newInstance(serviceFactoryClassName);
serviceRpcFactory = newInstance(serviceRpcFactoryClassName);
authCredentials = authCredentialsState.restore();
authCredentials = authCredentialsState != null ? authCredentialsState.restore() : null;
}

private static <T> T newInstance(String className) throws IOException, ClassNotFoundException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public void testServiceOptions() throws Exception {
options = options.toBuilder()
.namespace("ns1")
.retryParams(RetryParams.defaultInstance())
.authCredentials(AuthCredentials.noCredentials())
.authCredentials(null)
.force(true)
.build();
serializedCopy = serializeAndDeserialize(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,24 @@
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.api.services.storage.model.StorageObject;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
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;
Expand All @@ -71,7 +69,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;

Expand Down Expand Up @@ -563,18 +560,15 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio
for (SignUrlOption option : options) {
optionMap.put(option.option(), option.value());
}
ServiceAccountAuthCredentials cred =
ServiceAccountAuthCredentials authCred =
(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");
ServiceAccountCredentials cred = authCred != null ? authCred.credentials() : null;
if (authCred == null) {
checkArgument(
this.options().authCredentials() != null
&& this.options().authCredentials().credentials() instanceof ServiceAccountCredentials,
"Signing key was not provided and could not be derived");
cred = (ServiceAccountCredentials) this.options().authCredentials().credentials();
}
// construct signature - see https://cloud.google.com/storage/docs/access-control#Signed-URLs
StringBuilder stBuilder = new StringBuilder();
Expand Down Expand Up @@ -610,12 +604,12 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio
stBuilder.append(path);
try {
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initSign(cred.privateKey());
signer.initSign(cred.getPrivateKey());
signer.update(stBuilder.toString().getBytes(UTF_8));
String signature =
URLEncoder.encode(BaseEncoding.base64().encode(signer.sign()), UTF_8.name());
stBuilder = new StringBuilder("https://storage.googleapis.com").append(path);
stBuilder.append("?GoogleAccessId=").append(cred.account());
stBuilder.append("?GoogleAccessId=").append(cred.getClientEmail());
stBuilder.append("&Expires=").append(expiration);
stBuilder.append("&Signature=").append(signature);
return new URL(stBuilder.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void testServiceOptions() throws Exception {
options = options.toBuilder()
.projectId("p2")
.retryParams(RetryParams.defaultInstance())
.authCredentials(AuthCredentials.noCredentials())
.authCredentials(null)
.pathDelimiter(":")
.build();
serializedCopy = serializeAndDeserialize(options);
Expand Down Expand Up @@ -111,7 +111,6 @@ public void testReadChannelState() throws IOException, ClassNotFoundException {
StorageOptions options = StorageOptions.builder()
.projectId("p2")
.retryParams(RetryParams.defaultInstance())
.authCredentials(AuthCredentials.noCredentials())
.build();
BlobReadChannel reader =
new BlobReadChannelImpl(options, BlobId.of("b", "n"), EMPTY_RPC_OPTIONS);
Expand All @@ -127,7 +126,6 @@ public void testWriteChannelState() throws IOException, ClassNotFoundException {
StorageOptions options = StorageOptions.builder()
.projectId("p2")
.retryParams(RetryParams.defaultInstance())
.authCredentials(AuthCredentials.noCredentials())
.build();
BlobWriteChannelImpl writer = new BlobWriteChannelImpl(
options, BlobInfo.builder(BlobId.of("b", "n")).build(), "upload-id");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.io.BaseEncoding;
import com.google.gcloud.AuthCredentials;
import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials;
import com.google.gcloud.Page;
import com.google.gcloud.RetryParams;
import com.google.gcloud.ServiceOptions;
import com.google.gcloud.Page;
import com.google.gcloud.spi.StorageRpc;
import com.google.gcloud.spi.StorageRpc.Tuple;
import com.google.gcloud.spi.StorageRpcFactory;
Expand Down Expand Up @@ -260,7 +259,6 @@ public void setUp() throws IOException, InterruptedException {
EasyMock.replay(rpcFactoryMock);
options = StorageOptions.builder()
.projectId("projectId")
.authCredentials(AuthCredentials.noCredentials())
.clock(TIME_SOURCE)
.serviceRpcFactory(rpcFactoryMock)
.build();
Expand Down