Skip to content

Commit 9d92856

Browse files
Add way to disable refresh tokens
1 parent e9720e9 commit 9d92856

File tree

4 files changed

+106
-10
lines changed

4 files changed

+106
-10
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,14 @@ public class DatabricksConfig {
175175
@ConfigAttribute(env = "DATABRICKS_OAUTH_BROWSER_AUTH_TIMEOUT")
176176
private Duration oauthBrowserAuthTimeout;
177177

178+
/**
179+
* Disable automatically adding the offline_access scope to the OAuth authentication
180+
* request to request refresh tokens. Note that this does not remove the scope if it
181+
* is explicitly provided by the user.
182+
*/
183+
@ConfigAttribute(env = "DATABRICKS_DISABLE_OAUTH_REFRESH_TOKEN")
184+
private Boolean disableOauthRefreshToken;
185+
178186
public Environment getEnv() {
179187
return env;
180188
}
@@ -631,6 +639,15 @@ public DatabricksConfig setOAuthBrowserAuthTimeout(Duration oauthBrowserAuthTime
631639
return this;
632640
}
633641

642+
public boolean getDisableOauthRefreshToken() {
643+
return disableOauthRefreshToken != null && disableOauthRefreshToken;
644+
}
645+
646+
public DatabricksConfig setDisableOauthRefreshToken(boolean disable) {
647+
this.disableOauthRefreshToken = disable;
648+
return this;
649+
}
650+
634651
public boolean isAzure() {
635652
if (azureWorkspaceResourceId != null) {
636653
return true;

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProvider.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.HashSet;
1010
import java.util.Objects;
1111
import java.util.Optional;
12+
import java.util.List;
1213
import java.util.Set;
1314
import org.slf4j.Logger;
1415
import org.slf4j.LoggerFactory;
@@ -105,20 +106,25 @@ public OAuthHeaderFactory configure(DatabricksConfig config) {
105106
}
106107
}
107108

108-
CachedTokenSource performBrowserAuth(
109-
DatabricksConfig config, String clientId, String clientSecret, TokenCache tokenCache)
110-
throws IOException {
111-
LOGGER.debug("Performing browser authentication");
112-
109+
protected List<String> getScopes(DatabricksConfig config) {
113110
// Get user-provided scopes and add required default scopes.
114111
Set<String> scopes = new HashSet<>(config.getScopes());
115-
116-
// Needed to request a refresh token.
117-
scopes.add("offline_access");
118-
112+
// Requesting a refresh token is most of the time the right thing to do to enable
113+
// long-lived access to the API. However, some Identity Providers do not support
114+
// refresh tokens.
115+
if (!config.getDisableOauthRefreshToken()) {
116+
scopes.add("offline_access");
117+
}
119118
if (config.isAzure()) {
120119
scopes.add(config.getEffectiveAzureLoginAppId() + "/user_impersonation");
121120
}
121+
return new ArrayList<>(scopes);
122+
}
123+
124+
CachedTokenSource performBrowserAuth(
125+
DatabricksConfig config, String clientId, String clientSecret, TokenCache tokenCache)
126+
throws IOException {
127+
LOGGER.debug("Performing browser authentication");
122128

123129
OAuthClient client =
124130
new OAuthClient.Builder()
@@ -129,7 +135,7 @@ CachedTokenSource performBrowserAuth(
129135
.withAccountId(config.getAccountId())
130136
.withRedirectUrl(config.getEffectiveOAuthRedirectUrl())
131137
.withBrowserTimeout(config.getOAuthBrowserAuthTimeout())
132-
.withScopes(new ArrayList<>(scopes))
138+
.withScopes(getScopes(config))
133139
.withOpenIDConnectEndpoints(config.getOidcEndpoints())
134140
.build();
135141
Consent consent = client.initiateConsent();

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,27 @@ public void testDisableRetriesEnvironmentVariable() {
299299

300300
assertEquals(true, config.getDisableRetries());
301301
}
302+
303+
@Test
304+
public void testDisableOauthRefreshTokenDefaultValue() {
305+
DatabricksConfig config = new DatabricksConfig();
306+
assertEquals(false, config.getDisableOauthRefreshToken());
307+
}
308+
309+
@Test
310+
public void testDisableOauthRefreshTokenSetAndGet() {
311+
DatabricksConfig config = new DatabricksConfig().setDisableOauthRefreshToken(true);
312+
assertEquals(true, config.getDisableOauthRefreshToken());
313+
}
314+
315+
@Test
316+
public void testDisableOauthRefreshTokenEnvironmentVariable() {
317+
Map<String, String> env = new HashMap<>();
318+
env.put("DATABRICKS_DISABLE_OAUTH_REFRESH_TOKEN", "true");
319+
320+
DatabricksConfig config = new DatabricksConfig();
321+
config.resolve(new Environment(env, new ArrayList<>(), System.getProperty("os.name")));
322+
323+
assertEquals(true, config.getDisableOauthRefreshToken());
324+
}
302325
}

databricks-sdk-java/src/test/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProviderTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.time.Instant;
1717
import java.util.Arrays;
1818
import java.util.HashMap;
19+
import java.util.List;
1920
import java.util.Map;
2021
import java.util.Optional;
2122
import org.junit.jupiter.api.Test;
@@ -551,4 +552,53 @@ void cacheWithInvalidTokensTest() throws IOException {
551552
// Verify token was saved after browser auth (for the new token)
552553
Mockito.verify(mockTokenCache, Mockito.times(1)).save(any(Token.class));
553554
}
555+
556+
@Test
557+
void doNotAddOfflineAccessScopeWhenDisableOauthRefreshTokenIsTrue() {
558+
DatabricksConfig config =
559+
new DatabricksConfig()
560+
.setHost("https://test.databricks.com")
561+
.setClientId("test-client-id")
562+
.setDisableOauthRefreshToken(true)
563+
.setScopes(Arrays.asList("my-test-scope"));
564+
565+
ExternalBrowserCredentialsProvider provider = new ExternalBrowserCredentialsProvider();
566+
List<String> scopes = provider.getScopes(config);
567+
568+
assertEquals(1, scopes.size());
569+
assertTrue(scopes.contains("my-test-scope"));
570+
}
571+
572+
@Test
573+
void doNotRemoveUserProvidedScopesWhenDisableOauthRefreshTokenIsTrue() {
574+
DatabricksConfig config =
575+
new DatabricksConfig()
576+
.setHost("https://test.databricks.com")
577+
.setClientId("test-client-id")
578+
.setDisableOauthRefreshToken(true)
579+
.setScopes(Arrays.asList("my-test-scope", "offline_access"));
580+
581+
ExternalBrowserCredentialsProvider provider = new ExternalBrowserCredentialsProvider();
582+
List<String> scopes = provider.getScopes(config);
583+
584+
assertEquals(2, scopes.size());
585+
assertTrue(scopes.contains("offline_access"));
586+
assertTrue(scopes.contains("my-test-scope"));
587+
}
588+
589+
@Test
590+
void addOfflineAccessScopeWhenDisableOauthRefreshTokenIsFalse() {
591+
DatabricksConfig config =
592+
new DatabricksConfig()
593+
.setHost("https://test.databricks.com")
594+
.setClientId("test-client-id")
595+
.setScopes(Arrays.asList("my-test-scope"));
596+
597+
ExternalBrowserCredentialsProvider provider = new ExternalBrowserCredentialsProvider();
598+
List<String> scopes = provider.getScopes(config);
599+
600+
assertEquals(2, scopes.size());
601+
assertTrue(scopes.contains("offline_access"));
602+
assertTrue(scopes.contains("my-test-scope"));
603+
}
554604
}

0 commit comments

Comments
 (0)