Skip to content

Commit 809e639

Browse files
committed
fix(oauth2): allow multiple spaces in Bearer token header
Update DefaultBearerTokenResolver and ServerBearerTokenAuthenticationConverter to allow one or more spaces between 'Bearer' and the token, as permitted by RFC 6750. Closes gh-19500 Signed-off-by: zanarelli <zanarelli.dev@gmail.com>
1 parent d449950 commit 809e639

4 files changed

Lines changed: 69 additions & 2 deletions

File tree

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver {
4242

4343
private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token";
4444

45-
private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$",
45+
private static final Pattern authorizationPattern = Pattern.compile("^Bearer +(?<token>[a-zA-Z0-9-._~+/]+=*)$",
4646
Pattern.CASE_INSENSITIVE);
4747

4848
private boolean allowFormEncodedBodyParameter = false;

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class ServerBearerTokenAuthenticationConverter implements ServerAuthentic
5252

5353
private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token";
5454

55-
private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$",
55+
private static final Pattern authorizationPattern = Pattern.compile("^Bearer +(?<token>[a-zA-Z0-9-._~+/]+=*)$",
5656
Pattern.CASE_INSENSITIVE);
5757

5858
private boolean allowFormEncodedBodyParameter = false;

oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,39 @@ public void resolveWhenValidHeaderIsPresentThenTokenIsResolved() {
5555
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
5656
}
5757

58+
// gh-19500
59+
@Test
60+
public void resolveWhenValidHeaderWithOneSpaceIsPresentThenTokenIsResolved() {
61+
MockHttpServletRequest request = new MockHttpServletRequest();
62+
request.addHeader("Authorization", "Bearer " + TEST_TOKEN);
63+
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
64+
}
65+
66+
// gh-19500
67+
@Test
68+
public void resolveWhenValidHeaderWithTwoSpacesIsPresentThenTokenIsResolved() {
69+
MockHttpServletRequest request = new MockHttpServletRequest();
70+
request.addHeader("Authorization", "Bearer " + TEST_TOKEN);
71+
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
72+
}
73+
74+
// gh-19500
75+
@Test
76+
public void resolveWhenValidHeaderWithThreeSpacesIsPresentThenTokenIsResolved() {
77+
MockHttpServletRequest request = new MockHttpServletRequest();
78+
request.addHeader("Authorization", "Bearer " + TEST_TOKEN);
79+
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
80+
}
81+
82+
// gh-19500
83+
@Test
84+
public void resolveWhenHeaderWithZeroSpacesIsPresentThenTokenIsNotResolved() {
85+
MockHttpServletRequest request = new MockHttpServletRequest();
86+
request.addHeader("Authorization", "Bearer" + TEST_TOKEN);
87+
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.resolver.resolve(request))
88+
.withMessageContaining(("Bearer token is malformed"));
89+
}
90+
5891
// gh-8502
5992
@Test
6093
public void resolveWhenHeaderEndsWithPaddingIndicatorThenTokenIsResolved() {

oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,40 @@ public void resolveWhenValidHeaderIsPresentThenTokenIsResolved() {
6060
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
6161
}
6262

63+
// gh-19500
64+
@Test
65+
public void resolveWhenValidHeaderWithOneSpaceIsPresentThenTokenIsResolved() {
66+
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
67+
.header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN);
68+
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
69+
}
70+
71+
// gh-19500
72+
@Test
73+
public void resolveWhenValidHeaderWithTwoSpacesIsPresentThenTokenIsResolved() {
74+
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
75+
.header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN);
76+
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
77+
}
78+
79+
// gh-19500
80+
@Test
81+
public void resolveWhenValidHeaderWithThreeSpacesIsPresentThenTokenIsResolved() {
82+
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
83+
.header(HttpHeaders.AUTHORIZATION, "Bearer " + TEST_TOKEN);
84+
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
85+
}
86+
87+
// gh-19500
88+
@Test
89+
public void resolveWhenHeaderWithZeroSpacesIsPresentThenTokenIsNotResolved() {
90+
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest.get("/")
91+
.header(HttpHeaders.AUTHORIZATION, "Bearer" + TEST_TOKEN);
92+
assertThatExceptionOfType(OAuth2AuthenticationException.class)
93+
.isThrownBy(() -> convertToToken(request))
94+
.withMessageContaining("Bearer token is malformed");
95+
}
96+
6397
// gh-8502
6498
@Test
6599
public void resolveWhenHeaderEndsWithPaddingIndicatorThenTokenIsResolved() {

0 commit comments

Comments
 (0)