Skip to content

Commit 1d6a808

Browse files
authored
Add external scopes to U2M workflow (#1035)
## Description - We had issues with SCOPES which we fixed in SDK [[Link](databricks/databricks-sdk-java@11237a2)], it works for M2M use-cases. But, the current ask is to now resolve this for U2M too. ## Testing - Added unit tests ## Additional Notes to the Reviewer <!-- Share any additional context or insights that may help the reviewer understand the changes better. This could include challenges faced, limitations, or compromises made during the development process. Also, mention any areas of the code that you would like the reviewer to focus on specifically. --> NO_CHANGELOG=true
1 parent 512026e commit 1d6a808

File tree

6 files changed

+28
-6
lines changed

6 files changed

+28
-6
lines changed

src/main/java/com/databricks/jdbc/api/impl/DatabricksConnectionContext.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.databricks.jdbc.api.impl;
22

33
import static com.databricks.jdbc.common.DatabricksJdbcConstants.*;
4+
import static com.databricks.jdbc.common.DatabricksJdbcUrlParams.AUTH_SCOPE;
45
import static com.databricks.jdbc.common.DatabricksJdbcUrlParams.DEFAULT_STRING_COLUMN_LENGTH;
56
import static com.databricks.jdbc.common.EnvironmentVariables.DEFAULT_ROW_LIMIT_PER_BLOCK;
67
import static com.databricks.jdbc.common.util.UserAgentManager.USER_AGENT_SEA_CLIENT;
@@ -307,6 +308,9 @@ public String getNullableClientId() {
307308

308309
@Override
309310
public List<String> getOAuthScopesForU2M() throws DatabricksParsingException {
311+
if (getParameter(AUTH_SCOPE) != null) {
312+
return Collections.singletonList(getAuthScope());
313+
}
310314
if (getCloud() == Cloud.AWS || getCloud() == Cloud.GCP) {
311315
return Arrays.asList(
312316
DatabricksJdbcConstants.SQL_SCOPE, DatabricksJdbcConstants.OFFLINE_ACCESS_SCOPE);

src/main/java/com/databricks/jdbc/api/internal/IDatabricksConnectionContext.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ public interface IDatabricksConnectionContext {
5353

5454
String getClientSecret();
5555

56+
/**
57+
* Returns the OAuth scopes to request for the user-to-machine (U2M) authorization flow.
58+
*
59+
* <p>If an explicit auth scope is provided via connection parameters, this returns a singleton
60+
* list containing that scope. On AWS and GCP, this returns the SQL scope and offline access
61+
* scope. On Azure, this returns {@code null} because the default scope is set by the Databricks
62+
* SDK.
63+
*
64+
* @return a list of OAuth scopes to request, or {@code null} on Azure to use the SDK default
65+
* @throws DatabricksParsingException if connection parameters cannot be parsed
66+
*/
5667
List<String> getOAuthScopesForU2M() throws DatabricksParsingException;
5768

5869
AuthMech getAuthMech();

src/main/java/com/databricks/jdbc/common/DatabricksJdbcUrlParams.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public enum DatabricksJdbcUrlParams {
4747
USE_JWT_ASSERTION("UseJWTAssertion", "Use JWT assertion", "0"),
4848
OIDC_DISCOVERY_MODE("EnableOIDCDiscovery", "OIDC discovery mode", "1"),
4949
DISCOVERY_MODE("OAuthDiscoveryMode", "OAuth discovery mode", "1"), // Same as OIDC_DISCOVERY_MODE
50-
AUTH_SCOPE("Auth_Scope", "Authentication scope", "all-apis"),
50+
AUTH_SCOPE("Auth_Scope", "Authentication scope"),
5151
OIDC_DISCOVERY_ENDPOINT("OIDCDiscoveryEndpoint", "OIDC Discovery Endpoint"),
5252
DISCOVERY_URL("OAuthDiscoveryURL", "OAuth discovery URL"), // Same as OIDC_DISCOVERY_ENDPOINT
5353
IDENTITY_FEDERATION_CLIENT_ID(

src/test/java/com/databricks/jdbc/TestConstants.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class TestConstants {
3838
public static final StatementId TEST_STATEMENT_ID = new StatementId("statement_id");
3939
public static final String UC_VOLUME_CATALOG = "uc_volume_test_catalog";
4040
public static final String UC_VOLUME_SCHEMA = "uc_volume_test_schema";
41+
public static final String TEST_SCOPE_STRING = "URI:RS:000001:000999:DatabricksOAuth:TEST";
4142

4243
public static final String DEFAULT_BENCHFOOD_HOST = "e2-benchfood.cloud.databricks.com";
4344
public static final String DEFAULT_BENCHFOOD_HTTP_PATH = "/sql/1.0/warehouses/6e681b20741e4674";
@@ -202,7 +203,7 @@ public class TestConstants {
202203
public static final String VALID_URL_3 =
203204
"jdbc:databricks://sample-host.cloud.databricks.com:9999/default;transportMode=http;"
204205
+ "ssl=0;AuthMech=3;httpPath=/sql/1.0/warehouses/9999999999999999;EnableQueryResultLZ4Compression=0;"
205-
+ "UseThriftClient=1;LogLevel=1234";
206+
+ "UseThriftClient=1;LogLevel=1234;Auth_scope=URI:RS:000001:000999:DatabricksOAuth:TEST";
206207

207208
public static final String VALID_URL_4 =
208209
"jdbc:databricks://sample-host.cloud.databricks.com:9999/default;AuthMech=3;"

src/test/java/com/databricks/jdbc/api/impl/DatabricksConnectionContextTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.databricks.jdbc.api.impl;
22

3+
import static com.databricks.jdbc.TestConstants.TEST_SCOPE_STRING;
34
import static com.databricks.jdbc.api.impl.DatabricksConnectionContext.buildPropertiesMap;
45
import static com.databricks.jdbc.api.impl.DatabricksConnectionContext.getLogLevel;
56
import static com.databricks.jdbc.common.DatabricksJdbcConstants.GCP_GOOGLE_CREDENTIALS_AUTH_TYPE;
@@ -16,6 +17,7 @@
1617
import com.databricks.jdbc.exception.DatabricksVendorCode;
1718
import com.databricks.sdk.core.ProxyConfig;
1819
import com.google.common.collect.ImmutableMap;
20+
import java.util.Collections;
1921
import java.util.List;
2022
import java.util.Properties;
2123
import org.junit.jupiter.api.BeforeAll;
@@ -109,9 +111,10 @@ public void testParseValid() throws DatabricksSQLException {
109111
assertEquals(AuthFlow.TOKEN_PASSTHROUGH, connectionContext.getAuthFlow());
110112
assertEquals(AuthMech.PAT, connectionContext.getAuthMech());
111113
assertEquals(CompressionCodec.NONE, connectionContext.getCompressionCodec());
112-
assertEquals(8, connectionContext.parameters.size());
114+
assertEquals(9, connectionContext.parameters.size());
113115
assertEquals(LogLevel.OFF, connectionContext.getLogLevel());
114-
assertEquals(connectionContext.getOAuthScopesForU2M(), expected_scopes);
116+
assertEquals(
117+
connectionContext.getOAuthScopesForU2M(), Collections.singletonList(TEST_SCOPE_STRING));
115118
assertFalse(connectionContext.isAllPurposeCluster());
116119
assertEquals(DatabricksClientType.THRIFT, connectionContext.getClientType());
117120

src/test/java/com/databricks/jdbc/dbclient/impl/common/ClientConfiguratorTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.databricks.jdbc.dbclient.impl.common;
22

33
import static com.databricks.jdbc.TestConstants.TEST_DISCOVERY_URL;
4+
import static com.databricks.jdbc.TestConstants.TEST_SCOPE_STRING;
45
import static com.databricks.jdbc.common.DatabricksJdbcConstants.GCP_GOOGLE_CREDENTIALS_AUTH_TYPE;
56
import static com.databricks.jdbc.common.DatabricksJdbcConstants.M2M_AZURE_CLIENT_SECRET_AUTH_TYPE;
67
import static org.junit.jupiter.api.Assertions.*;
@@ -26,6 +27,7 @@
2627
import java.io.IOException;
2728
import java.net.ServerSocket;
2829
import java.time.Duration;
30+
import java.util.Collections;
2931
import java.util.List;
3032
import java.util.Properties;
3133
import org.junit.jupiter.api.Test;
@@ -207,9 +209,10 @@ void getWorkspaceClient_OAuthWithBrowserBasedAuthentication_AuthenticatesCorrect
207209
when(mockContext.getHostForOAuth()).thenReturn("https://oauth-browser.databricks.com");
208210
when(mockContext.getClientId()).thenReturn("browser-client-id");
209211
when(mockContext.getClientSecret()).thenReturn("browser-client-secret");
210-
when(mockContext.getOAuthScopesForU2M()).thenReturn(List.of("scope1", "scope2"));
211212
when(mockContext.isOAuthDiscoveryModeEnabled()).thenReturn(true);
212213
when(mockContext.getOAuthDiscoveryURL()).thenReturn(TEST_DISCOVERY_URL);
214+
when(mockContext.getOAuthScopesForU2M())
215+
.thenReturn(Collections.singletonList(TEST_SCOPE_STRING));
213216
when(mockContext.getHttpConnectionPoolSize()).thenReturn(100);
214217
when(mockContext.getOAuth2RedirectUrlPorts()).thenReturn(List.of(8020));
215218
when(mockContext.getHttpMaxConnectionsPerRoute()).thenReturn(100);
@@ -222,7 +225,7 @@ void getWorkspaceClient_OAuthWithBrowserBasedAuthentication_AuthenticatesCorrect
222225
assertEquals("https://oauth-browser.databricks.com", config.getHost());
223226
assertEquals("browser-client-id", config.getClientId());
224227
assertEquals("browser-client-secret", config.getClientSecret());
225-
assertEquals(List.of("scope1", "scope2"), config.getScopes());
228+
assertEquals(List.of(TEST_SCOPE_STRING), config.getScopes());
226229
assertEquals("http://localhost:8020", config.getOAuthRedirectUrl());
227230
assertEquals(DatabricksJdbcConstants.U2M_AUTH_TYPE, config.getAuthType());
228231
}

0 commit comments

Comments
 (0)