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 gh-7011
This commit is contained in:
parent
3c240d0ce3
commit
6f5a443175
|
@ -50,8 +50,14 @@ public class ServerBearerTokenAuthenticationConverter
|
|||
private boolean allowUriQueryParameter = false;
|
||||
|
||||
public Mono<Authentication> convert(ServerWebExchange exchange) {
|
||||
return Mono.justOrEmpty(this.token(exchange.getRequest()))
|
||||
.map(BearerTokenAuthenticationToken::new);
|
||||
return Mono.justOrEmpty(token(exchange.getRequest()))
|
||||
.map(token -> {
|
||||
if (token.isEmpty()) {
|
||||
BearerTokenError error = invalidTokenError();
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
return new BearerTokenAuthenticationToken(token);
|
||||
});
|
||||
}
|
||||
|
||||
private String token(ServerHttpRequest request) {
|
||||
|
@ -90,11 +96,8 @@ public class ServerBearerTokenAuthenticationConverter
|
|||
if (StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
|
||||
Matcher matcher = authorizationPattern.matcher(authorization);
|
||||
|
||||
if ( !matcher.matches() ) {
|
||||
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN,
|
||||
HttpStatus.BAD_REQUEST,
|
||||
"Bearer token is malformed",
|
||||
"https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
if (!matcher.matches() ) {
|
||||
BearerTokenError error = invalidTokenError();
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
|
@ -103,6 +106,13 @@ public class ServerBearerTokenAuthenticationConverter
|
|||
return null;
|
||||
}
|
||||
|
||||
private static BearerTokenError invalidTokenError() {
|
||||
return new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN,
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
"Bearer token is malformed",
|
||||
"https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
}
|
||||
|
||||
private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) {
|
||||
return this.allowUriQueryParameter && HttpMethod.GET.equals(request.getMethod());
|
||||
}
|
||||
|
|
|
@ -19,15 +19,19 @@ package org.springframework.security.oauth2.server.resource.web.server;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenError;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.catchThrowableOfType;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
|
@ -52,6 +56,21 @@ public class ServerBearerTokenAuthenticationConverterTests {
|
|||
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
||||
// gh-7011
|
||||
@Test
|
||||
public void resolveWhenValidHeaderIsEmptyStringThenTokenIsResolved() {
|
||||
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
|
||||
.get("/")
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer ");
|
||||
|
||||
OAuth2AuthenticationException expected = catchThrowableOfType(() -> convertToToken(request),
|
||||
OAuth2AuthenticationException.class);
|
||||
BearerTokenError error = (BearerTokenError) expected.getError();
|
||||
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
|
||||
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenLowercaseHeaderIsPresentThenTokenIsResolved() {
|
||||
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
|
||||
|
@ -123,6 +142,23 @@ public class ServerBearerTokenAuthenticationConverterTests {
|
|||
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
||||
// gh-7011
|
||||
@Test
|
||||
public void resolveWhenQueryParameterIsEmptyAndSupportedThenOAuth2AuthenticationException() {
|
||||
this.converter.setAllowUriQueryParameter(true);
|
||||
|
||||
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
|
||||
.get("/")
|
||||
.queryParam("access_token", "");
|
||||
|
||||
OAuth2AuthenticationException expected = catchThrowableOfType(() -> convertToToken(request),
|
||||
OAuth2AuthenticationException.class);
|
||||
BearerTokenError error = (BearerTokenError) expected.getError();
|
||||
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
|
||||
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
|
||||
MockServerHttpRequest.BaseBuilder<?> request = MockServerHttpRequest
|
||||
|
|
Loading…
Reference in New Issue