From ecccc3613f35dc229f9cfbb670bded1c0db6ea30 Mon Sep 17 00:00:00 2001 From: Dominik Przybysz <132913826+sfc-gh-dprzybysz@users.noreply.github.com> Date: Tue, 26 Nov 2024 07:56:29 +0100 Subject: [PATCH 1/3] SNOW-1825712: Update GH actions versions (#1975) --- .github/workflows/build-test.yml | 10 +++++----- .github/workflows/check-style.yml | 2 +- .github/workflows/jira_close.yml | 2 +- .github/workflows/jira_issue.yml | 2 +- .github/workflows/snyk-issue.yml | 2 +- .github/workflows/snyk-pr.yml | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 2607c5d46..ef331f720 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -29,7 +29,7 @@ jobs: name: Build runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Build shell: bash env: @@ -53,7 +53,7 @@ jobs: java-version: ${{ matrix.runConfig.javaVersion }} distribution: 'temurin' cache: maven - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.7' architecture: 'x64' @@ -83,7 +83,7 @@ jobs: java-version: ${{ matrix.runConfig.javaVersion }} distribution: 'temurin' cache: maven - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.7' - name: Install Homebrew Bash @@ -110,7 +110,7 @@ jobs: category: ['TestCategoryResultSet,TestCategoryStatement,TestCategoryLoader', 'TestCategoryOthers', 'TestCategoryArrow,TestCategoryConnection,TestCategoryCore,TestCategoryDiagnostic', 'TestCategoryFips'] additionalMavenProfile: ['', '-Dthin-jar'] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Tests shell: bash env: @@ -132,7 +132,7 @@ jobs: category: ['TestCategoryOthers', 'TestCategoryConnection,TestCategoryStatement', 'TestCategoryCore,TestCategoryLoader,TestCategoryResultSet'] is_old_driver: ['true'] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Tests shell: bash env: diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml index 221651298..d26f41865 100644 --- a/.github/workflows/check-style.yml +++ b/.github/workflows/check-style.yml @@ -9,7 +9,7 @@ jobs: name: Check Style runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Check Style shell: bash run: mvn clean validate --batch-mode --show-version -P check-style diff --git a/.github/workflows/jira_close.yml b/.github/workflows/jira_close.yml index dfcb8bc73..0dacf7fab 100644 --- a/.github/workflows/jira_close.yml +++ b/.github/workflows/jira_close.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: snowflakedb/gh-actions ref: jira_v1 diff --git a/.github/workflows/jira_issue.yml b/.github/workflows/jira_issue.yml index 943ad70aa..92501da8f 100644 --- a/.github/workflows/jira_issue.yml +++ b/.github/workflows/jira_issue.yml @@ -14,7 +14,7 @@ jobs: if: ((github.event_name == 'issue_comment' && github.event.comment.body == 'recreate jira' && github.event.comment.user.login == 'sfc-gh-mkeller') || (github.event_name == 'issues' && github.event.pull_request.user.login != 'whitesource-for-github-com[bot]')) steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: snowflakedb/gh-actions ref: jira_v1 diff --git a/.github/workflows/snyk-issue.yml b/.github/workflows/snyk-issue.yml index 7b58bb12a..1e36dae35 100644 --- a/.github/workflows/snyk-issue.yml +++ b/.github/workflows/snyk-issue.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout action - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: snowflakedb/whitesource-actions token: ${{ secrets.WHITESOURCE_ACTION_TOKEN }} diff --git a/.github/workflows/snyk-pr.yml b/.github/workflows/snyk-pr.yml index 5fc21951b..0c101e391 100644 --- a/.github/workflows/snyk-pr.yml +++ b/.github/workflows/snyk-pr.yml @@ -15,13 +15,13 @@ jobs: if: ${{ github.event.pull_request.user.login == 'sfc-gh-snyk-sca-sa' }} steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.ref }} fetch-depth: 0 - name: checkout action - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: snowflakedb/whitesource-actions token: ${{ secrets.WHITESOURCE_ACTION_TOKEN }} From f1038e6e42918b0bd044662f76be814b7852e473 Mon Sep 17 00:00:00 2001 From: Laurent Goujon Date: Tue, 26 Nov 2024 01:09:03 -0800 Subject: [PATCH 2/3] SNOW-1747516: Fix native libraries relocation (#1927) --- FIPS/pom.xml | 28 ++++++++++++++++++++++++++++ parent-pom.xml | 1 + pom.xml | 28 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/FIPS/pom.xml b/FIPS/pom.xml index 0b874551d..b8efd8c05 100644 --- a/FIPS/pom.xml +++ b/FIPS/pom.xml @@ -510,6 +510,22 @@ io.grpc ${shadeBase}.grpc + + META-INF.native.io_grpc_netty_shaded_netty_tcnative + META-INF.native.${shadeNativeBase}_grpc_netty_shaded_netty_tcnative + + + META-INF.native.libio_grpc_netty_shaded_netty_tcnative + META-INF.native.lib${shadeNativeBase}_grpc_netty_shaded_netty_tcnative + + + META-INF.native.io_grpc_netty_shaded_netty_transport_native_epoll + META-INF.native.${shadeNativeBase}_grpc_netty_shaded_netty_transport_native_epoll + + + META-INF.native.libio_grpc_netty_shaded_netty_transport_native_epoll + META-INF.native.lib${shadeNativeBase}_grpc_netty_shaded_netty_transport_native_epoll + org.checkerframework ${shadeBase}.org.checkerframework @@ -526,6 +542,18 @@ org.conscrypt ${shadeBase}.org.conscrypt + + conscrypt_openjdk_jni + ${shadeNativeBase}_conscrypt_openjdk_jni + + + META-INF.native.conscrypt_openjdk_jni + META-INF.native.${shadeNativeBase}_conscrypt_openjdk_jni + + + META-INF.native.libconscrypt_openjdk_jni + META-INF.native.lib${shadeNativeBase}_conscrypt_openjdk_jni + opencensus ${shadeBase}.opencensus diff --git a/parent-pom.xml b/parent-pom.xml index d69c49cbf..1e5aac29c 100644 --- a/parent-pom.xml +++ b/parent-pom.xml @@ -75,6 +75,7 @@ UTF-8 net/snowflake/client/jdbc/internal net.snowflake.client.jdbc.internal + net_snowflake_client_jdbc_internal 2.0.13 5.1.4 net.snowflake.client.category.AllTestCategory diff --git a/pom.xml b/pom.xml index 45e57505b..0f34e2953 100644 --- a/pom.xml +++ b/pom.xml @@ -943,6 +943,22 @@ io.grpc ${shadeBase}.grpc + + META-INF.native.io_grpc_netty_shaded_netty_tcnative + META-INF.native.${shadeNativeBase}_grpc_netty_shaded_netty_tcnative + + + META-INF.native.libio_grpc_netty_shaded_netty_tcnative + META-INF.native.lib${shadeNativeBase}_grpc_netty_shaded_netty_tcnative + + + META-INF.native.io_grpc_netty_shaded_netty_transport_native_epoll + META-INF.native.${shadeNativeBase}_grpc_netty_shaded_netty_transport_native_epoll + + + META-INF.native.libio_grpc_netty_shaded_netty_transport_native_epoll + META-INF.native.lib${shadeNativeBase}_grpc_netty_shaded_netty_transport_native_epoll + org.checkerframework ${shadeBase}.org.checkerframework @@ -959,6 +975,18 @@ org.conscrypt ${shadeBase}.org.conscrypt + + conscrypt_openjdk_jni + ${shadeNativeBase}_conscrypt_openjdk_jni + + + META-INF.native.conscrypt_openjdk_jni + META-INF.native.${shadeNativeBase}_conscrypt_openjdk_jni + + + META-INF.native.libconscrypt_openjdk_jni + META-INF.native.lib${shadeNativeBase}_conscrypt_openjdk_jni + opencensus ${shadeBase}.opencensus From 7fd70cdc5fbb31798b56b1335de87ed3b56b3725 Mon Sep 17 00:00:00 2001 From: Przemyslaw Motacki Date: Tue, 26 Nov 2024 10:25:02 +0100 Subject: [PATCH 3/3] SNOW-1689931 Adding flag to skip token file permission verification (#1959) --- .../config/SFConnectionConfigParser.java | 86 +++++++++++-------- .../snowflake/client/jdbc/SnowflakeUtil.java | 16 ++++ .../config/SFConnectionConfigParserTest.java | 69 ++++++++++++++- 3 files changed, 132 insertions(+), 39 deletions(-) diff --git a/src/main/java/net/snowflake/client/config/SFConnectionConfigParser.java b/src/main/java/net/snowflake/client/config/SFConnectionConfigParser.java index 35698c557..1da9f766a 100644 --- a/src/main/java/net/snowflake/client/config/SFConnectionConfigParser.java +++ b/src/main/java/net/snowflake/client/config/SFConnectionConfigParser.java @@ -1,5 +1,6 @@ package net.snowflake.client.config; +import static net.snowflake.client.jdbc.SnowflakeUtil.convertSystemGetEnvToBooleanValue; import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetEnv; import com.fasterxml.jackson.dataformat.toml.TomlMapper; @@ -34,6 +35,53 @@ public class SFConnectionConfigParser { "SNOWFLAKE_DEFAULT_CONNECTION_NAME"; public static final String DEFAULT = "default"; public static final String SNOWFLAKE_TOKEN_FILE_PATH = "/snowflake/session/token"; + public static final String SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION = + "SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION"; + + public static ConnectionParameters buildConnectionParameters() throws SnowflakeSQLException { + String defaultConnectionName = + Optional.ofNullable(systemGetEnv(SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY)).orElse(DEFAULT); + Map fileConnectionConfiguration = + loadDefaultConnectionConfiguration(defaultConnectionName); + + if (fileConnectionConfiguration != null && !fileConnectionConfiguration.isEmpty()) { + Properties connectionProperties = new Properties(); + connectionProperties.putAll(fileConnectionConfiguration); + + String url = createUrl(fileConnectionConfiguration); + logger.debug("Url created using parameters from connection configuration file: {}", url); + + if ("oauth".equals(fileConnectionConfiguration.get("authenticator")) + && fileConnectionConfiguration.get("token") == null) { + Path path = + Paths.get( + Optional.ofNullable(fileConnectionConfiguration.get("token_file_path")) + .orElse(SNOWFLAKE_TOKEN_FILE_PATH)); + logger.debug("Token used in connect is read from file: {}", path); + try { + boolean shouldSkipTokenFilePermissionsVerification = + convertSystemGetEnvToBooleanValue(SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION, false); + if (!shouldSkipTokenFilePermissionsVerification) { + verifyFilePermissionSecure(path); + } else { + logger.debug("Skip token file permissions verification"); + } + String token = new String(Files.readAllBytes(path), Charset.defaultCharset()); + if (!token.isEmpty()) { + putPropertyIfNotNull(connectionProperties, "token", token.trim()); + } else { + throw new SnowflakeSQLException( + "Non-empty token must be set when the authenticator type is OAUTH"); + } + } catch (Exception ex) { + throw new SnowflakeSQLException(ex, "There is a problem during reading token from file"); + } + } + return new ConnectionParameters(url, connectionProperties); + } else { + return null; + } + } private static Map loadDefaultConnectionConfiguration( String defaultConnectionName) throws SnowflakeSQLException { @@ -88,44 +136,6 @@ private static void verifyFilePermissionSecure(Path configFilePath) } } - public static ConnectionParameters buildConnectionParameters() throws SnowflakeSQLException { - String defaultConnectionName = - Optional.ofNullable(systemGetEnv(SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY)).orElse(DEFAULT); - Map fileConnectionConfiguration = - loadDefaultConnectionConfiguration(defaultConnectionName); - - if (fileConnectionConfiguration != null && !fileConnectionConfiguration.isEmpty()) { - Properties conectionProperties = new Properties(); - conectionProperties.putAll(fileConnectionConfiguration); - - String url = createUrl(fileConnectionConfiguration); - logger.debug("Url created using parameters from connection configuration file: {}", url); - - if ("oauth".equals(fileConnectionConfiguration.get("authenticator")) - && fileConnectionConfiguration.get("token") == null) { - Path path = - Paths.get( - Optional.ofNullable(fileConnectionConfiguration.get("token_file_path")) - .orElse(SNOWFLAKE_TOKEN_FILE_PATH)); - logger.debug("Token used in connect is read from file: {}", path); - try { - verifyFilePermissionSecure(path); - String token = new String(Files.readAllBytes(path), Charset.defaultCharset()); - if (!token.isEmpty()) { - putPropertyIfNotNull(conectionProperties, "token", token.trim()); - } else { - logger.warn("The token has empty value"); - } - } catch (Exception ex) { - throw new SnowflakeSQLException(ex, "There is a problem during reading token from file"); - } - } - return new ConnectionParameters(url, conectionProperties); - } else { - return null; - } - } - private static String createUrl(Map fileConnectionConfiguration) throws SnowflakeSQLException { Optional maybeAccount = Optional.ofNullable(fileConnectionConfiguration.get("account")); diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java index 635384972..8e9a683a0 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java @@ -837,6 +837,22 @@ public static boolean convertSystemPropertyToBooleanValue( } return defaultValue; } + /** + * Helper function to convert environment variable to boolean + * + * @param envVariableKey property name of the environment variable + * @param defaultValue default value used + * @return the value of the environment variable as boolean, else the default value + */ + @SnowflakeJdbcInternalApi + public static boolean convertSystemGetEnvToBooleanValue( + String envVariableKey, boolean defaultValue) { + String environmentVariableValue = systemGetEnv(envVariableKey); + if (environmentVariableValue != null) { + return Boolean.parseBoolean(environmentVariableValue); + } + return defaultValue; + } @SnowflakeJdbcInternalApi public static T mapSFExceptionToSQLException(ThrowingCallable action) diff --git a/src/test/java/net/snowflake/client/config/SFConnectionConfigParserTest.java b/src/test/java/net/snowflake/client/config/SFConnectionConfigParserTest.java index 01da714e5..bfb30f645 100644 --- a/src/test/java/net/snowflake/client/config/SFConnectionConfigParserTest.java +++ b/src/test/java/net/snowflake/client/config/SFConnectionConfigParserTest.java @@ -1,5 +1,6 @@ package net.snowflake.client.config; +import static net.snowflake.client.config.SFConnectionConfigParser.SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION; import static net.snowflake.client.config.SFConnectionConfigParser.SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY; import static net.snowflake.client.config.SFConnectionConfigParser.SNOWFLAKE_HOME_KEY; import static org.junit.Assert.assertEquals; @@ -17,8 +18,11 @@ import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import net.snowflake.client.RunningNotOnLinuxMac; @@ -32,20 +36,36 @@ public class SFConnectionConfigParserTest { + private static final List ENV_VARIABLES_KEYS = + new ArrayList<>( + Arrays.asList( + SNOWFLAKE_HOME_KEY, + SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY, + SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION)); private Path tempPath = null; private TomlMapper tomlMapper = new TomlMapper(); + private Map envVariables = new HashMap(); @Before public void setUp() throws IOException { tempPath = Files.createTempDirectory(".snowflake"); + ENV_VARIABLES_KEYS.stream() + .forEach( + key -> { + if (SnowflakeUtil.systemGetEnv(key) != null) { + envVariables.put(key, SnowflakeUtil.systemGetEnv(key)); + } + }); } @After public void close() throws IOException { SnowflakeUtil.systemUnsetEnv(SNOWFLAKE_HOME_KEY); SnowflakeUtil.systemUnsetEnv(SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY); + SnowflakeUtil.systemUnsetEnv(SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION); Files.walk(tempPath).map(Path::toFile).forEach(File::delete); Files.delete(tempPath); + envVariables.forEach((key, value) -> SnowflakeUtil.systemSetEnv(key, value)); } @Test @@ -103,6 +123,21 @@ public void testThrowErrorWhenWrongPermissionsForTokenFile() throws IOException SnowflakeSQLException.class, () -> SFConnectionConfigParser.buildConnectionParameters()); } + @Test + public void testNoThrowErrorWhenWrongPermissionsForTokenFileButSkippingFlagIsEnabled() + throws SnowflakeSQLException, IOException { + SnowflakeUtil.systemSetEnv(SNOWFLAKE_HOME_KEY, tempPath.toString()); + SnowflakeUtil.systemSetEnv(SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY, "default"); + SnowflakeUtil.systemSetEnv(SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION, "true"); + File tokenFile = new File(Paths.get(tempPath.toString(), "token").toUri()); + prepareConnectionConfigurationTomlFile( + Collections.singletonMap("token_file_path", tokenFile.toString()), true, false); + + ConnectionParameters data = SFConnectionConfigParser.buildConnectionParameters(); + assertNotNull(data); + assertEquals(tokenFile.toString(), data.getParams().get("token_file_path")); + } + @Test public void testLoadSFConnectionConfigWithHostConfigured() throws SnowflakeSQLException, IOException { @@ -133,6 +168,19 @@ public void shouldThrowExceptionIfNoneOfHostAndAccountIsSet() throws IOException SnowflakeSQLException.class, () -> SFConnectionConfigParser.buildConnectionParameters()); } + @Test + public void shouldThrowExceptionIfTokenIsNotSetForOauth() throws IOException { + SnowflakeUtil.systemSetEnv(SNOWFLAKE_HOME_KEY, tempPath.toString()); + SnowflakeUtil.systemSetEnv(SNOWFLAKE_DEFAULT_CONNECTION_NAME_KEY, "default"); + SnowflakeUtil.systemSetEnv(SKIP_TOKEN_FILE_PERMISSIONS_VERIFICATION, "true"); + File tokenFile = new File(Paths.get(tempPath.toString(), "token").toUri()); + prepareConnectionConfigurationTomlFile( + Collections.singletonMap("token_file_path", tokenFile.toString()), true, false, ""); + + Assert.assertThrows( + SnowflakeSQLException.class, () -> SFConnectionConfigParser.buildConnectionParameters()); + } + private void prepareConnectionConfigurationTomlFile() throws IOException { prepareConnectionConfigurationTomlFile(null, true, true); } @@ -144,6 +192,16 @@ private void prepareConnectionConfigurationTomlFile(Map moreParameters) throws I private void prepareConnectionConfigurationTomlFile( Map moreParameters, boolean onlyUserPermissionConnection, boolean onlyUserPermissionToken) throws IOException { + prepareConnectionConfigurationTomlFile( + moreParameters, onlyUserPermissionConnection, onlyUserPermissionToken, "token_from_file"); + } + + private void prepareConnectionConfigurationTomlFile( + Map moreParameters, + boolean onlyUserPermissionConnection, + boolean onlyUserPermissionToken, + String token) + throws IOException { Path path = Paths.get(tempPath.toString(), "connections.toml"); Path filePath = createFilePathWithPermission(path, onlyUserPermissionConnection); File file = filePath.toFile(); @@ -166,7 +224,16 @@ private void prepareConnectionConfigurationTomlFile( createFilePathWithPermission( Paths.get(configurationParams.get("token_file_path").toString()), onlyUserPermissionToken); - Files.write(tokenFilePath, "token_from_file".getBytes()); + Files.write(tokenFilePath, token.getBytes()); + Path emptyTokenFilePath = + createFilePathWithPermission( + Paths.get( + configurationParams + .get("token_file_path") + .toString() + .replaceAll("token", "emptytoken")), + onlyUserPermissionToken); + Files.write(emptyTokenFilePath, "".getBytes()); } }