Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.databricks.sdk.core.http.Request;
import com.databricks.sdk.core.http.Response;
import com.databricks.sdk.core.oauth.ErrorTokenSource;
import com.databricks.sdk.core.oauth.HostMetadata;
import com.databricks.sdk.core.oauth.OAuthHeaderFactory;
import com.databricks.sdk.core.oauth.OpenIDConnectEndpoints;
import com.databricks.sdk.core.oauth.TokenSource;
Expand Down Expand Up @@ -800,6 +801,32 @@ public OpenIDConnectEndpoints getDatabricksOidcEndpoints() throws IOException {
return fetchOidcEndpointsFromDiscovery();
}

/**
* [Experimental] Fetch the raw Databricks well-known configuration from
* {host}/.well-known/databricks-config.
*
* <p><b>Note:</b> This API is experimental and may change or be removed in future releases
* without notice.
*
* @return Parsed {@link HostMetadata} as returned by the server.
* @throws DatabricksException if the request fails or the server returns a non-200 status.
*/
HostMetadata getHostMetadata() throws IOException {
String url = host + "/.well-known/databricks-config";
try {
Request request = new Request("GET", url);
Response resp = getHttpClient().execute(request);
if (resp.getStatusCode() != 200) {
throw new DatabricksException(
"Failed to fetch host metadata from " + url + ": HTTP " + resp.getStatusCode());
}
return new ObjectMapper().readValue(resp.getBody(), HostMetadata.class);
} catch (IOException e) {
throw new DatabricksException(
"Failed to fetch host metadata from " + url + ": " + e.getMessage(), e);
}
}

private OpenIDConnectEndpoints fetchOidcEndpointsFromDiscovery() {
try {
Request request = new Request("GET", discoveryUrl);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.databricks.sdk.core.oauth;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
* [Experimental] Parsed response from the /.well-known/databricks-config discovery endpoint.
*
* <p><b>Note:</b> This API is experimental and may change or be removed in future releases without
* notice.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class HostMetadata {
@JsonProperty("oidc_endpoint")
private String oidcEndpoint;

@JsonProperty("account_id")
private String accountId;

@JsonProperty("workspace_id")
private String workspaceId;

public HostMetadata() {}

public HostMetadata(String oidcEndpoint, String accountId, String workspaceId) {
this.oidcEndpoint = oidcEndpoint;
this.accountId = accountId;
this.workspaceId = workspaceId;
}

public String getOidcEndpoint() {
return oidcEndpoint;
}

public String getAccountId() {
return accountId;
}

public String getWorkspaceId() {
return workspaceId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.databricks.sdk.core.commons.CommonsHttpClient;
import com.databricks.sdk.core.http.HttpClient;
import com.databricks.sdk.core.oauth.ErrorTokenSource;
import com.databricks.sdk.core.oauth.HostMetadata;
import com.databricks.sdk.core.oauth.OAuthHeaderFactory;
import com.databricks.sdk.core.oauth.OpenIDConnectEndpoints;
import com.databricks.sdk.core.oauth.Token;
Expand Down Expand Up @@ -421,4 +422,93 @@ public void testGetClientTypeAccountOnUnified() {
.setExperimentalIsUnifiedHost(true)
.getClientType());
}

// --- HostMetadata tests ---

private static final String DUMMY_ACCOUNT_ID = "00000000-0000-0000-0000-000000000001";
private static final String DUMMY_WORKSPACE_ID = "111111111111111";

private static Environment emptyEnv() {
return new Environment(new HashMap<>(), new ArrayList<>(), System.getProperty("os.name"));
}

@Test
public void testGetHostMetadataWorkspaceStaticOidcEndpoint() throws IOException {
String response =
"{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\","
+ "\"account_id\":\""
+ DUMMY_ACCOUNT_ID
+ "\","
+ "\"workspace_id\":\""
+ DUMMY_WORKSPACE_ID
+ "\"}";
try (FixtureServer server =
new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) {
DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl());
config.resolve(emptyEnv());
HostMetadata meta = config.getHostMetadata();
assertEquals("https://ws.databricks.com/oidc", meta.getOidcEndpoint());
assertEquals(DUMMY_ACCOUNT_ID, meta.getAccountId());
assertEquals(DUMMY_WORKSPACE_ID, meta.getWorkspaceId());
}
}

@Test
public void testGetHostMetadataAccountRawOidcTemplate() throws IOException {
String response =
"{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}";
try (FixtureServer server =
new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) {
DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl());
config.resolve(emptyEnv());
HostMetadata meta = config.getHostMetadata();
assertEquals("https://acc.databricks.com/oidc/accounts/{account_id}", meta.getOidcEndpoint());
assertNull(meta.getAccountId());
assertNull(meta.getWorkspaceId());
}
}

@Test
public void testGetHostMetadataRaisesOnHttpError() throws IOException {
try (FixtureServer server =
new FixtureServer().with("GET", "/.well-known/databricks-config", "{}", 404)) {
DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl());
config.resolve(emptyEnv());
DatabricksException ex =
assertThrows(DatabricksException.class, () -> config.getHostMetadata());
assertTrue(ex.getMessage().contains("Failed to fetch host metadata"));
}
}

// --- discoveryUrl / OIDC endpoint tests ---

@Test
public void testDiscoveryUrlFromEnv() {
Map<String, String> env = new HashMap<>();
env.put("DATABRICKS_DISCOVERY_URL", "https://custom.idp.example.com/oidc");
DatabricksConfig config = new DatabricksConfig();
config.resolve(new Environment(env, new ArrayList<>(), System.getProperty("os.name")));
assertEquals("https://custom.idp.example.com/oidc", config.getDiscoveryUrl());
}

@Test
public void testDatabricksOidcEndpointsUsesDiscoveryUrl() throws IOException {
String discoveryUrlSuffix = "/oidc";
String discoveryUrlResponse =
"{\"authorization_endpoint\":\"https://ws.databricks.com/oidc/v1/authorize\","
+ "\"token_endpoint\":\"https://ws.databricks.com/oidc/v1/token\"}";
try (FixtureServer server =
new FixtureServer().with("GET", discoveryUrlSuffix, discoveryUrlResponse, 200)) {
String discoveryUrl = server.getUrl() + discoveryUrlSuffix;
OpenIDConnectEndpoints endpoints =
new DatabricksConfig()
.setHost(server.getUrl())
.setDiscoveryUrl(discoveryUrl)
.setHttpClient(new CommonsHttpClient.Builder().withTimeoutSeconds(30).build())
.getDatabricksOidcEndpoints();
assertEquals(
"https://ws.databricks.com/oidc/v1/authorize", endpoints.getAuthorizationEndpoint());
assertEquals("https://ws.databricks.com/oidc/v1/token", endpoints.getTokenEndpoint());
}
}
}
Loading