Skip to content

Commit 2662285

Browse files
Fix OIDC endpoints detection (#657)
## What changes are proposed in this pull request? Fix getOidcEndpoints() method. The method was incorrectly returning Azure OIDC when `ARM_CLIENT_ID` is set, but `getOidcEndpoints()` is never called for Azure OIDC. This logic actually caused Databricks M2M to use the wrong endpoint when the user set the `ARM_CLIENT_ID` for other purposes as can be seen in #656 NOTE: The new logic **matches the behavior of the Go SDK**. ## How is this tested? - Before this change, M2M authentication would fail (see #656) - Add new tests and rerun existing ones. NO_CHANGELOG=true --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent e988598 commit 2662285

File tree

3 files changed

+145
-12
lines changed

3 files changed

+145
-12
lines changed

databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -796,18 +796,6 @@ private OpenIDConnectEndpoints fetchDefaultOidcEndpoints() throws IOException {
796796
if (getHostType() == HostType.UNIFIED) {
797797
return getUnifiedOidcEndpoints(getAccountId());
798798
}
799-
800-
if (isAzure() && getAzureClientId() != null) {
801-
Request request = new Request("GET", getHost() + "/oidc/oauth2/v2.0/authorize");
802-
request.setRedirectionBehavior(false);
803-
Response resp = getHttpClient().execute(request);
804-
String realAuthUrl = resp.getFirstHeader("location");
805-
if (realAuthUrl == null) {
806-
return null;
807-
}
808-
return new OpenIDConnectEndpoints(
809-
realAuthUrl.replaceAll("/authorize", "/token"), realAuthUrl);
810-
}
811799
if (isAccountClient() && getAccountId() != null) {
812800
String prefix = getHost() + "/oidc/accounts/" + getAccountId();
813801
return new OpenIDConnectEndpoints(prefix + "/v1/token", prefix + "/v1/authorize");
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.databricks.sdk.integration;
2+
3+
import com.databricks.sdk.AccountClient;
4+
import com.databricks.sdk.core.DatabricksConfig;
5+
import com.databricks.sdk.integration.framework.EnvContext;
6+
import com.databricks.sdk.integration.framework.EnvOrSkip;
7+
import com.databricks.sdk.integration.framework.EnvTest;
8+
import com.databricks.sdk.service.iam.ListAccountServicePrincipalsRequest;
9+
import com.databricks.sdk.service.iam.ServicePrincipal;
10+
import org.junit.jupiter.api.Test;
11+
import org.junit.jupiter.api.extension.ExtendWith;
12+
import org.slf4j.Logger;
13+
import org.slf4j.LoggerFactory;
14+
15+
@ExtendWith(EnvTest.class)
16+
@EnvContext("account")
17+
public class DatabricksOidcAccountIT {
18+
private static final Logger LOG = LoggerFactory.getLogger(DatabricksOidcAccountIT.class);
19+
20+
@Test
21+
void testAccountOAuthM2MAuth(
22+
@EnvOrSkip("CLOUD_ENV") String cloudEnv,
23+
@EnvOrSkip("DATABRICKS_HOST") String host,
24+
@EnvOrSkip("DATABRICKS_ACCOUNT_ID") String accountId,
25+
@EnvOrSkip("TEST_DATABRICKS_CLIENT_ID") String clientId,
26+
@EnvOrSkip("TEST_DATABRICKS_CLIENT_SECRET") String clientSecret) {
27+
LOG.info("Cloud environment: {}", cloudEnv);
28+
29+
// Create account client with OAuth M2M authentication
30+
DatabricksConfig config =
31+
new DatabricksConfig()
32+
.setHost(host)
33+
.setAccountId(accountId)
34+
.setClientId(clientId)
35+
.setClientSecret(clientSecret)
36+
.setAuthType("oauth-m2m");
37+
38+
AccountClient ac = new AccountClient(config);
39+
40+
// List service principals to verify authentication works
41+
Iterable<ServicePrincipal> servicePrincipals =
42+
ac.servicePrincipals().list(new ListAccountServicePrincipalsRequest());
43+
servicePrincipals.iterator().next();
44+
}
45+
46+
@Test
47+
void testAccountAzureClientSecretAuth(
48+
@EnvOrSkip("CLOUD_ENV") String cloudEnv,
49+
@EnvOrSkip("DATABRICKS_HOST") String host,
50+
@EnvOrSkip("DATABRICKS_ACCOUNT_ID") String accountId,
51+
@EnvOrSkip("ARM_CLIENT_ID") String azureClientId,
52+
@EnvOrSkip("ARM_CLIENT_SECRET") String azureClientSecret,
53+
@EnvOrSkip("ARM_TENANT_ID") String azureTenantId) {
54+
LOG.info("Cloud environment: {}", cloudEnv);
55+
56+
// Create account client with Azure client secret authentication
57+
DatabricksConfig config =
58+
new DatabricksConfig()
59+
.setHost(host)
60+
.setAccountId(accountId)
61+
.setAzureClientId(azureClientId)
62+
.setAzureClientSecret(azureClientSecret)
63+
.setAzureTenantId(azureTenantId)
64+
.setAuthType("azure-client-secret");
65+
66+
AccountClient ac = new AccountClient(config);
67+
68+
// List service principals to verify authentication works
69+
Iterable<ServicePrincipal> servicePrincipals =
70+
ac.servicePrincipals().list(new ListAccountServicePrincipalsRequest());
71+
servicePrincipals.iterator().next();
72+
}
73+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.databricks.sdk.integration;
2+
3+
import static org.junit.jupiter.api.Assertions.assertNotNull;
4+
5+
import com.databricks.sdk.WorkspaceClient;
6+
import com.databricks.sdk.core.DatabricksConfig;
7+
import com.databricks.sdk.integration.framework.EnvContext;
8+
import com.databricks.sdk.integration.framework.EnvOrSkip;
9+
import com.databricks.sdk.integration.framework.EnvTest;
10+
import com.databricks.sdk.service.iam.User;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.ExtendWith;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
@ExtendWith(EnvTest.class)
17+
@EnvContext("ucws")
18+
public class DatabricksOidcWorkspaceIT {
19+
private static final Logger LOG = LoggerFactory.getLogger(DatabricksOidcWorkspaceIT.class);
20+
21+
@Test
22+
void testWorkspaceOAuthM2MAuth(
23+
@EnvOrSkip("CLOUD_ENV") String cloudEnv,
24+
@EnvOrSkip("DATABRICKS_HOST") String host,
25+
@EnvOrSkip("TEST_DATABRICKS_CLIENT_ID") String clientId,
26+
@EnvOrSkip("TEST_DATABRICKS_CLIENT_SECRET") String clientSecret) {
27+
LOG.info("Cloud environment: {}", cloudEnv);
28+
29+
// Create workspace client with OAuth M2M authentication
30+
DatabricksConfig config =
31+
new DatabricksConfig()
32+
.setHost(host)
33+
.setClientId(clientId)
34+
.setClientSecret(clientSecret)
35+
.setAuthType("oauth-m2m");
36+
37+
WorkspaceClient ws = new WorkspaceClient(config);
38+
39+
// Call the "me" API
40+
User me = ws.currentUser().me();
41+
42+
// Verify we got a valid response
43+
assertNotNull(me.getUserName(), "Expected non-empty UserName");
44+
}
45+
46+
@Test
47+
void testWorkspaceAzureClientSecretAuth(
48+
@EnvOrSkip("CLOUD_ENV") String cloudEnv,
49+
@EnvOrSkip("DATABRICKS_HOST") String host,
50+
@EnvOrSkip("ARM_CLIENT_ID") String azureClientId,
51+
@EnvOrSkip("ARM_CLIENT_SECRET") String azureClientSecret,
52+
@EnvOrSkip("ARM_TENANT_ID") String azureTenantId) {
53+
LOG.info("Cloud environment: {}", cloudEnv);
54+
55+
// Create workspace client with Azure client secret authentication
56+
DatabricksConfig config =
57+
new DatabricksConfig()
58+
.setHost(host)
59+
.setAzureClientId(azureClientId)
60+
.setAzureClientSecret(azureClientSecret)
61+
.setAzureTenantId(azureTenantId)
62+
.setAuthType("azure-client-secret");
63+
64+
WorkspaceClient ws = new WorkspaceClient(config);
65+
66+
// Call the "me" API
67+
User me = ws.currentUser().me();
68+
69+
// Verify we got a valid response
70+
assertNotNull(me.getUserName(), "Expected non-empty UserName");
71+
}
72+
}

0 commit comments

Comments
 (0)