From 446603131e86bea55525799b96ade3c848fa4b5d Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Fri, 4 Jul 2025 09:38:16 +0000 Subject: [PATCH 1/4] Pass Account Id to OAuthClient in External Browser Authentication. --- .../core/oauth/ExternalBrowserCredentialsProvider.java | 1 + .../java/com/databricks/sdk/core/oauth/OAuthClient.java | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProvider.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProvider.java index 3708887ef..70b7e1e21 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProvider.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProvider.java @@ -112,6 +112,7 @@ CachedTokenSource performBrowserAuth( .withClientId(clientId) .withClientSecret(clientSecret) .withHost(config.getHost()) + .withAccountId(config.getAccountId()) .withRedirectUrl(config.getEffectiveOAuthRedirectUrl()) .withScopes(config.getScopes()) .build(); diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java index cf65ba71a..4ac3030cf 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java @@ -35,7 +35,7 @@ public static class Builder { private List scopes; private String clientSecret; private HttpClient hc; - + private String accountId; public Builder() {} public Builder withHttpClient(HttpClient hc) { @@ -71,6 +71,11 @@ public Builder withScopes(List scopes) { public OAuthClient build() throws IOException { return new OAuthClient(this); } + + public Builder withAccountId(String accountId) { + this.accountId = accountId; + return this; + } } private final String clientId; @@ -92,7 +97,7 @@ private OAuthClient(Builder b) throws IOException { this.host = b.host; this.hc = b.hc; - DatabricksConfig config = new DatabricksConfig().setHost(b.host).resolve(); + DatabricksConfig config = new DatabricksConfig().setHost(b.host).setAccountId(b.accountId).resolve(); OpenIDConnectEndpoints oidc = config.getOidcEndpoints(); if (oidc == null) { throw new DatabricksException(b.host + " does not support OAuth"); From 67ff1fd2ec0ea3cbefb41e32f871df30baf84bc6 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Fri, 4 Jul 2025 09:45:17 +0000 Subject: [PATCH 2/4] update --- .../main/java/com/databricks/sdk/core/oauth/OAuthClient.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java index 4ac3030cf..139031c8c 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/OAuthClient.java @@ -36,6 +36,7 @@ public static class Builder { private String clientSecret; private HttpClient hc; private String accountId; + public Builder() {} public Builder withHttpClient(HttpClient hc) { @@ -97,7 +98,8 @@ private OAuthClient(Builder b) throws IOException { this.host = b.host; this.hc = b.hc; - DatabricksConfig config = new DatabricksConfig().setHost(b.host).setAccountId(b.accountId).resolve(); + DatabricksConfig config = + new DatabricksConfig().setHost(b.host).setAccountId(b.accountId).resolve(); OpenIDConnectEndpoints oidc = config.getOidcEndpoints(); if (oidc == null) { throw new DatabricksException(b.host + " does not support OAuth"); From ed861181fdb59a3762b8541383e6f91b3d0a99c9 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Fri, 4 Jul 2025 10:58:44 +0000 Subject: [PATCH 3/4] update --- .../sdk/core/oauth/OAuthClientTest.java | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java new file mode 100644 index 000000000..213da780a --- /dev/null +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java @@ -0,0 +1,121 @@ +package com.databricks.sdk.core.oauth; + +import static org.junit.jupiter.api.Assertions.*; + +import com.databricks.sdk.core.FixtureServer; +import com.databricks.sdk.core.commons.CommonsHttpClient; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class OAuthClientTest { + + @ParameterizedTest(name = "{0}") + @MethodSource("provideBuilderTestCases") + void testOAuthClientBuilder( + String displayName, + String clientId, + String clientSecret, + String host, + String redirectUrl, + List scopes, + String accountId, + String expectedTokenUrl, + String expectedAuthUrl) + throws IOException { + + FixtureServer.FixtureMapping fixture = + new FixtureServer.FixtureMapping.Builder() + .validateMethod("GET") + .validatePath("/oidc/.well-known/oauth-authorization-server") + .withResponse( + "{\"token_endpoint\": \"" + + expectedTokenUrl + + "\", \"authorization_endpoint\": \"" + + expectedAuthUrl + + "\"}", + 200) + .build(); + + try (FixtureServer fixtures = new FixtureServer()) { + fixtures.with(fixture); + + OAuthClient.Builder builder = + new OAuthClient.Builder() + .withHttpClient(new CommonsHttpClient.Builder().withTimeoutSeconds(30).build()) + .withClientId(clientId) + .withClientSecret(clientSecret) + .withHost(fixtures.getUrl()) + .withRedirectUrl(redirectUrl) + .withScopes(scopes); + if (accountId != null) { + builder.withAccountId(accountId); + } + OAuthClient client = builder.build(); + + // Verify builder properties. + assertEquals(clientId, client.getClientId()); + assertEquals(clientSecret, client.getClientSecret()); + assertEquals(fixtures.getUrl(), client.getHost()); + assertEquals(redirectUrl, client.getRedirectUrl()); + assertEquals(expectedTokenUrl, client.getTokenUrl()); + assertEquals(expectedAuthUrl, client.getAuthUrl()); + + // Handle scopes - if null was passed, OAuthClient uses default scopes. + if (scopes == null) { + List defaultScopes = Arrays.asList("offline_access", "clusters", "sql"); + assertEquals(defaultScopes, client.getScopes()); + } else { + assertEquals(scopes, client.getScopes()); + } + } + } + + static Stream provideBuilderTestCases() { + return Stream.of( + Arguments.of( + "Basic host + scopes", + "test-client-1", + "test-secret-1", + "https://test1.databricks.com", + "http://localhost:8080/callback", + Arrays.asList("clusters", "sql"), + null, + "https://test1.databricks.com/oidc/token", + "https://test1.databricks.com/oidc/authorize"), + Arguments.of( + "Null client secret", + "test-client-2", + null, + "https://test2.databricks.com", + "http://localhost:9000/callback", + Arrays.asList("sql", "jobs"), + null, + "https://test2.databricks.com/oidc/token", + "https://test2.databricks.com/oidc/authorize"), + Arguments.of( + "Default scopes", + "test-client-3", + "test-secret-3", + "https://test3.databricks.com", + "http://localhost:7000/callback", + null, // Will use default scopes + null, + "https://test3.databricks.com/oidc/token", + "https://test3.databricks.com/oidc/authorize"), + Arguments.of( + "Accounts host with accountId", + "account-client", + "account-secret", + "https://accounts.cloud.databricks.com", + "http://localhost:8081/callback", + Arrays.asList("clusters"), + "my-account-id", + "https://accounts.cloud.databricks.com/oidc/accounts/my-account-id/v1/token", + "https://accounts.cloud.databricks.com/oidc/accounts/my-account-id/v1/authorize")); + } +} From 99adb729a361aab4f84d510e21138d0dc2309b43 Mon Sep 17 00:00:00 2001 From: Parth Bansal Date: Fri, 4 Jul 2025 12:34:36 +0000 Subject: [PATCH 4/4] update --- .../sdk/core/oauth/OAuthClientTest.java | 121 ------------------ 1 file changed, 121 deletions(-) delete mode 100644 databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java deleted file mode 100644 index 213da780a..000000000 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/OAuthClientTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.databricks.sdk.core.oauth; - -import static org.junit.jupiter.api.Assertions.*; - -import com.databricks.sdk.core.FixtureServer; -import com.databricks.sdk.core.commons.CommonsHttpClient; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -public class OAuthClientTest { - - @ParameterizedTest(name = "{0}") - @MethodSource("provideBuilderTestCases") - void testOAuthClientBuilder( - String displayName, - String clientId, - String clientSecret, - String host, - String redirectUrl, - List scopes, - String accountId, - String expectedTokenUrl, - String expectedAuthUrl) - throws IOException { - - FixtureServer.FixtureMapping fixture = - new FixtureServer.FixtureMapping.Builder() - .validateMethod("GET") - .validatePath("/oidc/.well-known/oauth-authorization-server") - .withResponse( - "{\"token_endpoint\": \"" - + expectedTokenUrl - + "\", \"authorization_endpoint\": \"" - + expectedAuthUrl - + "\"}", - 200) - .build(); - - try (FixtureServer fixtures = new FixtureServer()) { - fixtures.with(fixture); - - OAuthClient.Builder builder = - new OAuthClient.Builder() - .withHttpClient(new CommonsHttpClient.Builder().withTimeoutSeconds(30).build()) - .withClientId(clientId) - .withClientSecret(clientSecret) - .withHost(fixtures.getUrl()) - .withRedirectUrl(redirectUrl) - .withScopes(scopes); - if (accountId != null) { - builder.withAccountId(accountId); - } - OAuthClient client = builder.build(); - - // Verify builder properties. - assertEquals(clientId, client.getClientId()); - assertEquals(clientSecret, client.getClientSecret()); - assertEquals(fixtures.getUrl(), client.getHost()); - assertEquals(redirectUrl, client.getRedirectUrl()); - assertEquals(expectedTokenUrl, client.getTokenUrl()); - assertEquals(expectedAuthUrl, client.getAuthUrl()); - - // Handle scopes - if null was passed, OAuthClient uses default scopes. - if (scopes == null) { - List defaultScopes = Arrays.asList("offline_access", "clusters", "sql"); - assertEquals(defaultScopes, client.getScopes()); - } else { - assertEquals(scopes, client.getScopes()); - } - } - } - - static Stream provideBuilderTestCases() { - return Stream.of( - Arguments.of( - "Basic host + scopes", - "test-client-1", - "test-secret-1", - "https://test1.databricks.com", - "http://localhost:8080/callback", - Arrays.asList("clusters", "sql"), - null, - "https://test1.databricks.com/oidc/token", - "https://test1.databricks.com/oidc/authorize"), - Arguments.of( - "Null client secret", - "test-client-2", - null, - "https://test2.databricks.com", - "http://localhost:9000/callback", - Arrays.asList("sql", "jobs"), - null, - "https://test2.databricks.com/oidc/token", - "https://test2.databricks.com/oidc/authorize"), - Arguments.of( - "Default scopes", - "test-client-3", - "test-secret-3", - "https://test3.databricks.com", - "http://localhost:7000/callback", - null, // Will use default scopes - null, - "https://test3.databricks.com/oidc/token", - "https://test3.databricks.com/oidc/authorize"), - Arguments.of( - "Accounts host with accountId", - "account-client", - "account-secret", - "https://accounts.cloud.databricks.com", - "http://localhost:8081/callback", - Arrays.asList("clusters"), - "my-account-id", - "https://accounts.cloud.databricks.com/oidc/accounts/my-account-id/v1/token", - "https://accounts.cloud.databricks.com/oidc/accounts/my-account-id/v1/authorize")); - } -}