diff --git a/src/main/java/net/snowflake/client/core/SFLoginInput.java b/src/main/java/net/snowflake/client/core/SFLoginInput.java index 35df50a7c..148aa3658 100644 --- a/src/main/java/net/snowflake/client/core/SFLoginInput.java +++ b/src/main/java/net/snowflake/client/core/SFLoginInput.java @@ -49,6 +49,8 @@ public class SFLoginInput { private String privateKeyFilePwd; private String inFlightCtx; // Opaque string sent for Snowsight account activation + private boolean disableConsoleLogin = true; + // Additional headers to add for Snowsight. Map additionalHttpHeadersForSnowsight; @@ -63,6 +65,15 @@ SFLoginInput setServerUrl(String serverUrl) { return this; } + public boolean getDisableConsoleLogin() { + return disableConsoleLogin; + } + + SFLoginInput setDisableConsoleLogin(boolean disableConsoleLogin) { + this.disableConsoleLogin = disableConsoleLogin; + return this; + } + String getDatabaseName() { return databaseName; } diff --git a/src/main/java/net/snowflake/client/core/SFSession.java b/src/main/java/net/snowflake/client/core/SFSession.java index c85aa30a8..c8c4ad21e 100644 --- a/src/main/java/net/snowflake/client/core/SFSession.java +++ b/src/main/java/net/snowflake/client/core/SFSession.java @@ -483,7 +483,12 @@ public synchronized void open() throws SFException, SnowflakeSQLException { .setApplication((String) connectionPropertiesMap.get(SFSessionProperty.APPLICATION)) .setServiceName(getServiceName()) .setOCSPMode(getOCSPMode()) - .setHttpClientSettingsKey(httpClientSettingsKey); + .setHttpClientSettingsKey(httpClientSettingsKey) + .setDisableConsoleLogin( + connectionPropertiesMap.get(SFSessionProperty.DISABLE_CONSOLE_LOGIN) != null + ? getBooleanValue( + connectionPropertiesMap.get(SFSessionProperty.DISABLE_CONSOLE_LOGIN)) + : true); // Enable or disable OOB telemetry based on connection parameter. Default is disabled. // The value may still change later when session parameters from the server are read. diff --git a/src/main/java/net/snowflake/client/core/SFSessionProperty.java b/src/main/java/net/snowflake/client/core/SFSessionProperty.java index 48f80db72..686b02d19 100644 --- a/src/main/java/net/snowflake/client/core/SFSessionProperty.java +++ b/src/main/java/net/snowflake/client/core/SFSessionProperty.java @@ -71,6 +71,8 @@ public enum SFSessionProperty { MAX_HTTP_RETRIES("maxHttpRetries", false, Integer.class), + DISABLE_CONSOLE_LOGIN("disableConsoleLogin", false, Boolean.class), + PUT_GET_MAX_RETRIES("putGetMaxRetries", false, Integer.class); // property key in string diff --git a/src/main/java/net/snowflake/client/core/SessionUtil.java b/src/main/java/net/snowflake/client/core/SessionUtil.java index c4a3ead7a..9646e2690 100644 --- a/src/main/java/net/snowflake/client/core/SessionUtil.java +++ b/src/main/java/net/snowflake/client/core/SessionUtil.java @@ -54,6 +54,7 @@ public class SessionUtil { private static final String SF_PATH_LOGIN_REQUEST = "/session/v1/login-request"; private static final String SF_PATH_TOKEN_REQUEST = "/session/token-request"; public static final String SF_PATH_AUTHENTICATOR_REQUEST = "/session/authenticator-request"; + public static final String SF_PATH_CONSOLE_LOGIN_REQUEST = "/console/login"; public static final String SF_QUERY_SESSION_DELETE = "delete"; diff --git a/src/main/java/net/snowflake/client/core/SessionUtilExternalBrowser.java b/src/main/java/net/snowflake/client/core/SessionUtilExternalBrowser.java index b18d1ebcb..e3eabd2c2 100644 --- a/src/main/java/net/snowflake/client/core/SessionUtilExternalBrowser.java +++ b/src/main/java/net/snowflake/client/core/SessionUtilExternalBrowser.java @@ -215,6 +215,22 @@ private String getSSOUrl(int port) throws SFException, SnowflakeSQLException { } } + private String getConsoleLoginUrl(int port) throws SFException { + try { + String serverUrl = loginInput.getServerUrl(); + String consoleLoginUrl = serverUrl; + consoleLoginUrl += SessionUtil.SF_PATH_CONSOLE_LOGIN_REQUEST; + consoleLoginUrl += "?login_name=" + loginInput.getUserName(); + consoleLoginUrl += "&client_port=" + port; + + logger.debug("console login url: {}", consoleLoginUrl); + + return consoleLoginUrl; + } catch (Exception ex) { + throw new SFException(ex, ErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + } + /** * Authenticate * @@ -227,13 +243,26 @@ void authenticate() throws SFException, SnowflakeSQLException { // main procedure int port = this.getLocalPort(ssocket); logger.debug("Listening localhost:{}", port); - String ssoUrl = getSSOUrl(port); - this.handlers.output( - "Initiating login request with your identity provider. A " - + "browser window should have opened for you to complete the " - + "login. If you can't see it, check existing browser windows, " - + "or your OS settings. Press CTRL+C to abort and try again..."); - this.handlers.openBrowser(ssoUrl); + + if (loginInput.getDisableConsoleLogin()) { + // Access GS to get SSO URL + String ssoUrl = getSSOUrl(port); + this.handlers.output( + "Initiating login request with your identity provider. A " + + "browser window should have opened for you to complete the " + + "login. If you can't see it, check existing browser windows, " + + "or your OS settings. Press CTRL+C to abort and try again..."); + this.handlers.openBrowser(ssoUrl); + } else { + // Multiple SAML way to do authentication via console login + String consoleLoginUrl = getConsoleLoginUrl(port); + this.handlers.output( + "Initiating login request with your identity provider(s). A " + + "browser window should have opened for you to complete the " + + "login. If you can't see it, check existing browser windows, " + + "or your OS settings. Press CTRL+C to abort and try again..."); + this.handlers.openBrowser(consoleLoginUrl); + } while (true) { Socket socket = ssocket.accept(); // start accepting the request diff --git a/src/test/java/net/snowflake/client/core/SessionUtilExternalBrowserTest.java b/src/test/java/net/snowflake/client/core/SessionUtilExternalBrowserTest.java index 6b0d15c24..0092b925f 100644 --- a/src/test/java/net/snowflake/client/core/SessionUtilExternalBrowserTest.java +++ b/src/test/java/net/snowflake/client/core/SessionUtilExternalBrowserTest.java @@ -229,6 +229,7 @@ private SFLoginInput initMockLoginInput() { .thenReturn(ClientAuthnDTO.AuthenticatorType.EXTERNALBROWSER.name()); when(loginInput.getAccountName()).thenReturn("testaccount"); when(loginInput.getUserName()).thenReturn("testuser"); + when(loginInput.getDisableConsoleLogin()).thenReturn(true); return loginInput; } } diff --git a/src/test/java/net/snowflake/client/jdbc/SSOConnectionTest.java b/src/test/java/net/snowflake/client/jdbc/SSOConnectionTest.java index 22e846e5b..6a945fcc9 100644 --- a/src/test/java/net/snowflake/client/jdbc/SSOConnectionTest.java +++ b/src/test/java/net/snowflake/client/jdbc/SSOConnectionTest.java @@ -288,6 +288,7 @@ private SFLoginInput initMockLoginInput() { .thenReturn(ClientAuthnDTO.AuthenticatorType.EXTERNALBROWSER.name()); when(loginInput.getAccountName()).thenReturn("testaccount"); when(loginInput.getUserName()).thenReturn("testuser"); + when(loginInput.getDisableConsoleLogin()).thenReturn(true); return loginInput; }