Skip to content

Commit 694b7c4

Browse files
committed
Merge remote-tracking branch 'origin/main' into default-profile
2 parents 3595fae + f28430b commit 694b7c4

5 files changed

Lines changed: 102 additions & 19 deletions

File tree

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,10 @@ void resolveHostMetadata() throws IOException {
907907
discoveryUrl = oidcUri.resolve(".well-known/oauth-authorization-server").toString();
908908
LOG.debug("Resolved discovery_url from host metadata: \"{}\"", discoveryUrl);
909909
}
910+
// For account hosts, use the accountId as the token audience if not already set.
911+
if (tokenAudience == null && getClientType() == ClientType.ACCOUNT && accountId != null) {
912+
tokenAudience = accountId;
913+
}
910914
}
911915

912916
private OpenIDConnectEndpoints fetchOidcEndpointsFromDiscovery() {

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

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,12 @@ public HeaderFactory configure(DatabricksConfig config) {
6666
Map<String, String> headers = new HashMap<>();
6767
headers.put("Authorization", String.format("Bearer %s", idToken.getTokenValue()));
6868

69-
if (config.getClientType() == ClientType.ACCOUNT) {
70-
AccessToken token;
71-
try {
72-
token = finalServiceAccountCredentials.createScoped(GCP_SCOPES).refreshAccessToken();
73-
} catch (IOException e) {
74-
String message =
75-
"Failed to refresh access token from Google service account credentials.";
76-
LOG.error(message + e);
77-
throw new DatabricksException(message, e);
78-
}
69+
try {
70+
AccessToken token =
71+
finalServiceAccountCredentials.createScoped(GCP_SCOPES).refreshAccessToken();
7972
headers.put(SA_ACCESS_TOKEN_HEADER, token.getTokenValue());
73+
} catch (IOException e) {
74+
LOG.warn("Failed to refresh GCP SA access token, skipping header: {}", e.getMessage());
8075
}
8176

8277
return headers;

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,11 @@ public HeaderFactory configure(DatabricksConfig config) {
6969
throw new DatabricksException(message, e);
7070
}
7171

72-
if (config.getClientType() == ClientType.ACCOUNT) {
73-
try {
74-
headers.put(
75-
SA_ACCESS_TOKEN_HEADER, gcpScopedCredentials.refreshAccessToken().getTokenValue());
76-
} catch (IOException e) {
77-
String message = "Failed to refresh access token from scoped id token credentials.";
78-
LOG.error(message + e);
79-
throw new DatabricksException(message, e);
80-
}
72+
try {
73+
headers.put(
74+
SA_ACCESS_TOKEN_HEADER, gcpScopedCredentials.refreshAccessToken().getTokenValue());
75+
} catch (IOException e) {
76+
LOG.warn("Failed to refresh GCP SA access token, skipping header: {}", e.getMessage());
8177
}
8278

8379
return headers;

databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,52 @@ public void testResolveHostMetadataRaisesOnHttpError() throws IOException {
586586
}
587587
}
588588

589+
@Test
590+
public void testResolveHostMetadataSetsTokenAudienceForAccountHost() throws IOException {
591+
// For a unified host with no workspaceId (ACCOUNT client type), resolveHostMetadata should
592+
// set tokenAudience to accountId when not already configured.
593+
String response =
594+
"{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\","
595+
+ "\"account_id\":\""
596+
+ DUMMY_ACCOUNT_ID
597+
+ "\"}";
598+
try (FixtureServer server =
599+
new FixtureServer()
600+
.with("GET", "/.well-known/databricks-config", response, 200)
601+
.with("GET", "/.well-known/databricks-config", response, 200)) {
602+
DatabricksConfig config =
603+
new DatabricksConfig()
604+
.setHost(server.getUrl())
605+
.setExperimentalIsUnifiedHost(true)
606+
.setAccountId(DUMMY_ACCOUNT_ID);
607+
config.resolve(emptyEnv());
608+
// Client type should be ACCOUNT (unified host, no workspaceId)
609+
assertEquals(ClientType.ACCOUNT, config.getClientType());
610+
config.resolveHostMetadata();
611+
assertEquals(DUMMY_ACCOUNT_ID, config.getTokenAudience());
612+
}
613+
}
614+
615+
@Test
616+
public void testResolveHostMetadataDoesNotOverwriteTokenAudience() throws IOException {
617+
String response =
618+
"{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\","
619+
+ "\"account_id\":\""
620+
+ DUMMY_ACCOUNT_ID
621+
+ "\"}";
622+
try (FixtureServer server =
623+
new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) {
624+
DatabricksConfig config =
625+
new DatabricksConfig()
626+
.setHost(server.getUrl())
627+
.setAccountId(DUMMY_ACCOUNT_ID)
628+
.setTokenAudience("custom-audience");
629+
config.resolve(emptyEnv());
630+
config.resolveHostMetadata();
631+
assertEquals("custom-audience", config.getTokenAudience());
632+
}
633+
}
634+
589635
// --- tryResolveHostMetadata (config init) tests ---
590636

591637
@Test
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.databricks.sdk.integration;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import com.databricks.sdk.core.DatabricksConfig;
6+
import com.databricks.sdk.integration.framework.EnvContext;
7+
import com.databricks.sdk.integration.framework.EnvOrSkip;
8+
import com.databricks.sdk.integration.framework.EnvTest;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.extension.ExtendWith;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
14+
/**
15+
* Integration test for host metadata resolution via /.well-known/databricks-config. Port of Go SDK
16+
* #1546.
17+
*/
18+
@ExtendWith(EnvTest.class)
19+
@EnvContext("ucws")
20+
public class HostMetadataIT {
21+
private static final Logger LOG = LoggerFactory.getLogger(HostMetadataIT.class);
22+
23+
@Test
24+
void testResolvePopulatesFieldsFromMetadata(@EnvOrSkip("DATABRICKS_HOST") String host) {
25+
DatabricksConfig config =
26+
new DatabricksConfig().setHost(host).setExperimentalIsUnifiedHost(true);
27+
config.resolve();
28+
29+
LOG.info(
30+
"Resolved metadata for {}: accountId={}, workspaceId={}, discoveryUrl={}",
31+
host,
32+
config.getAccountId(),
33+
config.getWorkspaceId(),
34+
config.getDiscoveryUrl());
35+
36+
// After resolve(), host metadata should have been resolved
37+
assertNotNull(config.getDiscoveryUrl(), "Expected discoveryUrl to be populated after resolve");
38+
assertFalse(config.getDiscoveryUrl().isEmpty(), "Expected non-empty discoveryUrl");
39+
assertNotNull(config.getAccountId(), "Expected accountId to be populated after resolve");
40+
assertFalse(config.getAccountId().isEmpty(), "Expected non-empty accountId");
41+
}
42+
}

0 commit comments

Comments
 (0)