25
25
import java .io .IOException ;
26
26
import java .io .InputStream ;
27
27
import java .io .Serializable ;
28
+ import java .lang .reflect .InvocationTargetException ;
28
29
import java .lang .reflect .Method ;
30
+ import java .security .InvalidKeyException ;
31
+ import java .security .NoSuchAlgorithmException ;
29
32
import java .security .PrivateKey ;
33
+ import java .security .Signature ;
34
+ import java .security .SignatureException ;
30
35
import java .util .Collection ;
31
36
import java .util .Objects ;
32
37
35
40
*/
36
41
public abstract class AuthCredentials implements Restorable <AuthCredentials > {
37
42
38
- private static class AppEngineAuthCredentials extends AuthCredentials {
43
+ /**
44
+ * Represents built-in credentials when running in Google App Engine.
45
+ */
46
+ public static class AppEngineAuthCredentials extends AuthCredentials
47
+ implements ServiceAccountSigner {
39
48
40
49
private static final AuthCredentials INSTANCE = new AppEngineAuthCredentials ();
41
50
private static final AppEngineAuthCredentialsState STATE = new AppEngineAuthCredentialsState ();
42
51
43
- private static class AppEngineCredentials extends GoogleCredentials {
52
+ private AppEngineCredentials credentials ;
53
+
54
+ private static class AppEngineCredentials extends GoogleCredentials
55
+ implements ServiceAccountSigner {
44
56
45
57
private final Object appIdentityService ;
58
+ private final String account ;
46
59
private final Method getAccessToken ;
47
60
private final Method getAccessTokenResult ;
61
+ private final Method signForApp ;
62
+ private final Method getSignature ;
48
63
private final Collection <String > scopes ;
49
64
50
65
AppEngineCredentials () {
@@ -59,6 +74,12 @@ private static class AppEngineCredentials extends GoogleCredentials {
59
74
"com.google.appengine.api.appidentity.AppIdentityService$GetAccessTokenResult" );
60
75
this .getAccessTokenResult = serviceClass .getMethod ("getAccessToken" , Iterable .class );
61
76
this .getAccessToken = tokenResultClass .getMethod ("getAccessToken" );
77
+ this .account = (String ) serviceClass .getMethod ("getServiceAccountName" )
78
+ .invoke (appIdentityService );
79
+ this .signForApp = serviceClass .getMethod ("signForApp" , byte [].class );
80
+ Class <?> signingResultClass = Class .forName (
81
+ "com.google.appengine.api.appidentity.AppIdentityService$SigningResult" );
82
+ this .getSignature = signingResultClass .getMethod ("getSignature" );
62
83
this .scopes = null ;
63
84
} catch (Exception e ) {
64
85
throw new RuntimeException ("Could not create AppEngineCredentials." , e );
@@ -69,11 +90,14 @@ private static class AppEngineCredentials extends GoogleCredentials {
69
90
this .appIdentityService = unscoped .appIdentityService ;
70
91
this .getAccessToken = unscoped .getAccessToken ;
71
92
this .getAccessTokenResult = unscoped .getAccessTokenResult ;
93
+ this .account = unscoped .account ;
94
+ this .signForApp = unscoped .signForApp ;
95
+ this .getSignature = unscoped .getSignature ;
72
96
this .scopes = scopes ;
73
97
}
74
98
75
99
/**
76
- * Refresh the access token by getting it from the App Identity service
100
+ * Refresh the access token by getting it from the App Identity service.
77
101
*/
78
102
@ Override
79
103
public AccessToken refreshAccessToken () throws IOException {
@@ -98,6 +122,21 @@ public boolean createScopedRequired() {
98
122
public GoogleCredentials createScoped (Collection <String > scopes ) {
99
123
return new AppEngineCredentials (scopes , this );
100
124
}
125
+
126
+ @ Override
127
+ public String account () {
128
+ return account ;
129
+ }
130
+
131
+ @ Override
132
+ public byte [] sign (byte [] toSign ) {
133
+ try {
134
+ Object signingResult = signForApp .invoke (appIdentityService , (Object ) toSign );
135
+ return (byte []) getSignature .invoke (signingResult );
136
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex ) {
137
+ throw new SigningException ("Failed to sign the provided bytes" , ex );
138
+ }
139
+ }
101
140
}
102
141
103
142
private static class AppEngineAuthCredentialsState
@@ -122,14 +161,27 @@ public boolean equals(Object obj) {
122
161
}
123
162
124
163
@ Override
125
- public GoogleCredentials credentials () {
126
- return new AppEngineCredentials ();
164
+ public AppEngineCredentials credentials () {
165
+ if (credentials == null ) {
166
+ credentials = new AppEngineCredentials ();
167
+ }
168
+ return credentials ;
127
169
}
128
170
129
171
@ Override
130
172
public RestorableState <AuthCredentials > capture () {
131
173
return STATE ;
132
174
}
175
+
176
+ @ Override
177
+ public String account () {
178
+ return credentials ().account ();
179
+ }
180
+
181
+ @ Override
182
+ public byte [] sign (byte [] toSign ) {
183
+ return credentials ().sign (toSign );
184
+ }
133
185
}
134
186
135
187
/**
@@ -138,8 +190,10 @@ public RestorableState<AuthCredentials> capture() {
138
190
* @see <a href="https://cloud.google.com/docs/authentication#user_accounts_and_service_accounts">
139
191
* User accounts and service accounts</a>
140
192
*/
141
- public static class ServiceAccountAuthCredentials extends AuthCredentials {
193
+ public static class ServiceAccountAuthCredentials extends AuthCredentials
194
+ implements ServiceAccountSigner {
142
195
196
+ private final ServiceAccountCredentials credentials ;
143
197
private final String account ;
144
198
private final PrivateKey privateKey ;
145
199
@@ -178,23 +232,44 @@ public boolean equals(Object obj) {
178
232
}
179
233
180
234
ServiceAccountAuthCredentials (String account , PrivateKey privateKey ) {
181
- this .account = checkNotNull (account );
182
- this .privateKey = checkNotNull (privateKey );
235
+ this (new ServiceAccountCredentials (null , account , privateKey , null , null ));
236
+ }
237
+
238
+ ServiceAccountAuthCredentials (ServiceAccountCredentials credentials ) {
239
+ this .credentials = checkNotNull (credentials );
240
+ this .account = checkNotNull (credentials .getClientEmail ());
241
+ this .privateKey = checkNotNull (credentials .getPrivateKey ());
183
242
}
184
243
185
244
@ Override
186
245
public ServiceAccountCredentials credentials () {
187
- return new ServiceAccountCredentials ( null , account , privateKey , null , null ) ;
246
+ return credentials ;
188
247
}
189
248
249
+ @ Override
190
250
public String account () {
191
251
return account ;
192
252
}
193
253
254
+ /**
255
+ * Returns the private key associated with the service account credentials.
256
+ */
194
257
public PrivateKey privateKey () {
195
258
return privateKey ;
196
259
}
197
260
261
+ @ Override
262
+ public byte [] sign (byte [] toSign ) {
263
+ try {
264
+ Signature signer = Signature .getInstance ("SHA256withRSA" );
265
+ signer .initSign (privateKey ());
266
+ signer .update (toSign );
267
+ return signer .sign ();
268
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException ex ) {
269
+ throw new SigningException ("Failed to sign the provided bytes" , ex );
270
+ }
271
+ }
272
+
198
273
@ Override
199
274
public RestorableState <AuthCredentials > capture () {
200
275
return new ServiceAccountAuthCredentialsState (account , privateKey );
@@ -242,6 +317,10 @@ public boolean equals(Object obj) {
242
317
}
243
318
}
244
319
320
+ ApplicationDefaultAuthCredentials (GoogleCredentials credentials ) {
321
+ googleCredentials = credentials ;
322
+ }
323
+
245
324
ApplicationDefaultAuthCredentials () throws IOException {
246
325
googleCredentials = GoogleCredentials .getApplicationDefault ();
247
326
}
@@ -320,7 +399,12 @@ public static AuthCredentials createForAppEngine() {
320
399
* @throws IOException if the credentials cannot be created in the current environment
321
400
*/
322
401
public static AuthCredentials createApplicationDefaults () throws IOException {
323
- return new ApplicationDefaultAuthCredentials ();
402
+ GoogleCredentials credentials = GoogleCredentials .getApplicationDefault ();
403
+ if (credentials instanceof ServiceAccountCredentials ) {
404
+ ServiceAccountCredentials serviceAccountCredentials = (ServiceAccountCredentials ) credentials ;
405
+ return new ServiceAccountAuthCredentials (serviceAccountCredentials );
406
+ }
407
+ return new ApplicationDefaultAuthCredentials (credentials );
324
408
}
325
409
326
410
/**
0 commit comments