Skip to content

Commit ab8ca97

Browse files
committed
Merge pull request #430 from ajkannan/remove-initializer-dependency
Remove http initializer from AuthCredentials
2 parents 80c7a96 + 942ceb4 commit ab8ca97

File tree

6 files changed

+109
-88
lines changed

6 files changed

+109
-88
lines changed

gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,17 @@
1818

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

21-
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
22-
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
23-
import com.google.api.client.http.HttpRequestInitializer;
24-
import com.google.api.client.http.HttpTransport;
25-
import com.google.api.client.json.jackson.JacksonFactory;
26-
import com.google.auth.http.HttpCredentialsAdapter;
21+
import com.google.auth.oauth2.AccessToken;
2722
import com.google.auth.oauth2.GoogleCredentials;
2823
import com.google.auth.oauth2.ServiceAccountCredentials;
2924

3025
import java.io.IOException;
3126
import java.io.InputStream;
3227
import java.io.Serializable;
28+
import java.lang.reflect.Method;
3329
import java.security.PrivateKey;
30+
import java.util.Collection;
3431
import java.util.Objects;
35-
import java.util.Set;
3632

3733
/**
3834
* Credentials for accessing Google Cloud services.
@@ -42,8 +38,67 @@ public abstract class AuthCredentials implements Restorable<AuthCredentials> {
4238
private static class AppEngineAuthCredentials extends AuthCredentials {
4339

4440
private static final AuthCredentials INSTANCE = new AppEngineAuthCredentials();
45-
private static final AppEngineAuthCredentialsState STATE =
46-
new AppEngineAuthCredentialsState();
41+
private static final AppEngineAuthCredentialsState STATE = new AppEngineAuthCredentialsState();
42+
43+
private static class AppEngineCredentials extends GoogleCredentials {
44+
45+
private final Object appIdentityService;
46+
private final Method getAccessToken;
47+
private final Method getAccessTokenResult;
48+
private final Collection<String> scopes;
49+
50+
AppEngineCredentials() {
51+
try {
52+
Class<?> factoryClass =
53+
Class.forName("com.google.appengine.api.appidentity.AppIdentityServiceFactory");
54+
Method method = factoryClass.getMethod("getAppIdentityService");
55+
this.appIdentityService = method.invoke(null);
56+
Class<?> serviceClass =
57+
Class.forName("com.google.appengine.api.appidentity.AppIdentityService");
58+
Class<?> tokenResultClass = Class.forName(
59+
"com.google.appengine.api.appidentity.AppIdentityService$GetAccessTokenResult");
60+
this.getAccessTokenResult = serviceClass.getMethod("getAccessToken", Iterable.class);
61+
this.getAccessToken = tokenResultClass.getMethod("getAccessToken");
62+
this.scopes = null;
63+
} catch (Exception e) {
64+
throw new RuntimeException("Could not create AppEngineCredentials.", e);
65+
}
66+
}
67+
68+
AppEngineCredentials(Collection<String> scopes, AppEngineCredentials unscoped) {
69+
this.appIdentityService = unscoped.appIdentityService;
70+
this.getAccessToken = unscoped.getAccessToken;
71+
this.getAccessTokenResult = unscoped.getAccessTokenResult;
72+
this.scopes = scopes;
73+
}
74+
75+
/**
76+
* Refresh the access token by getting it from the App Identity service
77+
*/
78+
@Override
79+
public AccessToken refreshAccessToken() throws IOException {
80+
if (createScopedRequired()) {
81+
throw new IOException("AppEngineCredentials requires createScoped call before use.");
82+
}
83+
try {
84+
Object accessTokenResult = getAccessTokenResult.invoke(appIdentityService, scopes);
85+
String accessToken = (String) getAccessToken.invoke(accessTokenResult);
86+
return new AccessToken(accessToken, null);
87+
} catch (Exception e) {
88+
throw new IOException("Could not get the access token.", e);
89+
}
90+
}
91+
92+
@Override
93+
public boolean createScopedRequired() {
94+
return scopes == null || scopes.isEmpty();
95+
}
96+
97+
@Override
98+
public GoogleCredentials createScoped(Collection<String> scopes) {
99+
return new AppEngineCredentials(scopes, this);
100+
}
101+
}
47102

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

69124
@Override
70-
protected HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
71-
Set<String> scopes) {
72-
return new AppIdentityCredential(scopes);
125+
public GoogleCredentials credentials() {
126+
return new AppEngineCredentials();
73127
}
74128

75129
@Override
@@ -83,8 +137,6 @@ public static class ServiceAccountAuthCredentials extends AuthCredentials {
83137
private final String account;
84138
private final PrivateKey privateKey;
85139

86-
private static final AuthCredentials NO_CREDENTIALS = new ServiceAccountAuthCredentials();
87-
88140
private static class ServiceAccountAuthCredentialsState
89141
implements RestorableState<AuthCredentials>, Serializable {
90142

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

101153
@Override
102154
public AuthCredentials restore() {
103-
if (account == null && privateKey == null) {
104-
return NO_CREDENTIALS;
105-
}
106155
return new ServiceAccountAuthCredentials(account, privateKey);
107156
}
108157

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

130-
ServiceAccountAuthCredentials() {
131-
account = null;
132-
privateKey = null;
133-
}
134-
135179
@Override
136-
protected HttpRequestInitializer httpRequestInitializer(
137-
HttpTransport transport, Set<String> scopes) {
138-
GoogleCredential.Builder builder = new GoogleCredential.Builder()
139-
.setTransport(transport)
140-
.setJsonFactory(new JacksonFactory());
141-
if (privateKey != null) {
142-
builder.setServiceAccountPrivateKey(privateKey);
143-
builder.setServiceAccountId(account);
144-
builder.setServiceAccountScopes(scopes);
145-
}
146-
return builder.build();
180+
public ServiceAccountCredentials credentials() {
181+
return new ServiceAccountCredentials(null, account, privateKey, null, null);
147182
}
148183

149184
public String account() {
@@ -198,18 +233,8 @@ public boolean equals(Object obj) {
198233
}
199234

200235
@Override
201-
protected HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
202-
Set<String> scopes) {
203-
return new HttpCredentialsAdapter(googleCredentials.createScoped(scopes));
204-
}
205-
206-
public ServiceAccountAuthCredentials toServiceAccountCredentials() {
207-
if (googleCredentials instanceof ServiceAccountCredentials) {
208-
ServiceAccountCredentials credentials = (ServiceAccountCredentials) googleCredentials;
209-
return new ServiceAccountAuthCredentials(credentials.getClientEmail(),
210-
credentials.getPrivateKey());
211-
}
212-
return null;
236+
public GoogleCredentials credentials() {
237+
return googleCredentials;
213238
}
214239

215240
@Override
@@ -218,8 +243,7 @@ public RestorableState<AuthCredentials> capture() {
218243
}
219244
}
220245

221-
protected abstract HttpRequestInitializer httpRequestInitializer(HttpTransport transport,
222-
Set<String> scopes);
246+
public abstract GoogleCredentials credentials();
223247

224248
public static AuthCredentials createForAppEngine() {
225249
return AppEngineAuthCredentials.INSTANCE;
@@ -271,12 +295,15 @@ public static ServiceAccountAuthCredentials createFor(String account, PrivateKey
271295
*/
272296
public static ServiceAccountAuthCredentials createForJson(InputStream jsonCredentialStream)
273297
throws IOException {
274-
GoogleCredential tempCredentials = GoogleCredential.fromStream(jsonCredentialStream);
275-
return new ServiceAccountAuthCredentials(tempCredentials.getServiceAccountId(),
276-
tempCredentials.getServiceAccountPrivateKey());
277-
}
278-
279-
public static AuthCredentials noCredentials() {
280-
return ServiceAccountAuthCredentials.NO_CREDENTIALS;
298+
GoogleCredentials tempCredentials = GoogleCredentials.fromStream(jsonCredentialStream);
299+
if (tempCredentials instanceof ServiceAccountCredentials) {
300+
ServiceAccountCredentials tempServiceAccountCredentials =
301+
(ServiceAccountCredentials) tempCredentials;
302+
return new ServiceAccountAuthCredentials(
303+
tempServiceAccountCredentials.getClientEmail(),
304+
tempServiceAccountCredentials.getPrivateKey());
305+
}
306+
throw new IOException(
307+
"The given JSON Credentials Stream is not for a service account credential.");
281308
}
282309
}

gcloud-java-core/src/main/java/com/google/gcloud/ServiceOptions.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.google.api.client.http.HttpRequestInitializer;
2626
import com.google.api.client.http.HttpTransport;
2727
import com.google.api.client.http.javanet.NetHttpTransport;
28+
import com.google.auth.http.HttpCredentialsAdapter;
2829
import com.google.common.collect.Iterables;
2930
import com.google.gcloud.spi.ServiceRpcFactory;
3031

@@ -311,8 +312,9 @@ protected ServiceOptions(Class<? extends ServiceFactory<ServiceT, OptionsT>> ser
311312
httpTransportFactory = firstNonNull(builder.httpTransportFactory,
312313
getFromServiceLoader(HttpTransportFactory.class, DefaultHttpTransportFactory.INSTANCE));
313314
httpTransportFactoryClassName = httpTransportFactory.getClass().getName();
314-
authCredentials = firstNonNull(builder.authCredentials, defaultAuthCredentials());
315-
authCredentialsState = authCredentials.capture();
315+
authCredentials =
316+
builder.authCredentials != null ? builder.authCredentials : defaultAuthCredentials();
317+
authCredentialsState = authCredentials != null ? authCredentials.capture() : null;
316318
retryParams = builder.retryParams;
317319
serviceFactory = firstNonNull(builder.serviceFactory,
318320
getFromServiceLoader(serviceFactoryClass, defaultServiceFactory()));
@@ -348,7 +350,7 @@ private static AuthCredentials defaultAuthCredentials() {
348350
try {
349351
return AuthCredentials.createApplicationDefaults();
350352
} catch (Exception ex) {
351-
return AuthCredentials.noCredentials();
353+
return null;
352354
}
353355
}
354356

@@ -508,13 +510,15 @@ public RetryParams retryParams() {
508510
* options.
509511
*/
510512
public HttpRequestInitializer httpRequestInitializer() {
511-
HttpTransport httpTransport = httpTransportFactory.create();
512-
final HttpRequestInitializer baseRequestInitializer =
513-
authCredentials().httpRequestInitializer(httpTransport, scopes());
513+
final HttpRequestInitializer delegate = authCredentials() != null
514+
? new HttpCredentialsAdapter(authCredentials().credentials().createScoped(scopes()))
515+
: null;
514516
return new HttpRequestInitializer() {
515517
@Override
516518
public void initialize(HttpRequest httpRequest) throws IOException {
517-
baseRequestInitializer.initialize(httpRequest);
519+
if (delegate != null) {
520+
delegate.initialize(httpRequest);
521+
}
518522
if (connectTimeout >= 0) {
519523
httpRequest.setConnectTimeout(connectTimeout);
520524
}
@@ -580,7 +584,7 @@ private void readObject(ObjectInputStream input) throws IOException, ClassNotFou
580584
httpTransportFactory = newInstance(httpTransportFactoryClassName);
581585
serviceFactory = newInstance(serviceFactoryClassName);
582586
serviceRpcFactory = newInstance(serviceRpcFactoryClassName);
583-
authCredentials = authCredentialsState.restore();
587+
authCredentials = authCredentialsState != null ? authCredentialsState.restore() : null;
584588
}
585589

586590
private static <T> T newInstance(String className) throws IOException, ClassNotFoundException {

gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/SerializationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public void testServiceOptions() throws Exception {
144144
options = options.toBuilder()
145145
.namespace("ns1")
146146
.retryParams(RetryParams.defaultInstance())
147-
.authCredentials(AuthCredentials.noCredentials())
147+
.authCredentials(null)
148148
.force(true)
149149
.build();
150150
serializedCopy = serializeAndDeserialize(options);

gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,24 @@
3131
import static java.nio.charset.StandardCharsets.UTF_8;
3232

3333
import com.google.api.services.storage.model.StorageObject;
34+
import com.google.auth.oauth2.ServiceAccountCredentials;
3435
import com.google.common.base.Function;
3536
import com.google.common.base.Functions;
3637
import com.google.common.collect.ImmutableList;
3738
import com.google.common.collect.ImmutableMap;
3839
import com.google.common.collect.Iterables;
3940
import com.google.common.collect.Lists;
4041
import com.google.common.collect.Maps;
41-
import com.google.common.collect.Sets;
4242
import com.google.common.hash.Hashing;
4343
import com.google.common.io.BaseEncoding;
4444
import com.google.common.primitives.Ints;
45-
import com.google.gcloud.AuthCredentials;
46-
import com.google.gcloud.AuthCredentials.ApplicationDefaultAuthCredentials;
4745
import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials;
48-
import com.google.gcloud.PageImpl;
4946
import com.google.gcloud.BaseService;
5047
import com.google.gcloud.ExceptionHandler;
5148
import com.google.gcloud.ExceptionHandler.Interceptor;
52-
import com.google.gcloud.RetryHelper.RetryHelperException;
5349
import com.google.gcloud.Page;
50+
import com.google.gcloud.PageImpl;
51+
import com.google.gcloud.RetryHelper.RetryHelperException;
5452
import com.google.gcloud.spi.StorageRpc;
5553
import com.google.gcloud.spi.StorageRpc.RewriteResponse;
5654
import com.google.gcloud.spi.StorageRpc.Tuple;
@@ -71,7 +69,6 @@
7169
import java.util.EnumMap;
7270
import java.util.List;
7371
import java.util.Map;
74-
import java.util.Set;
7572
import java.util.concurrent.Callable;
7673
import java.util.concurrent.TimeUnit;
7774

@@ -563,18 +560,15 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio
563560
for (SignUrlOption option : options) {
564561
optionMap.put(option.option(), option.value());
565562
}
566-
ServiceAccountAuthCredentials cred =
563+
ServiceAccountAuthCredentials authCred =
567564
(ServiceAccountAuthCredentials) optionMap.get(SignUrlOption.Option.SERVICE_ACCOUNT_CRED);
568-
if (cred == null) {
569-
AuthCredentials serviceCred = this.options().authCredentials();
570-
if (serviceCred instanceof ServiceAccountAuthCredentials) {
571-
cred = (ServiceAccountAuthCredentials) serviceCred;
572-
} else {
573-
if (serviceCred instanceof ApplicationDefaultAuthCredentials) {
574-
cred = ((ApplicationDefaultAuthCredentials) serviceCred).toServiceAccountCredentials();
575-
}
576-
}
577-
checkArgument(cred != null, "Signing key was not provided and could not be derived");
565+
ServiceAccountCredentials cred = authCred != null ? authCred.credentials() : null;
566+
if (authCred == null) {
567+
checkArgument(
568+
this.options().authCredentials() != null
569+
&& this.options().authCredentials().credentials() instanceof ServiceAccountCredentials,
570+
"Signing key was not provided and could not be derived");
571+
cred = (ServiceAccountCredentials) this.options().authCredentials().credentials();
578572
}
579573
// construct signature - see https://cloud.google.com/storage/docs/access-control#Signed-URLs
580574
StringBuilder stBuilder = new StringBuilder();
@@ -610,12 +604,12 @@ public URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOptio
610604
stBuilder.append(path);
611605
try {
612606
Signature signer = Signature.getInstance("SHA256withRSA");
613-
signer.initSign(cred.privateKey());
607+
signer.initSign(cred.getPrivateKey());
614608
signer.update(stBuilder.toString().getBytes(UTF_8));
615609
String signature =
616610
URLEncoder.encode(BaseEncoding.base64().encode(signer.sign()), UTF_8.name());
617611
stBuilder = new StringBuilder("https://storage.googleapis.com").append(path);
618-
stBuilder.append("?GoogleAccessId=").append(cred.account());
612+
stBuilder.append("?GoogleAccessId=").append(cred.getClientEmail());
619613
stBuilder.append("&Expires=").append(expiration);
620614
stBuilder.append("&Signature=").append(signature);
621615
return new URL(stBuilder.toString());

gcloud-java-storage/src/test/java/com/google/gcloud/storage/SerializationTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public void testServiceOptions() throws Exception {
8383
options = options.toBuilder()
8484
.projectId("p2")
8585
.retryParams(RetryParams.defaultInstance())
86-
.authCredentials(AuthCredentials.noCredentials())
86+
.authCredentials(null)
8787
.pathDelimiter(":")
8888
.build();
8989
serializedCopy = serializeAndDeserialize(options);
@@ -111,7 +111,6 @@ public void testReadChannelState() throws IOException, ClassNotFoundException {
111111
StorageOptions options = StorageOptions.builder()
112112
.projectId("p2")
113113
.retryParams(RetryParams.defaultInstance())
114-
.authCredentials(AuthCredentials.noCredentials())
115114
.build();
116115
BlobReadChannel reader =
117116
new BlobReadChannelImpl(options, BlobId.of("b", "n"), EMPTY_RPC_OPTIONS);
@@ -127,7 +126,6 @@ public void testWriteChannelState() throws IOException, ClassNotFoundException {
127126
StorageOptions options = StorageOptions.builder()
128127
.projectId("p2")
129128
.retryParams(RetryParams.defaultInstance())
130-
.authCredentials(AuthCredentials.noCredentials())
131129
.build();
132130
BlobWriteChannelImpl writer = new BlobWriteChannelImpl(
133131
options, BlobInfo.builder(BlobId.of("b", "n")).build(), "upload-id");

gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@
3131
import com.google.common.collect.Iterables;
3232
import com.google.common.collect.Maps;
3333
import com.google.common.io.BaseEncoding;
34-
import com.google.gcloud.AuthCredentials;
3534
import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials;
35+
import com.google.gcloud.Page;
3636
import com.google.gcloud.RetryParams;
3737
import com.google.gcloud.ServiceOptions;
38-
import com.google.gcloud.Page;
3938
import com.google.gcloud.spi.StorageRpc;
4039
import com.google.gcloud.spi.StorageRpc.Tuple;
4140
import com.google.gcloud.spi.StorageRpcFactory;
@@ -260,7 +259,6 @@ public void setUp() throws IOException, InterruptedException {
260259
EasyMock.replay(rpcFactoryMock);
261260
options = StorageOptions.builder()
262261
.projectId("projectId")
263-
.authCredentials(AuthCredentials.noCredentials())
264262
.clock(TIME_SOURCE)
265263
.serviceRpcFactory(rpcFactoryMock)
266264
.build();

0 commit comments

Comments
 (0)