1818
1919import 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 ;
2722import com .google .auth .oauth2 .GoogleCredentials ;
2823import com .google .auth .oauth2 .ServiceAccountCredentials ;
2924
3025import java .io .IOException ;
3126import java .io .InputStream ;
3227import java .io .Serializable ;
28+ import java .lang .reflect .Method ;
3329import java .security .PrivateKey ;
30+ import java .util .Collection ;
3431import 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}
0 commit comments