Skip to content

Commit fe97325

Browse files
committed
ServerBearerTokenAuthenticationConverter Handles Empty Tokens
Previously ServerBearerTokenAuthenticationConverter would throw an IllegalArgumentException when the access token in a URI was empty String. It also incorrectly provided HttpStatus.BAD_REQUEST for an empty String access token in the headers. This changes ServerBearerTokenAuthenticationConverter to consistently throw a OAuth2AuthenticationException with an HttpStatus.UNAUTHORIZED Fixes spring-projectsgh-7011
1 parent 878d262 commit fe97325

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ public class ServerBearerTokenAuthenticationConverter
5050
private boolean allowUriQueryParameter = false;
5151

5252
public Mono<Authentication> convert(ServerWebExchange exchange) {
53-
return Mono.justOrEmpty(this.token(exchange.getRequest()))
54-
.map(BearerTokenAuthenticationToken::new);
53+
return Mono.justOrEmpty(token(exchange.getRequest()))
54+
.map(token -> {
55+
if (token.isEmpty()) {
56+
BearerTokenError error = invalidTokenError();
57+
throw new OAuth2AuthenticationException(error);
58+
}
59+
return new BearerTokenAuthenticationToken(token);
60+
});
5561
}
5662

5763
private String token(ServerHttpRequest request) {
@@ -90,11 +96,8 @@ private static String resolveFromAuthorizationHeader(HttpHeaders headers) {
9096
if (StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
9197
Matcher matcher = authorizationPattern.matcher(authorization);
9298

93-
if ( !matcher.matches() ) {
94-
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN,
95-
HttpStatus.BAD_REQUEST,
96-
"Bearer token is malformed",
97-
"https://tools.ietf.org/html/rfc6750#section-3.1");
99+
if (!matcher.matches() ) {
100+
BearerTokenError error = invalidTokenError();
98101
throw new OAuth2AuthenticationException(error);
99102
}
100103

@@ -103,6 +106,13 @@ private static String resolveFromAuthorizationHeader(HttpHeaders headers) {
103106
return null;
104107
}
105108

109+
private static BearerTokenError invalidTokenError() {
110+
return new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN,
111+
HttpStatus.UNAUTHORIZED,
112+
"Bearer token is malformed",
113+
"https://tools.ietf.org/html/rfc6750#section-3.1");
114+
}
115+
106116
private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) {
107117
return this.allowUriQueryParameter && HttpMethod.GET.equals(request.getMethod());
108118
}

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,19 @@
1919
import org.junit.Before;
2020
import org.junit.Test;
2121
import org.springframework.http.HttpHeaders;
22+
import org.springframework.http.HttpStatus;
2223
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
2324
import org.springframework.mock.web.server.MockServerWebExchange;
2425
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
2526
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
27+
import org.springframework.security.oauth2.server.resource.BearerTokenError;
28+
import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
2629

2730
import java.util.Base64;
2831

2932
import static org.assertj.core.api.Assertions.assertThat;
3033
import static org.assertj.core.api.Assertions.assertThatCode;
34+
import static org.assertj.core.api.Assertions.catchThrowableOfType;
3135

3236
/**
3337
* @author Rob Winch
@@ -52,6 +56,21 @@ public void resolveWhenValidHeaderIsPresentThenTokenIsResolved() {
5256
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
5357
}
5458

59+
// gh-7011
60+
@Test
61+
public void resolveWhenValidHeaderIsEmptyStringThenTokenIsResolved() {
62+
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
63+
.get("/")
64+
.header(HttpHeaders.AUTHORIZATION, "Bearer ");
65+
66+
OAuth2AuthenticationException expected = catchThrowableOfType(() -> convertToToken(request),
67+
OAuth2AuthenticationException.class);
68+
BearerTokenError error = (BearerTokenError) expected.getError();
69+
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
70+
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
71+
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
72+
}
73+
5574
@Test
5675
public void resolveWhenLowercaseHeaderIsPresentThenTokenIsResolved() {
5776
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
@@ -123,6 +142,23 @@ public void resolveWhenQueryParameterIsPresentAndSupportedThenTokenIsResolved()
123142
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
124143
}
125144

145+
// gh-7011
146+
@Test
147+
public void resolveWhenQueryParameterIsEmptyAndSupportedThenOAuth2AuthenticationException() {
148+
this.converter.setAllowUriQueryParameter(true);
149+
150+
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
151+
.get("/")
152+
.queryParam("access_token", "");
153+
154+
OAuth2AuthenticationException expected = catchThrowableOfType(() -> convertToToken(request),
155+
OAuth2AuthenticationException.class);
156+
BearerTokenError error = (BearerTokenError) expected.getError();
157+
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
158+
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
159+
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
160+
}
161+
126162
@Test
127163
public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
128164
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest

0 commit comments

Comments
 (0)