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 @@ -99,7 +99,8 @@ public OAuthHeaderFactory configure(DatabricksConfig config) {
() -> {
Token token = tokenSource.getToken();
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", token.getTokenType() + " " + token.getAccessToken());
headers.put(
"Authorization", token.getCanonicalTokenType() + " " + token.getAccessToken());
if (finalMgmtTokenSource != null) {
AzureUtils.addSpManagementToken(finalMgmtTokenSource, headers);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public Token getToken() {
public Map<String, String> headers() {
Token token = tokenSource.getToken();
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", token.getTokenType() + " " + token.getAccessToken());
headers.put(
"Authorization", token.getCanonicalTokenType() + " " + token.getAccessToken());
return headers;
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ public String getTokenType() {
return tokenType;
}

/**
* Returns the token type canonicalized for use as the Authorization header scheme. Per RFC 6749
* §5.1 / RFC 6750 §2.1, identity providers may return {@code token_type} in any case (e.g.
* "bearer", "BEARER"). Some downstream servers and proxies reject anything other than the
* canonical "Bearer" capitalization, so we normalize that scheme here. Other schemes are returned
* unchanged.
*
* @return the canonicalized token type
*/
public String getCanonicalTokenType() {
if ("bearer".equalsIgnoreCase(tokenType)) {
return "Bearer";
}
return tokenType;
}

/**
* Returns the refresh token, if available. May be null for non-refreshable tokens.
*
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,19 @@ private static Stream<Arguments> provideTokenSourceTestCases() {
Arguments.of(
"Token with custom type",
new Token(TOKEN_VALUE, "Custom", expiry),
Collections.singletonMap("Authorization", "Custom " + TOKEN_VALUE)));
Collections.singletonMap("Authorization", "Custom " + TOKEN_VALUE)),
Arguments.of(
"Lowercase bearer is canonicalized",
new Token(TOKEN_VALUE, "bearer", expiry),
Collections.singletonMap("Authorization", "Bearer " + TOKEN_VALUE)),
Arguments.of(
"Uppercase BEARER is canonicalized",
new Token(TOKEN_VALUE, "BEARER", expiry),
Collections.singletonMap("Authorization", "Bearer " + TOKEN_VALUE)),
Arguments.of(
"Mixed-case BeArEr is canonicalized",
new Token(TOKEN_VALUE, "BeArEr", expiry),
Collections.singletonMap("Authorization", "Bearer " + TOKEN_VALUE)));
}

@ParameterizedTest(name = "{0}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,20 @@ void createRefreshableToken() {
assertEquals(refreshToken, token.getRefreshToken());
assertEquals(currentInstant.plusSeconds(300), token.getExpiry());
}

@Test
void canonicalTokenTypeNormalizesBearerCasing() {
Instant expiry = currentInstant.plusSeconds(300);
assertEquals("Bearer", new Token(accessToken, "Bearer", expiry).getCanonicalTokenType());
assertEquals("Bearer", new Token(accessToken, "bearer", expiry).getCanonicalTokenType());
assertEquals("Bearer", new Token(accessToken, "BEARER", expiry).getCanonicalTokenType());
assertEquals("Bearer", new Token(accessToken, "BeArEr", expiry).getCanonicalTokenType());
}

@Test
void canonicalTokenTypePreservesNonBearerSchemes() {
Instant expiry = currentInstant.plusSeconds(300);
assertEquals("Custom", new Token(accessToken, "Custom", expiry).getCanonicalTokenType());
assertEquals("MAC", new Token(accessToken, "MAC", expiry).getCanonicalTokenType());
}
}
Loading