@@ -80,6 +80,13 @@ final class BigQueryJdbcOAuthUtility {
8080 + "Thank you for using JDBC Driver for Google BigQuery!\n "
8181 + "You may now close the window.</body></html>" ;
8282
83+ static final String BIGQUERY_SCOPE = "https://www.googleapis.com/auth/bigquery" ;
84+ static final String DRIVE_READONLY_SCOPE = "https://www.googleapis.com/auth/drive.readonly" ;
85+
86+ static final List <String > DEFAULT_BIGQUERY_SCOPES = Arrays .asList (BIGQUERY_SCOPE );
87+ static final List <String > BIGQUERY_WITH_DRIVE_SCOPES =
88+ Arrays .asList (BIGQUERY_SCOPE , DRIVE_READONLY_SCOPE );
89+
8390 private static final int USER_AUTH_TIMEOUT_MS = 120000 ;
8491 private static final BigQueryJdbcCustomLogger LOG =
8592 new BigQueryJdbcCustomLogger (BigQueryJdbcOAuthUtility .class .getName ());
@@ -117,6 +124,7 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
117124 throw new IllegalArgumentException (OAUTH_TYPE_ERROR_MESSAGE );
118125 }
119126 oauthProperties .put (BigQueryJdbcUrlUtility .OAUTH_TYPE_PROPERTY_NAME , String .valueOf (authType ));
127+
120128 switch (authType ) {
121129 case GOOGLE_SERVICE_ACCOUNT :
122130 // For using a Google Service Account (OAuth Type 0)
@@ -144,11 +152,6 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
144152 BigQueryJdbcUrlUtility .OAUTH_CLIENT_ID_PROPERTY_NAME , ds .getOAuthClientId ());
145153 oauthProperties .put (
146154 BigQueryJdbcUrlUtility .OAUTH_CLIENT_SECRET_PROPERTY_NAME , ds .getOAuthClientSecret ());
147- int reqGoogleDriveScope = ds .getRequestGoogleDriveScope ();
148- oauthProperties .put (
149- BigQueryJdbcUrlUtility .REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME ,
150- String .valueOf (reqGoogleDriveScope ));
151- LOG .fine ("RequestGoogleDriveScope parsed." );
152155 break ;
153156 case PRE_GENERATED_TOKEN :
154157 String refreshToken = ds .getOAuthRefreshToken ();
@@ -239,7 +242,7 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
239242 BigQueryJdbcUrlUtility .OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME ,
240243 ds .getOAuthSAImpersonationScopes () != null
241244 ? ds .getOAuthSAImpersonationScopes ()
242- : BigQueryJdbcUrlUtility . DEFAULT_OAUTH_SA_IMPERSONATION_SCOPES_VALUE );
245+ : BIGQUERY_SCOPE );
243246 oauthProperties .put (
244247 BigQueryJdbcUrlUtility .OAUTH_SA_IMPERSONATION_TOKEN_LIFETIME_PROPERTY_NAME ,
245248 ds .getOAuthSAImpersonationTokenLifetime () != null
@@ -258,6 +261,7 @@ static Map<String, String> parseOAuthProperties(DataSource ds, String callerClas
258261 static GoogleCredentials getCredentials (
259262 Map <String , String > authProperties ,
260263 Map <String , String > overrideProperties ,
264+ Boolean reqGoogleDriveScopeBool ,
261265 String callerClassName ) {
262266 LOG .finest ("++enter++\t " + callerClassName );
263267
@@ -280,15 +284,19 @@ static GoogleCredentials getCredentials(
280284 break ;
281285 case APPLICATION_DEFAULT_CREDENTIALS :
282286 // This auth method doesn't support service account impersonation
283- return getApplicationDefaultCredentials (callerClassName );
287+
288+ credentials = getApplicationDefaultCredentials (callerClassName );
289+ break ;
284290 case EXTERNAL_ACCOUNT_AUTH :
285291 // This auth method doesn't support service account impersonation
286- return getExternalAccountAuthCredentials (authProperties , callerClassName );
292+ credentials = getExternalAccountAuthCredentials (authProperties , callerClassName );
293+ break ;
287294 default :
288295 throw new IllegalStateException (OAUTH_TYPE_ERROR_MESSAGE );
289296 }
290297
291- return getServiceAccountImpersonatedCredentials (credentials , authProperties );
298+ return getServiceAccountImpersonatedCredentials (
299+ credentials , reqGoogleDriveScopeBool , authProperties );
292300 }
293301
294302 private static boolean isFileExists (String filename ) {
@@ -388,29 +396,10 @@ static UserAuthorizer getUserAuthorizer(
388396 String callerClassName )
389397 throws URISyntaxException {
390398 LOG .finest ("++enter++\t " + callerClassName );
399+
391400 List <String > scopes = new ArrayList <>();
392401 scopes .add ("https://www.googleapis.com/auth/bigquery" );
393402
394- // Add Google Drive scope conditionally
395- if (authProperties .containsKey (
396- BigQueryJdbcUrlUtility .REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME )) {
397- try {
398- int driveScopeValue =
399- Integer .parseInt (
400- authProperties .get (
401- BigQueryJdbcUrlUtility .REQUEST_GOOGLE_DRIVE_SCOPE_PROPERTY_NAME ));
402- if (driveScopeValue == 1 ) {
403- scopes .add ("https://www.googleapis.com/auth/drive.readonly" );
404- LOG .fine ("Added Google Drive read-only scope. Caller: " + callerClassName );
405- }
406- } catch (NumberFormatException e ) {
407- LOG .severe (
408- "Invalid value for RequestGoogleDriveScope, defaulting to not request Drive scope."
409- + " Caller: "
410- + callerClassName );
411- }
412- }
413-
414403 List <String > responseTypes = new ArrayList <>();
415404 responseTypes .add ("code" );
416405
@@ -500,14 +489,18 @@ private static GoogleCredentials getPreGeneratedAccessTokenCredentials(
500489 builder .setUniverseDomain (
501490 overrideProperties .get (BigQueryJdbcUrlUtility .UNIVERSE_DOMAIN_OVERRIDE_PROPERTY_NAME ));
502491 }
492+
503493 LOG .info ("Connection established. Auth Method: Pre-generated Access Token." );
504- return builder
505- .setAccessToken (
506- AccessToken .newBuilder ()
507- .setTokenValue (
508- authProperties .get (BigQueryJdbcUrlUtility .OAUTH_ACCESS_TOKEN_PROPERTY_NAME ))
509- .build ())
510- .build ();
494+ GoogleCredentials credentials =
495+ builder
496+ .setAccessToken (
497+ AccessToken .newBuilder ()
498+ .setTokenValue (
499+ authProperties .get (BigQueryJdbcUrlUtility .OAUTH_ACCESS_TOKEN_PROPERTY_NAME ))
500+ .build ())
501+ .build ();
502+
503+ return credentials ;
511504 }
512505
513506 static GoogleCredentials getPreGeneratedTokensCredentials (
@@ -552,6 +545,7 @@ static UserCredentials getPreGeneratedRefreshTokenCredentials(
552545 userCredentialsBuilder .setUniverseDomain (
553546 overrideProperties .get (BigQueryJdbcUrlUtility .UNIVERSE_DOMAIN_OVERRIDE_PROPERTY_NAME ));
554547 }
548+
555549 LOG .info ("Connection established. Auth Method: Pre-generated Refresh Token." );
556550 return userCredentialsBuilder .build ();
557551 }
@@ -571,6 +565,7 @@ private static GoogleCredentials getApplicationDefaultCredentials(String callerC
571565 LOG .info (
572566 "Connection established. Auth Method: Application Default Credentials, Principal: %s." ,
573567 principal );
568+
574569 return credentials ;
575570 } catch (IOException exception ) {
576571 // TODO throw exception
@@ -634,13 +629,19 @@ private static GoogleCredentials getExternalAccountAuthCredentials(
634629 // This function checks if connection string contains configuration for
635630 // credentials impersonation. If not, it returns regular credentials object.
636631 // If impersonated service account is provided, returns Credentials object
637- // accomodating this information.
632+ // accommodating this information.
638633 private static GoogleCredentials getServiceAccountImpersonatedCredentials (
639- GoogleCredentials credentials , Map <String , String > authProperties ) {
634+ GoogleCredentials credentials ,
635+ Boolean reqGoogleDriveScopeBool ,
636+ Map <String , String > authProperties ) {
640637
641638 String impersonationEmail =
642639 authProperties .get (BigQueryJdbcUrlUtility .OAUTH_SA_IMPERSONATION_EMAIL_PROPERTY_NAME );
643640 if (impersonationEmail == null || impersonationEmail .isEmpty ()) {
641+ if (reqGoogleDriveScopeBool ) {
642+ credentials = credentials .createScoped (BIGQUERY_WITH_DRIVE_SCOPES );
643+ LOG .fine ("Added Google Drive read-only scope to GoogleCredentials." );
644+ }
644645 return credentials ;
645646 }
646647
@@ -653,10 +654,18 @@ private static GoogleCredentials getServiceAccountImpersonatedCredentials(
653654
654655 // Scopes has a default value, so it should never be null
655656 List <String > impersonationScopes =
656- Arrays .asList (
657- authProperties
658- .get (BigQueryJdbcUrlUtility .OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME )
659- .split ("," ));
657+ new java .util .ArrayList <>(
658+ Arrays .asList (
659+ authProperties
660+ .get (BigQueryJdbcUrlUtility .OAUTH_SA_IMPERSONATION_SCOPES_PROPERTY_NAME )
661+ .split ("," )));
662+
663+ if (reqGoogleDriveScopeBool ) {
664+ if (!impersonationScopes .contains (DRIVE_READONLY_SCOPE )) {
665+ impersonationScopes .add (DRIVE_READONLY_SCOPE );
666+ LOG .fine ("Added Google Drive read-only scope to impersonation scopes." );
667+ }
668+ }
660669
661670 // Token lifetime has a default value, so it should never be null
662671 String impersonationLifetime =
0 commit comments