Skip to content

Commit 730fbbf

Browse files
SNOW-1196041: Ignore default credentials in GCS client (#1656)
1 parent 1624da4 commit 730fbbf

10 files changed

+194
-97
lines changed

parent-pom.xml

+10
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<commons.pool.version>1.5.4</commons.pool.version>
3939
<c3p0.version>0.9.5.4</c3p0.version>
4040
<google.api.grpc.version>2.22.0</google.api.grpc.version>
41+
<google.auth.library.oauth2.http.version>1.19.0</google.auth.library.oauth2.http.version>
4142
<google.cloud.core.version>2.21.0</google.cloud.core.version>
4243
<google.cloud.storage.version>2.22.6</google.cloud.storage.version>
4344
<google.code.gson.version>2.10.1</google.code.gson.version>
@@ -161,6 +162,11 @@
161162
<artifactId>proto-google-common-protos</artifactId>
162163
<version>${google.api.grpc.version}</version>
163164
</dependency>
165+
<dependency>
166+
<groupId>com.google.auth</groupId>
167+
<artifactId>google-auth-library-oauth2-http</artifactId>
168+
<version>${google.auth.library.oauth2.http.version}</version>
169+
</dependency>
164170
<dependency>
165171
<groupId>com.google.cloud</groupId>
166172
<artifactId>google-cloud-core</artifactId>
@@ -514,6 +520,10 @@
514520
<groupId>com.google.api</groupId>
515521
<artifactId>gax</artifactId>
516522
</dependency>
523+
<dependency>
524+
<groupId>com.google.auth</groupId>
525+
<artifactId>google-auth-library-oauth2-http</artifactId>
526+
</dependency>
517527
<dependency>
518528
<groupId>com.google.cloud</groupId>
519529
<artifactId>google-cloud-core</artifactId>

src/main/java/net/snowflake/client/core/SFBaseSession.java

+11
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ public abstract class SFBaseSession {
137137
// we need to allow for it to maintain backwards compatibility.
138138
private boolean enablePatternSearch = true;
139139

140+
/** Disable lookup for default credentials by GCS library */
141+
private boolean disableGcsDefaultCredentials = false;
142+
140143
private Map<String, Object> commonParameters;
141144

142145
protected SFBaseSession(SFConnectionHandler sfConnectionHandler) {
@@ -735,6 +738,14 @@ public void setEnablePatternSearch(boolean enablePatternSearch) {
735738
this.enablePatternSearch = enablePatternSearch;
736739
}
737740

741+
public boolean getDisableGcsDefaultCredentials() {
742+
return disableGcsDefaultCredentials;
743+
}
744+
745+
public void setDisableGcsDefaultCredentials(boolean disableGcsDefaultCredentials) {
746+
this.disableGcsDefaultCredentials = disableGcsDefaultCredentials;
747+
}
748+
738749
public int getClientResultChunkSize() {
739750
return clientResultChunkSize;
740751
}

src/main/java/net/snowflake/client/core/SFSession.java

+5
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@ public void addSFSessionProperty(String propertyName, Object propertyValue) thro
469469
setEnablePatternSearch(getBooleanValue(propertyValue));
470470
}
471471
break;
472+
case DISABLE_GCS_DEFAULT_CREDENTIALS:
473+
if (propertyValue != null) {
474+
setDisableGcsDefaultCredentials(getBooleanValue(propertyValue));
475+
}
476+
break;
472477

473478
default:
474479
break;

src/main/java/net/snowflake/client/core/SFSessionProperty.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ public enum SFSessionProperty {
7878

7979
RETRY_TIMEOUT("retryTimeout", false, Integer.class),
8080

81-
ENABLE_PATTERN_SEARCH("enablePatternSearch", false, Boolean.class);
81+
ENABLE_PATTERN_SEARCH("enablePatternSearch", false, Boolean.class),
82+
83+
DISABLE_GCS_DEFAULT_CREDENTIALS("disableGcsDefaultCredentials", false, Boolean.class);
8284

8385
// property key in string
8486
private String propertyKey;

src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import net.snowflake.client.core.OCSPMode;
3737
import net.snowflake.client.core.SFBaseSession;
3838
import net.snowflake.client.core.SFSessionProperty;
39+
import net.snowflake.client.core.SnowflakeJdbcInternalApi;
3940
import net.snowflake.client.log.SFLogger;
4041
import net.snowflake.client.log.SFLoggerFactory;
4142
import net.snowflake.common.core.SqlState;
@@ -50,7 +51,7 @@
5051
*/
5152
public class SnowflakeUtil {
5253

53-
static final SFLogger logger = SFLoggerFactory.getLogger(RestRequest.class);
54+
private static final SFLogger logger = SFLoggerFactory.getLogger(SnowflakeUtil.class);
5455

5556
/** Additional data types not covered by standard JDBC */
5657
public static final int EXTRA_TYPES_TIMESTAMP_LTZ = 50000;
@@ -754,4 +755,21 @@ public static Time getTimeInSessionTimezone(Long time, int nanos) {
754755
ts.setTime(c.getTimeInMillis());
755756
return ts;
756757
}
758+
759+
/**
760+
* Helper function to convert system properties to boolean
761+
*
762+
* @param systemProperty name of the system property
763+
* @param defaultValue default value used
764+
* @return the value of the system property as boolean, else the default value
765+
*/
766+
@SnowflakeJdbcInternalApi
767+
public static boolean convertSystemPropertyToBooleanValue(
768+
String systemProperty, boolean defaultValue) {
769+
String systemPropertyValue = systemGetProperty(systemProperty);
770+
if (systemPropertyValue != null) {
771+
return Boolean.parseBoolean(systemPropertyValue);
772+
}
773+
return defaultValue;
774+
}
757775
}

src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java

+22-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import com.fasterxml.jackson.databind.ObjectMapper;
1313
import com.google.api.gax.paging.Page;
1414
import com.google.api.gax.rpc.FixedHeaderProvider;
15+
import com.google.auth.oauth2.AccessToken;
16+
import com.google.auth.oauth2.GoogleCredentials;
1517
import com.google.cloud.storage.Blob;
1618
import com.google.cloud.storage.BlobId;
1719
import com.google.cloud.storage.BlobInfo;
@@ -43,6 +45,7 @@
4345
import net.snowflake.client.core.ObjectMapperFactory;
4446
import net.snowflake.client.core.SFSession;
4547
import net.snowflake.client.core.SFSessionProperty;
48+
import net.snowflake.client.core.SnowflakeJdbcInternalApi;
4649
import net.snowflake.client.jdbc.ErrorCode;
4750
import net.snowflake.client.jdbc.FileBackedOutputStream;
4851
import net.snowflake.client.jdbc.MatDesc;
@@ -74,6 +77,10 @@
7477
* @author ppaulus
7578
*/
7679
public class SnowflakeGCSClient implements SnowflakeStorageClient {
80+
@SnowflakeJdbcInternalApi
81+
public static final String DISABLE_GCS_DEFAULT_CREDENTIALS_PROPERTY_NAME =
82+
"net.snowflake.jdbc.disableGcsDefaultCredentials";
83+
7784
private static final String GCS_ENCRYPTIONDATAPROP = "encryptiondata";
7885
private static final String localFileSep = systemGetProperty("file.separator");
7986
private static final String GCS_METADATA_PREFIX = "x-goog-meta-";
@@ -1200,13 +1207,19 @@ private void setupGCSClient(
12001207
try {
12011208
String accessToken = (String) stage.getCredentials().get("GCS_ACCESS_TOKEN");
12021209
if (accessToken != null) {
1210+
// We are authenticated with an oauth access token.
1211+
StorageOptions.Builder builder = StorageOptions.newBuilder();
1212+
if (areDisabledGcsDefaultCredentials(session)) {
1213+
logger.debug(
1214+
"Adding explicit credentials to avoid default credential lookup by the GCS client");
1215+
builder.setCredentials(GoogleCredentials.create(new AccessToken(accessToken, null)));
1216+
}
1217+
12031218
// Using GoogleCredential with access token will cause IllegalStateException when the token
12041219
// is expired and trying to refresh, which cause error cannot be caught. Instead, set a
12051220
// header so we can caught the error code.
1206-
1207-
// We are authenticated with an oauth access token.
12081221
this.gcsClient =
1209-
StorageOptions.newBuilder()
1222+
builder
12101223
.setHeaderProvider(
12111224
FixedHeaderProvider.create("Authorization", "Bearer " + accessToken))
12121225
.build()
@@ -1234,6 +1247,12 @@ private void setupGCSClient(
12341247
}
12351248
}
12361249

1250+
private static boolean areDisabledGcsDefaultCredentials(SFSession session) {
1251+
return session != null && session.getDisableGcsDefaultCredentials()
1252+
|| SnowflakeUtil.convertSystemPropertyToBooleanValue(
1253+
DISABLE_GCS_DEFAULT_CREDENTIALS_PROPERTY_NAME, false);
1254+
}
1255+
12371256
private static boolean isSuccessStatusCode(int code) {
12381257
return code < 300 && code >= 200;
12391258
}

src/main/java/net/snowflake/client/jdbc/cloud/storage/StorageClientFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*/
2323
public class StorageClientFactory {
2424

25-
private static final SFLogger logger = SFLoggerFactory.getLogger(SnowflakeS3Client.class);
25+
private static final SFLogger logger = SFLoggerFactory.getLogger(StorageClientFactory.class);
2626

2727
private static StorageClientFactory factory;
2828

src/test/java/net/snowflake/client/jdbc/ConnectionLatestIT.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,10 @@ public void testQueryStatusErrorMessageAndErrorCodeChangeOnAsyncQuery() throws S
403403
SnowflakeResultSet sfResultSet = rs1.unwrap(SnowflakeResultSet.class);
404404
// status should change state to RUNNING and then to SUCCESS
405405
await()
406-
.atMost(Duration.ofSeconds(5))
406+
.atMost(Duration.ofSeconds(10))
407407
.until(() -> sfResultSet.getStatusV2().getStatus(), equalTo(QueryStatus.RUNNING));
408408
await()
409-
.atMost(Duration.ofSeconds(5))
409+
.atMost(Duration.ofSeconds(50))
410410
.until(() -> sfResultSet.getStatusV2().getStatus(), equalTo(QueryStatus.SUCCESS));
411411
}
412412
}

0 commit comments

Comments
 (0)