-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into SNOW-1848734-prevent-unnecessary-string-cr…
…eation-in-structured-types-get-object
- Loading branch information
Showing
13 changed files
with
379 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#!/bin/bash -e | ||
|
||
set -o pipefail | ||
|
||
export WORKSPACE=${WORKSPACE:-/mnt/workspace} | ||
export SOURCE_ROOT=${SOURCE_ROOT:-/mnt/host} | ||
MVNW_EXE=$SOURCE_ROOT/mvnw | ||
|
||
AUTH_PARAMETER_FILE=./.github/workflows/parameters_aws_auth_tests.json | ||
eval $(jq -r '.authtestparams | to_entries | map("export \(.key)=\(.value|tostring)")|.[]' $AUTH_PARAMETER_FILE) | ||
|
||
$MVNW_EXE -DjenkinsIT \ | ||
-Djava.io.tmpdir=$WORKSPACE \ | ||
-Djacoco.skip.instrument=true \ | ||
-Dskip.unitTests=true \ | ||
-DintegrationTestSuites=AuthenticationTestSuite \ | ||
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \ | ||
-Dnot-self-contained-jar \ | ||
verify \ | ||
--batch-mode --show-version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/bin/bash -e | ||
|
||
set -o pipefail | ||
THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
export WORKSPACE=${WORKSPACE:-/tmp} | ||
export INTERNAL_REPO=nexus.int.snowflakecomputing.com:8086 | ||
|
||
source $THIS_DIR/scripts/login_internal_docker.sh | ||
gpg --quiet --batch --yes --decrypt --passphrase="$PARAMETERS_SECRET" --output $THIS_DIR/../.github/workflows/parameters_aws_auth_tests.json "$THIS_DIR/../.github/workflows/parameters_aws_auth_tests.json.gpg" | ||
|
||
docker run \ | ||
-v $(cd $THIS_DIR/.. && pwd):/mnt/host \ | ||
-v $WORKSPACE:/mnt/workspace \ | ||
--rm \ | ||
nexus.int.snowflakecomputing.com:8086/docker/snowdrivers-test-external-browser-jdbc:1 \ | ||
"/mnt/host/ci/container/test_authentication.sh" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
src/test/java/net/snowflake/client/authentication/AuthConnectionParameters.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package net.snowflake.client.authentication; | ||
|
||
import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetEnv; | ||
|
||
import java.util.Properties; | ||
|
||
public class AuthConnectionParameters { | ||
|
||
static final String SSO_USER = systemGetEnv("SNOWFLAKE_AUTH_TEST_BROWSER_USER"); | ||
static final String HOST = systemGetEnv("SNOWFLAKE_AUTH_TEST_HOST"); | ||
static final String SSO_PASSWORD = systemGetEnv("SNOWFLAKE_AUTH_TEST_OKTA_PASS"); | ||
|
||
static Properties getBaseConnectionParameters() { | ||
Properties properties = new Properties(); | ||
properties.put("host", HOST); | ||
properties.put("port", systemGetEnv("SNOWFLAKE_AUTH_TEST_PORT")); | ||
properties.put("role", systemGetEnv("SNOWFLAKE_AUTH_TEST_ROLE")); | ||
properties.put("account", systemGetEnv("SNOWFLAKE_AUTH_TEST_ACCOUNT")); | ||
properties.put("db", systemGetEnv("SNOWFLAKE_AUTH_TEST_DATABASE")); | ||
properties.put("schema", systemGetEnv("SNOWFLAKE_AUTH_TEST_SCHEMA")); | ||
properties.put("warehouse", systemGetEnv("SNOWFLAKE_AUTH_TEST_WAREHOUSE")); | ||
return properties; | ||
} | ||
|
||
static Properties getExternalBrowserConnectionParameters() { | ||
Properties properties = getBaseConnectionParameters(); | ||
properties.put("user", SSO_USER); | ||
properties.put("authenticator", "externalbrowser"); | ||
return properties; | ||
} | ||
|
||
static Properties getStoreIDTokenConnectionParameters() { | ||
Properties properties = getExternalBrowserConnectionParameters(); | ||
properties.put("CLIENT_STORE_TEMPORARY_CREDENTIAL", true); | ||
return properties; | ||
} | ||
} |
114 changes: 114 additions & 0 deletions
114
src/test/java/net/snowflake/client/authentication/AuthTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package net.snowflake.client.authentication; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.CoreMatchers.nullValue; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import java.io.IOException; | ||
import java.sql.Connection; | ||
import java.sql.DriverManager; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.sql.Statement; | ||
import java.util.Properties; | ||
import java.util.concurrent.TimeUnit; | ||
import net.snowflake.client.core.SessionUtil; | ||
import net.snowflake.client.jdbc.SnowflakeConnectionV1; | ||
import net.snowflake.client.jdbc.SnowflakeSQLException; | ||
|
||
public class AuthTest { | ||
|
||
private Exception exception; | ||
private String idToken; | ||
private final boolean runAuthTestsManually; | ||
|
||
public AuthTest() { | ||
this.runAuthTestsManually = Boolean.parseBoolean(System.getenv("RUN_AUTH_TESTS_MANUALLY")); | ||
} | ||
|
||
public Thread getConnectAndExecuteSimpleQueryThread(Properties props, String sessionParameters) { | ||
return new Thread(() -> connectAndExecuteSimpleQuery(props, sessionParameters)); | ||
} | ||
|
||
public Thread getConnectAndExecuteSimpleQueryThread(Properties props) { | ||
return new Thread(() -> connectAndExecuteSimpleQuery(props, null)); | ||
} | ||
|
||
public void verifyExceptionIsThrown(String message) { | ||
assertThat("Expected exception not thrown", this.exception.getMessage(), is(message)); | ||
} | ||
|
||
public void verifyExceptionIsNotThrown() { | ||
assertThat("Unexpected exception thrown", this.exception, nullValue()); | ||
} | ||
|
||
public void connectAndProvideCredentials(Thread provideCredentialsThread, Thread connectThread) | ||
throws InterruptedException { | ||
if (runAuthTestsManually) { | ||
connectThread.start(); | ||
connectThread.join(); | ||
} else { | ||
provideCredentialsThread.start(); | ||
connectThread.start(); | ||
provideCredentialsThread.join(); | ||
connectThread.join(); | ||
} | ||
} | ||
|
||
public void provideCredentials(String scenario, String login, String password) { | ||
try { | ||
String provideBrowserCredentialsPath = "/externalbrowser/provideBrowserCredentials.js"; | ||
ProcessBuilder processBuilder = | ||
new ProcessBuilder("node", provideBrowserCredentialsPath, scenario, login, password); | ||
Process process = processBuilder.start(); | ||
process.waitFor(15, TimeUnit.SECONDS); | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
public void cleanBrowserProcesses() { | ||
if (!runAuthTestsManually) { | ||
String cleanBrowserProcessesPath = "/externalbrowser/cleanBrowserProcesses.js"; | ||
ProcessBuilder processBuilder = new ProcessBuilder("node", cleanBrowserProcessesPath); | ||
try { | ||
Process process = processBuilder.start(); | ||
process.waitFor(15, TimeUnit.SECONDS); | ||
} catch (InterruptedException | IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
|
||
public static void deleteIdToken() { | ||
SessionUtil.deleteIdTokenCache( | ||
AuthConnectionParameters.HOST, AuthConnectionParameters.SSO_USER); | ||
} | ||
|
||
public void connectAndExecuteSimpleQuery(Properties props, String sessionParameters) { | ||
String url = String.format("jdbc:snowflake://%s:%s", props.get("host"), props.get("port")); | ||
if (sessionParameters != null) { | ||
url += "?" + sessionParameters; | ||
} | ||
try (Connection con = DriverManager.getConnection(url, props); | ||
Statement stmt = con.createStatement(); | ||
ResultSet rs = stmt.executeQuery("select 1")) { | ||
assertTrue(rs.next()); | ||
assertEquals(1, rs.getInt(1)); | ||
saveToken(con); | ||
} catch (SQLException e) { | ||
this.exception = e; | ||
} | ||
} | ||
|
||
private void saveToken(Connection con) throws SnowflakeSQLException { | ||
SnowflakeConnectionV1 sfcon = (SnowflakeConnectionV1) con; | ||
this.idToken = sfcon.getSfSession().getIdToken(); | ||
} | ||
|
||
public String getIdToken() { | ||
return idToken; | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
src/test/java/net/snowflake/client/authentication/ExternalBrowserIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package net.snowflake.client.authentication; | ||
|
||
import static net.snowflake.client.authentication.AuthConnectionParameters.getExternalBrowserConnectionParameters; | ||
|
||
import java.io.IOException; | ||
import java.util.Properties; | ||
import net.snowflake.client.category.TestTags; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Tag; | ||
import org.junit.jupiter.api.Test; | ||
|
||
@Tag(TestTags.AUTHENTICATION) | ||
class ExternalBrowserIT { | ||
|
||
String login = AuthConnectionParameters.SSO_USER; | ||
String password = AuthConnectionParameters.SSO_PASSWORD; | ||
AuthTest authTest = new AuthTest(); | ||
|
||
@BeforeEach | ||
public void setUp() throws IOException { | ||
AuthTest.deleteIdToken(); | ||
} | ||
|
||
@AfterEach | ||
public void tearDown() { | ||
authTest.cleanBrowserProcesses(); | ||
AuthTest.deleteIdToken(); | ||
} | ||
|
||
@Test | ||
void shouldAuthenticateUsingExternalBrowser() throws InterruptedException { | ||
Thread provideCredentialsThread = | ||
new Thread(() -> authTest.provideCredentials("success", login, password)); | ||
Thread connectThread = | ||
authTest.getConnectAndExecuteSimpleQueryThread(getExternalBrowserConnectionParameters()); | ||
|
||
authTest.connectAndProvideCredentials(provideCredentialsThread, connectThread); | ||
authTest.verifyExceptionIsNotThrown(); | ||
} | ||
|
||
@Test | ||
void shouldThrowErrorForMismatchedUsername() throws InterruptedException { | ||
Properties properties = getExternalBrowserConnectionParameters(); | ||
properties.put("user", "differentUsername"); | ||
Thread provideCredentialsThread = | ||
new Thread(() -> authTest.provideCredentials("success", login, password)); | ||
Thread connectThread = authTest.getConnectAndExecuteSimpleQueryThread(properties); | ||
|
||
authTest.connectAndProvideCredentials(provideCredentialsThread, connectThread); | ||
authTest.verifyExceptionIsThrown( | ||
"The user you were trying to authenticate as differs from the user currently logged in at the IDP."); | ||
} | ||
|
||
@Test | ||
void shouldThrowErrorForWrongCredentials() throws InterruptedException { | ||
String login = "itsnotanaccount.com"; | ||
String password = "fakepassword"; | ||
Thread provideCredentialsThread = | ||
new Thread(() -> authTest.provideCredentials("fail", login, password)); | ||
Thread connectThread = | ||
authTest.getConnectAndExecuteSimpleQueryThread( | ||
getExternalBrowserConnectionParameters(), "BROWSER_RESPONSE_TIMEOUT=10"); | ||
|
||
authTest.connectAndProvideCredentials(provideCredentialsThread, connectThread); | ||
authTest.verifyExceptionIsThrown( | ||
"JDBC driver encountered communication error. Message: External browser authentication failed within timeout of 10000 milliseconds."); | ||
} | ||
|
||
@Test | ||
void shouldThrowErrorForBrowserTimeout() throws InterruptedException { | ||
Thread provideCredentialsThread = | ||
new Thread(() -> authTest.provideCredentials("timeout", login, password)); | ||
Thread connectThread = | ||
authTest.getConnectAndExecuteSimpleQueryThread( | ||
getExternalBrowserConnectionParameters(), "BROWSER_RESPONSE_TIMEOUT=1"); | ||
|
||
authTest.connectAndProvideCredentials(provideCredentialsThread, connectThread); | ||
authTest.verifyExceptionIsThrown( | ||
"JDBC driver encountered communication error. Message: External browser authentication failed within timeout of 1000 milliseconds."); | ||
} | ||
} |
Oops, something went wrong.