diff --git a/src/main/java/net/snowflake/client/core/HttpClientSettingsKey.java b/src/main/java/net/snowflake/client/core/HttpClientSettingsKey.java index 183655be7..0ca3df8b0 100644 --- a/src/main/java/net/snowflake/client/core/HttpClientSettingsKey.java +++ b/src/main/java/net/snowflake/client/core/HttpClientSettingsKey.java @@ -4,7 +4,6 @@ package net.snowflake.client.core; -import com.amazonaws.Protocol; import com.google.common.base.Strings; import java.io.Serializable; @@ -124,7 +123,8 @@ public String getUserAgentSuffix() { } /** Be careful of using this! Should only be called when password is later masked. */ - String getProxyPassword() { + @SnowflakeJdbcInternalApi + public String getProxyPassword() { return this.proxyPassword; } @@ -132,8 +132,19 @@ public String getNonProxyHosts() { return this.nonProxyHosts; } - public Protocol getProxyProtocol() { - return this.proxyProtocol.equalsIgnoreCase("https") ? Protocol.HTTPS : Protocol.HTTP; + /** + * @deprecated Use {@link #getProxyHttpProtocol()} + * @return ProxyProtocol + */ + @Deprecated + public com.amazonaws.Protocol getProxyProtocol() { + return this.proxyProtocol.equalsIgnoreCase("https") + ? com.amazonaws.Protocol.HTTPS + : com.amazonaws.Protocol.HTTP; + } + + public HttpProtocol getProxyHttpProtocol() { + return this.proxyProtocol.equalsIgnoreCase("https") ? HttpProtocol.HTTPS : HttpProtocol.HTTP; } public Boolean getGzipDisabled() { diff --git a/src/main/java/net/snowflake/client/core/HttpProtocol.java b/src/main/java/net/snowflake/client/core/HttpProtocol.java new file mode 100644 index 000000000..76868b0eb --- /dev/null +++ b/src/main/java/net/snowflake/client/core/HttpProtocol.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Snowflake Computing Inc. All rights reserved. + */ + +package net.snowflake.client.core; + +public enum HttpProtocol { + HTTP("http"), + + HTTPS("https"); + + private final String scheme; + + HttpProtocol(String scheme) { + this.scheme = scheme; + } + + public String getScheme() { + return scheme; + } +} diff --git a/src/main/java/net/snowflake/client/core/HttpUtil.java b/src/main/java/net/snowflake/client/core/HttpUtil.java index 5203db2f1..055db1c66 100644 --- a/src/main/java/net/snowflake/client/core/HttpUtil.java +++ b/src/main/java/net/snowflake/client/core/HttpUtil.java @@ -9,7 +9,6 @@ import static org.apache.http.client.config.CookieSpecs.IGNORE_COOKIES; import com.amazonaws.ClientConfiguration; -import com.amazonaws.Protocol; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.microsoft.azure.storage.OperationContext; @@ -36,6 +35,7 @@ import net.snowflake.client.jdbc.SnowflakeDriver; import net.snowflake.client.jdbc.SnowflakeSQLException; import net.snowflake.client.jdbc.SnowflakeUtil; +import net.snowflake.client.jdbc.cloud.storage.S3HttpUtil; import net.snowflake.client.log.ArgSupplier; import net.snowflake.client.log.SFLogger; import net.snowflake.client.log.SFLoggerFactory; @@ -143,19 +143,11 @@ public static void closeExpiredAndIdleConnections() { * * @param key key to HttpClient map containing OCSP and proxy info * @param clientConfig the configuration needed by S3 to set the proxy + * @deprecated use S3HttpUtil.setProxyForS3(HttpClientSettingsKey, ClientConfiguration) instead */ + @Deprecated public static void setProxyForS3(HttpClientSettingsKey key, ClientConfiguration clientConfig) { - if (key != null && key.usesProxy()) { - clientConfig.setProxyProtocol(key.getProxyProtocol()); - clientConfig.setProxyHost(key.getProxyHost()); - clientConfig.setProxyPort(key.getProxyPort()); - clientConfig.setNonProxyHosts(key.getNonProxyHosts()); - if (!Strings.isNullOrEmpty(key.getProxyUser()) - && !Strings.isNullOrEmpty(key.getProxyPassword())) { - clientConfig.setProxyUsername(key.getProxyUser()); - clientConfig.setProxyPassword(key.getProxyPassword()); - } - } + S3HttpUtil.setProxyForS3(key, clientConfig); } /** @@ -165,51 +157,12 @@ public static void setProxyForS3(HttpClientSettingsKey key, ClientConfiguration * @param proxyProperties proxy properties * @param clientConfig the configuration needed by S3 to set the proxy * @throws SnowflakeSQLException + * @deprecated use S3HttpUtil.setSessionlessProxyForS3(Properties, ClientConfiguration) instead */ + @Deprecated public static void setSessionlessProxyForS3( Properties proxyProperties, ClientConfiguration clientConfig) throws SnowflakeSQLException { - // do nothing yet - if (proxyProperties != null - && proxyProperties.size() > 0 - && proxyProperties.getProperty(SFSessionProperty.USE_PROXY.getPropertyKey()) != null) { - Boolean useProxy = - Boolean.valueOf( - proxyProperties.getProperty(SFSessionProperty.USE_PROXY.getPropertyKey())); - if (useProxy) { - // set up other proxy related values. - String proxyHost = - proxyProperties.getProperty(SFSessionProperty.PROXY_HOST.getPropertyKey()); - int proxyPort; - try { - proxyPort = - Integer.parseInt( - proxyProperties.getProperty(SFSessionProperty.PROXY_PORT.getPropertyKey())); - } catch (NumberFormatException | NullPointerException e) { - throw new SnowflakeSQLException( - ErrorCode.INVALID_PROXY_PROPERTIES, "Could not parse port number"); - } - String proxyUser = - proxyProperties.getProperty(SFSessionProperty.PROXY_USER.getPropertyKey()); - String proxyPassword = - proxyProperties.getProperty(SFSessionProperty.PROXY_PASSWORD.getPropertyKey()); - String nonProxyHosts = - proxyProperties.getProperty(SFSessionProperty.NON_PROXY_HOSTS.getPropertyKey()); - String proxyProtocol = - proxyProperties.getProperty(SFSessionProperty.PROXY_PROTOCOL.getPropertyKey()); - Protocol protocolEnum = - (!Strings.isNullOrEmpty(proxyProtocol) && proxyProtocol.equalsIgnoreCase("https")) - ? Protocol.HTTPS - : Protocol.HTTP; - clientConfig.setProxyHost(proxyHost); - clientConfig.setProxyPort(proxyPort); - clientConfig.setNonProxyHosts(nonProxyHosts); - clientConfig.setProxyProtocol(protocolEnum); - if (!Strings.isNullOrEmpty(proxyUser) && !Strings.isNullOrEmpty(proxyPassword)) { - clientConfig.setProxyUsername(proxyUser); - clientConfig.setProxyPassword(proxyPassword); - } - } - } + S3HttpUtil.setSessionlessProxyForS3(proxyProperties, clientConfig); } /** @@ -324,7 +277,7 @@ public static CloseableHttpClient buildHttpClient( HttpHost proxy = (key != null && key.usesProxy()) ? new HttpHost( - key.getProxyHost(), key.getProxyPort(), key.getProxyProtocol().toString()) + key.getProxyHost(), key.getProxyPort(), key.getProxyHttpProtocol().getScheme()) : null; // If defaultrequestconfig is not initialized or its proxy settings do not match current proxy // settings, re-build it (current or old proxy settings could be null, so null check is @@ -408,7 +361,7 @@ public static CloseableHttpClient buildHttpClient( new SnowflakeMutableProxyRoutePlanner( key.getProxyHost(), key.getProxyPort(), - key.getProxyProtocol(), + key.getProxyHttpProtocol(), key.getNonProxyHosts())); httpClientBuilder = httpClientBuilder.setProxy(proxy).setRoutePlanner(sdkProxyRoutePlanner); if (!Strings.isNullOrEmpty(key.getProxyUser()) diff --git a/src/main/java/net/snowflake/client/core/SFSession.java b/src/main/java/net/snowflake/client/core/SFSession.java index b2b5ae3a1..f93f29492 100644 --- a/src/main/java/net/snowflake/client/core/SFSession.java +++ b/src/main/java/net/snowflake/client/core/SFSession.java @@ -550,7 +550,7 @@ public synchronized void open() throws SFException, SnowflakeSQLException { httpClientSettingsKey.getProxyUser(), !Strings.isNullOrEmpty(httpClientSettingsKey.getProxyPassword()) ? "***" : "(empty)", httpClientSettingsKey.getNonProxyHosts(), - httpClientSettingsKey.getProxyProtocol()); + httpClientSettingsKey.getProxyHttpProtocol()); // TODO: temporarily hardcode sessionParameter debug info. will be changed in the future SFLoginInput loginInput = new SFLoginInput(); diff --git a/src/main/java/net/snowflake/client/core/SnowflakeMutableProxyRoutePlanner.java b/src/main/java/net/snowflake/client/core/SnowflakeMutableProxyRoutePlanner.java index e21e9d78c..b0aae8d2f 100644 --- a/src/main/java/net/snowflake/client/core/SnowflakeMutableProxyRoutePlanner.java +++ b/src/main/java/net/snowflake/client/core/SnowflakeMutableProxyRoutePlanner.java @@ -24,11 +24,22 @@ public class SnowflakeMutableProxyRoutePlanner implements HttpRoutePlanner, Seri private String host; private int proxyPort; private String nonProxyHosts; - private Protocol protocol; + private HttpProtocol protocol; + /** + * @deprecated use SnowflakeMutableProxyRoutePlanner(String host, int proxyPort, HttpProtocol + * protocol, String nonProxyHosts) + */ + @Deprecated public SnowflakeMutableProxyRoutePlanner( String host, int proxyPort, Protocol proxyProtocol, String nonProxyHosts) { - proxyRoutePlanner = new SdkProxyRoutePlanner(host, proxyPort, proxyProtocol, nonProxyHosts); + this(host, proxyPort, toSnowflakeProtocol(proxyProtocol), nonProxyHosts); + } + + public SnowflakeMutableProxyRoutePlanner( + String host, int proxyPort, HttpProtocol proxyProtocol, String nonProxyHosts) { + proxyRoutePlanner = + new SdkProxyRoutePlanner(host, proxyPort, toAwsProtocol(proxyProtocol), nonProxyHosts); this.host = host; this.proxyPort = proxyPort; this.nonProxyHosts = nonProxyHosts; @@ -37,7 +48,8 @@ public SnowflakeMutableProxyRoutePlanner( public void setNonProxyHosts(String nonProxyHosts) { this.nonProxyHosts = nonProxyHosts; - proxyRoutePlanner = new SdkProxyRoutePlanner(host, proxyPort, protocol, nonProxyHosts); + proxyRoutePlanner = + new SdkProxyRoutePlanner(host, proxyPort, toAwsProtocol(protocol), nonProxyHosts); } public String getNonProxyHosts() { @@ -49,4 +61,12 @@ public HttpRoute determineRoute(HttpHost target, HttpRequest request, HttpContex throws HttpException { return proxyRoutePlanner.determineRoute(target, request, context); } + + private static Protocol toAwsProtocol(HttpProtocol protocol) { + return protocol == HttpProtocol.HTTP ? Protocol.HTTP : Protocol.HTTPS; + } + + private static HttpProtocol toSnowflakeProtocol(Protocol protocol) { + return protocol == Protocol.HTTP ? HttpProtocol.HTTP : HttpProtocol.HTTPS; + } } diff --git a/src/main/java/net/snowflake/client/jdbc/cloud/storage/S3HttpUtil.java b/src/main/java/net/snowflake/client/jdbc/cloud/storage/S3HttpUtil.java new file mode 100644 index 000000000..ec7f0c7ca --- /dev/null +++ b/src/main/java/net/snowflake/client/jdbc/cloud/storage/S3HttpUtil.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 Snowflake Computing Inc. All rights reserved. + */ + +package net.snowflake.client.jdbc.cloud.storage; + +import com.amazonaws.ClientConfiguration; +import com.amazonaws.Protocol; +import com.google.common.base.Strings; +import java.util.Properties; +import net.snowflake.client.core.HttpClientSettingsKey; +import net.snowflake.client.core.HttpProtocol; +import net.snowflake.client.core.SFSessionProperty; +import net.snowflake.client.core.SnowflakeJdbcInternalApi; +import net.snowflake.client.jdbc.ErrorCode; +import net.snowflake.client.jdbc.SnowflakeSQLException; + +@SnowflakeJdbcInternalApi +public class S3HttpUtil { + /** + * A static function to set S3 proxy params when there is a valid session + * + * @param key key to HttpClient map containing OCSP and proxy info + * @param clientConfig the configuration needed by S3 to set the proxy + */ + public static void setProxyForS3(HttpClientSettingsKey key, ClientConfiguration clientConfig) { + if (key != null && key.usesProxy()) { + clientConfig.setProxyProtocol( + key.getProxyHttpProtocol() == HttpProtocol.HTTPS ? Protocol.HTTPS : Protocol.HTTP); + clientConfig.setProxyHost(key.getProxyHost()); + clientConfig.setProxyPort(key.getProxyPort()); + clientConfig.setNonProxyHosts(key.getNonProxyHosts()); + if (!Strings.isNullOrEmpty(key.getProxyUser()) + && !Strings.isNullOrEmpty(key.getProxyPassword())) { + clientConfig.setProxyUsername(key.getProxyUser()); + clientConfig.setProxyPassword(key.getProxyPassword()); + } + } + } + + /** + * A static function to set S3 proxy params for sessionless connections using the proxy params + * from the StageInfo + * + * @param proxyProperties proxy properties + * @param clientConfig the configuration needed by S3 to set the proxy + * @throws SnowflakeSQLException + */ + public static void setSessionlessProxyForS3( + Properties proxyProperties, ClientConfiguration clientConfig) throws SnowflakeSQLException { + // do nothing yet + if (proxyProperties != null + && proxyProperties.size() > 0 + && proxyProperties.getProperty(SFSessionProperty.USE_PROXY.getPropertyKey()) != null) { + Boolean useProxy = + Boolean.valueOf( + proxyProperties.getProperty(SFSessionProperty.USE_PROXY.getPropertyKey())); + if (useProxy) { + // set up other proxy related values. + String proxyHost = + proxyProperties.getProperty(SFSessionProperty.PROXY_HOST.getPropertyKey()); + int proxyPort; + try { + proxyPort = + Integer.parseInt( + proxyProperties.getProperty(SFSessionProperty.PROXY_PORT.getPropertyKey())); + } catch (NumberFormatException | NullPointerException e) { + throw new SnowflakeSQLException( + ErrorCode.INVALID_PROXY_PROPERTIES, "Could not parse port number"); + } + String proxyUser = + proxyProperties.getProperty(SFSessionProperty.PROXY_USER.getPropertyKey()); + String proxyPassword = + proxyProperties.getProperty(SFSessionProperty.PROXY_PASSWORD.getPropertyKey()); + String nonProxyHosts = + proxyProperties.getProperty(SFSessionProperty.NON_PROXY_HOSTS.getPropertyKey()); + String proxyProtocol = + proxyProperties.getProperty(SFSessionProperty.PROXY_PROTOCOL.getPropertyKey()); + Protocol protocolEnum = + (!Strings.isNullOrEmpty(proxyProtocol) && proxyProtocol.equalsIgnoreCase("https")) + ? Protocol.HTTPS + : Protocol.HTTP; + clientConfig.setProxyHost(proxyHost); + clientConfig.setProxyPort(proxyPort); + clientConfig.setNonProxyHosts(nonProxyHosts); + clientConfig.setProxyProtocol(protocolEnum); + if (!Strings.isNullOrEmpty(proxyUser) && !Strings.isNullOrEmpty(proxyPassword)) { + clientConfig.setProxyUsername(proxyUser); + clientConfig.setProxyPassword(proxyPassword); + } + } + } + } +} diff --git a/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeS3Client.java b/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeS3Client.java index 9ff35a247..b5af0aef5 100644 --- a/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeS3Client.java +++ b/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeS3Client.java @@ -166,9 +166,9 @@ private void setupSnowflakeS3Client( clientConfig.withSignerOverride("AWSS3V4SignerType"); clientConfig.getApacheHttpClientConfig().setSslSocketFactory(getSSLConnectionSocketFactory()); if (session != null) { - HttpUtil.setProxyForS3(session.getHttpClientKey(), clientConfig); + S3HttpUtil.setProxyForS3(session.getHttpClientKey(), clientConfig); } else { - HttpUtil.setSessionlessProxyForS3(proxyProperties, clientConfig); + S3HttpUtil.setSessionlessProxyForS3(proxyProperties, clientConfig); } AmazonS3Builder amazonS3Builder = AmazonS3Client.builder(); if (encMat != null) { diff --git a/src/test/java/net/snowflake/client/core/CoreUtilsMiscellaneousTest.java b/src/test/java/net/snowflake/client/core/CoreUtilsMiscellaneousTest.java index 598ffcdc0..f11614c8b 100644 --- a/src/test/java/net/snowflake/client/core/CoreUtilsMiscellaneousTest.java +++ b/src/test/java/net/snowflake/client/core/CoreUtilsMiscellaneousTest.java @@ -21,6 +21,7 @@ import net.snowflake.client.jdbc.ErrorCode; import net.snowflake.client.jdbc.SnowflakeSQLException; import net.snowflake.client.jdbc.SnowflakeUtil; +import net.snowflake.client.jdbc.cloud.storage.S3HttpUtil; import org.junit.Test; public class CoreUtilsMiscellaneousTest { @@ -109,7 +110,7 @@ public void testSetProxyForS3() { "jdbc", false); ClientConfiguration clientConfig = new ClientConfiguration(); - HttpUtil.setProxyForS3(testKey, clientConfig); + S3HttpUtil.setProxyForS3(testKey, clientConfig); assertEquals(Protocol.HTTPS, clientConfig.getProxyProtocol()); assertEquals("snowflakecomputing.com", clientConfig.getProxyHost()); assertEquals(443, clientConfig.getProxyPort()); @@ -129,7 +130,7 @@ public void testSetSessionlessProxyForS3() throws SnowflakeSQLException { props.put("nonProxyHosts", "baz.com | foo.com"); props.put("proxyProtocol", "http"); ClientConfiguration clientConfig = new ClientConfiguration(); - HttpUtil.setSessionlessProxyForS3(props, clientConfig); + S3HttpUtil.setSessionlessProxyForS3(props, clientConfig); assertEquals(Protocol.HTTP, clientConfig.getProxyProtocol()); assertEquals("localhost", clientConfig.getProxyHost()); assertEquals(8084, clientConfig.getProxyPort()); @@ -139,7 +140,7 @@ public void testSetSessionlessProxyForS3() throws SnowflakeSQLException { // Test that exception is thrown when port number is invalid props.put("proxyPort", "invalidnumber"); try { - HttpUtil.setSessionlessProxyForS3(props, clientConfig); + S3HttpUtil.setSessionlessProxyForS3(props, clientConfig); } catch (SnowflakeSQLException e) { assertEquals((int) ErrorCode.INVALID_PROXY_PROPERTIES.getMessageCode(), e.getErrorCode()); } @@ -349,7 +350,7 @@ public void testNullAndEmptyProxySettingsForS3() { HttpClientSettingsKey testKey = new HttpClientSettingsKey(OCSPMode.FAIL_OPEN, null, 443, null, null, null, "", "", false); ClientConfiguration clientConfig = new ClientConfiguration(); - HttpUtil.setProxyForS3(testKey, clientConfig); + S3HttpUtil.setProxyForS3(testKey, clientConfig); assertEquals(Protocol.HTTP, clientConfig.getProxyProtocol()); assertEquals("", clientConfig.getProxyHost()); assertEquals(443, clientConfig.getProxyPort()); diff --git a/src/test/java/net/snowflake/client/jdbc/CustomProxyLatestIT.java b/src/test/java/net/snowflake/client/jdbc/CustomProxyLatestIT.java index 719257871..e2edde50a 100644 --- a/src/test/java/net/snowflake/client/jdbc/CustomProxyLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/CustomProxyLatestIT.java @@ -9,7 +9,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; -import com.amazonaws.Protocol; import java.io.File; import java.net.Authenticator; import java.net.PasswordAuthentication; @@ -21,6 +20,7 @@ import java.util.Properties; import net.snowflake.client.category.TestCategoryOthers; import net.snowflake.client.core.HttpClientSettingsKey; +import net.snowflake.client.core.HttpProtocol; import net.snowflake.client.core.HttpUtil; import net.snowflake.client.core.SFSession; import net.snowflake.common.core.SqlState; @@ -600,7 +600,7 @@ public void testSetJVMProxyHttp() throws SQLException { "jdbc:snowflake://s3testaccount.us-east-1.snowflakecomputing.com", props); SFSession sfSession = con.unwrap(SnowflakeConnectionV1.class).getSfSession(); HttpClientSettingsKey clientSettingsKey = sfSession.getHttpClientKey(); - assertEquals(Protocol.HTTP, clientSettingsKey.getProxyProtocol()); + assertEquals(HttpProtocol.HTTP, clientSettingsKey.getProxyHttpProtocol()); con.close(); } @@ -626,7 +626,7 @@ public void testSetJVMProxyHttps() throws SQLException { "jdbc:snowflake://s3testaccount.us-east-1.snowflakecomputing.com", props); SFSession sfSession = con.unwrap(SnowflakeConnectionV1.class).getSfSession(); HttpClientSettingsKey clientSettingsKey = sfSession.getHttpClientKey(); - assertEquals(Protocol.HTTPS, clientSettingsKey.getProxyProtocol()); + assertEquals(HttpProtocol.HTTPS, clientSettingsKey.getProxyHttpProtocol()); con.close(); } @@ -651,7 +651,7 @@ public void testSetJVMProxyDefaultHttps() throws SQLException { "jdbc:snowflake://s3testaccount.us-east-1.snowflakecomputing.com", props); SFSession sfSession = con.unwrap(SnowflakeConnectionV1.class).getSfSession(); HttpClientSettingsKey clientSettingsKey = sfSession.getHttpClientKey(); - assertEquals(Protocol.HTTPS, clientSettingsKey.getProxyProtocol()); + assertEquals(HttpProtocol.HTTPS, clientSettingsKey.getProxyHttpProtocol()); con.close(); }