Skip to content
Merged
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
1 change: 1 addition & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
- Fixed SQL syntax error when LIKE queries contain empty ESCAPE clauses.
- Fix: driver failing to authenticate on token update in U2M flow.
- Fix: driver failing to parse complex data types with nullable attributes.
- Fixed: Resolved SDK token-caching regression causing token refresh on every call. SDK is now configured once to avoid excessive token endpoint hits and rate limiting.
---
*Note: When making changes, please add your change under the appropriate section with a brief description.*
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class DatabricksTokenFederationProvider implements CredentialsProvider, T
private static final JdbcLogger LOGGER =
JdbcLoggerFactory.getLogger(DatabricksTokenFederationProvider.class);
private Token token;
private HeaderFactory externalHeaderFactory;
private static final Map<String, String> TOKEN_EXCHANGE_PARAMS =
Map.of(
"grant_type",
Expand All @@ -69,6 +70,9 @@ public DatabricksTokenFederationProvider(
this.credentialsProvider = credentialsProvider;
this.externalProviderHeaders = new HashMap<>();
this.hc = DatabricksHttpClientFactory.getInstance().getClient(connectionContext);
// Initialize a minimal config; real config will be provided via configure(databricksConfig)
this.config = null;
this.externalHeaderFactory = null;
this.token =
new Token(
DatabricksJdbcConstants.EMPTY_STRING,
Expand All @@ -85,6 +89,7 @@ public DatabricksTokenFederationProvider(
this.connectionContext = connectionContext;
this.credentialsProvider = credentialsProvider;
this.config = config;
this.externalHeaderFactory = this.credentialsProvider.configure(this.config);
this.externalProviderHeaders = new HashMap<>();
this.token =
new Token(
Expand Down Expand Up @@ -113,6 +118,8 @@ public HeaderFactory configure(DatabricksConfig databricksConfig) {
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is configure always called once?


this.config = databricksConfig;
// Call the underlying provider's configure ONCE and cache the HeaderFactory
this.externalHeaderFactory = this.credentialsProvider.configure(this.config);
return () -> {
Token exchangedToken = getToken();
Map<String, String> headers = new HashMap<>(this.externalProviderHeaders);
Expand All @@ -124,7 +131,11 @@ public HeaderFactory configure(DatabricksConfig databricksConfig) {
}

public Token getToken() {
this.externalProviderHeaders = this.credentialsProvider.configure(this.config).headers();
if (this.externalHeaderFactory == null) {
// Lazy-initialize if configure(databricksConfig) was not called yet
this.externalHeaderFactory = this.credentialsProvider.configure(this.config);
}
this.externalProviderHeaders = this.externalHeaderFactory.headers();
String[] tokenInfo = extractTokenInfoFromHeader(this.externalProviderHeaders);
String accessTokenType = tokenInfo[0];
String accessToken = tokenInfo[1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,18 +377,21 @@ public void setupM2MConfig() throws DatabricksParsingException {
connectionContext, new AzureServicePrincipalCredentialsProvider()));
} else {
databricksConfig
.setAuthType(DatabricksJdbcConstants.M2M_AUTH_TYPE)
.setClientId(connectionContext.getClientId())
.setClientSecret(connectionContext.getClientSecret());
if (connectionContext.useJWTAssertion()) {
databricksConfig.setCredentialsProvider(
new DatabricksTokenFederationProvider(
connectionContext,
new PrivateKeyClientCredentialProvider(connectionContext, databricksConfig)));
CredentialsProvider jwtProvider =
new PrivateKeyClientCredentialProvider(connectionContext, databricksConfig);
databricksConfig
.setAuthType(jwtProvider.authType())
.setCredentialsProvider(
new DatabricksTokenFederationProvider(connectionContext, jwtProvider));
} else {
databricksConfig.setCredentialsProvider(
new DatabricksTokenFederationProvider(
connectionContext, new OAuthM2MServicePrincipalCredentialsProvider()));
CredentialsProvider m2mProvider = new OAuthM2MServicePrincipalCredentialsProvider();
databricksConfig
.setAuthType(DatabricksJdbcConstants.M2M_AUTH_TYPE)
.setCredentialsProvider(
new DatabricksTokenFederationProvider(connectionContext, m2mProvider));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ void testM2MWithJWT() throws DatabricksSQLException {
assertEquals("https://sample-host.18.azuredatabricks.net", config.getHost());
assertEquals("test-client", config.getClientId());
assertEquals("custom-oauth-m2m", provider.authType());
assertEquals(DatabricksJdbcConstants.M2M_AUTH_TYPE, config.getAuthType());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no other tests needed?

assertEquals(provider.authType(), config.getAuthType());
assertEquals(
PrivateKeyClientCredentialProvider.class, provider.getCredentialsProvider().getClass());
}
Expand Down
Loading