2828import com .google .api .client .json .JsonFactory ;
2929import com .google .api .client .json .jackson2 .JacksonFactory ;
3030import com .google .api .client .util .Preconditions ;
31+ import com .google .api .client .util .Strings ;
3132import com .google .api .client .util .store .FileDataStoreFactory ;
3233import com .google .cloud .dataflow .sdk .options .GcpOptions ;
3334
@@ -49,15 +50,14 @@ public class Credentials {
4950
5051 private static final Logger LOG = LoggerFactory .getLogger (Credentials .class );
5152
52- /**
53- * OAuth 2.0 scopes used by a local worker (not on GCE).
54- * The scope cloud-platform provides access to all Cloud Platform resources.
55- * cloud-platform isn't sufficient yet for talking to datastore so we request
56- * those resources separately.
57- * <p>
58- * Note that trusted scope relationships don't apply to OAuth tokens, so for
59- * services we access directly (GCS) as opposed to through the backend
60- * (BigQuery, GCE), we need to explicitly request that scope.
53+ /** OAuth 2.0 scopes used by a local worker (not on GCE).
54+ * The scope cloud-platform provides access to all Cloud Platform resources.
55+ * cloud-platform isn't sufficient yet for talking to datastore so we request
56+ * those resources separately.
57+ *
58+ * Note that trusted scope relationships don't apply to OAuth tokens, so for
59+ * services we access directly (GCS) as opposed to through the backend
60+ * (BigQuery, GCE), we need to explicitly request that scope.
6161 */
6262 private static final List <String > SCOPES = Arrays .asList (
6363 "https://www.googleapis.com/auth/cloud-platform" ,
@@ -74,15 +74,20 @@ public String getRedirectUri() {
7474
7575 /**
7676 * Initializes OAuth2 credentials.
77- * <p>
78- * This can use 3 different mechanisms for obtaining a credential:
77+ *
78+ * This can use 4 different mechanisms for obtaining a credential:
7979 * <ol>
8080 * <li>
8181 * It can fetch the
8282 * <a href="https://developers.google.com/accounts/docs/application-default-credentials">
8383 * application default credentials</a>.
8484 * </li>
8585 * <li>
86+ * It can run the gcloud tool in a subprocess to obtain a credential.
87+ * This is the preferred mechanism. The property "gcloud_path" can be
88+ * used to specify where we search for gcloud data.
89+ * </li>
90+ * <li>
8691 * The user can specify a client secrets file and go through the OAuth2
8792 * webflow. The credential will then be cached in the user's home
8893 * directory for reuse. Provide the property "secrets_file" to use this
@@ -96,8 +101,8 @@ public String getRedirectUri() {
96101 * </ol>
97102 * The default mechanism is to use the
98103 * <a href="https://developers.google.com/accounts/docs/application-default-credentials">
99- * application default credentials</a>. The other options can be used by providing the
100- * corresponding properties.
104+ * application default credentials</a> falling back to gcloud . The other options can be
105+ * used by providing the corresponding properties.
101106 */
102107 public static Credential getCredential (GcpOptions options )
103108 throws IOException , GeneralSecurityException {
@@ -119,12 +124,11 @@ public static Credential getCredential(GcpOptions options)
119124 try {
120125 return GoogleCredential .getApplicationDefault ().createScoped (SCOPES );
121126 } catch (IOException e ) {
122- throw new RuntimeException ("Unable to get application default credentials. Please see "
123- + "https://developers.google.com/accounts/docs/application-default-credentials "
124- + "for details on how to specify credentials. This version of the SDK is "
125- + "dependent on the gcloud core component version 2015.02.05 or newer to "
126- + "be able to get credentials from the currently authorized user via gcloud auth." , e );
127+ LOG .debug ("Failed to get application default credentials, falling back to gcloud." );
127128 }
129+
130+ String gcloudPath = options .getGCloudPath ();
131+ return getCredentialFromGCloud (gcloudPath );
128132 }
129133
130134 /**
@@ -145,6 +149,29 @@ private static Credential getCredentialFromFile(
145149 return credential ;
146150 }
147151
152+ /**
153+ * Loads OAuth2 credential from GCloud utility.
154+ */
155+ private static Credential getCredentialFromGCloud (String gcloudPath )
156+ throws IOException , GeneralSecurityException {
157+ GCloudCredential credential ;
158+ HttpTransport transport = GoogleNetHttpTransport .newTrustedTransport ();
159+ if (Strings .isNullOrEmpty (gcloudPath )) {
160+ credential = new GCloudCredential (transport );
161+ } else {
162+ credential = new GCloudCredential (gcloudPath , transport );
163+ }
164+
165+ try {
166+ credential .refreshToken ();
167+ } catch (IOException e ) {
168+ throw new RuntimeException ("Could not obtain credential using gcloud" , e );
169+ }
170+
171+ LOG .info ("Got user credential from GCloud" );
172+ return credential ;
173+ }
174+
148175 /**
149176 * Loads OAuth2 credential from client secrets, which may require an
150177 * interactive authorization prompt.
0 commit comments