From 4c6fef82b9b8d2a985305bcd1c0d59cc60245583 Mon Sep 17 00:00:00 2001 From: Hyeongi Jeong Date: Tue, 15 Oct 2024 16:21:01 +0900 Subject: [PATCH 1/2] Fix error when Bearer token is requested with empty string Issue gh-15885 --- .../web/DefaultBearerTokenResolver.java | 5 +++ ...verBearerTokenAuthenticationConverter.java | 5 +++ .../web/DefaultBearerTokenResolverTests.java | 34 +++++++++++++++++++ ...arerTokenAuthenticationConverterTests.java | 4 +-- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java index da357ca9c99..1d61e11b0f6 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java @@ -64,6 +64,11 @@ public String resolve(final HttpServletRequest request) { return authorizationHeaderToken; } if (parameterToken != null && isParameterTokenEnabledForRequest(request)) { + if (!StringUtils.hasText(parameterToken)) { + final BearerTokenError error = BearerTokenErrors + .invalidRequest("The requested token parameter is an empty string"); + throw new OAuth2AuthenticationException(error); + } return parameterToken; } return null; diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java index d30cd8e05af..4f8d33c6d09 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java @@ -78,6 +78,11 @@ private String token(ServerHttpRequest request) { return authorizationHeaderToken; } if (parameterToken != null && isParameterTokenSupportedForRequest(request)) { + if (!StringUtils.hasText(parameterToken)) { + final BearerTokenError error = BearerTokenErrors + .invalidRequest("The requested token parameter is an empty string"); + throw new OAuth2AuthenticationException(error); + } return parameterToken; } return null; diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java index e5cfca01c33..7937a699fdc 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java @@ -21,8 +21,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.server.resource.BearerTokenError; +import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -258,4 +261,35 @@ public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResol assertThat(this.resolver.resolve(request)).isNull(); } + @Test + public void resolveWhenQueryParameterIsPresentAndEmptyStringThenTokenIsNotResolved() { + this.resolver.setAllowUriQueryParameter(true); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("GET"); + request.addParameter("access_token", ""); + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.resolver.resolve(request)) + .withMessageContaining("The requested token parameter is an empty string") + .satisfies((e) -> { + BearerTokenError error = (BearerTokenError) e.getError(); + assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST); + assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST); + }); + } + + @Test + public void resolveWhenFormParameterIsPresentAndEmptyStringThenTokenIsNotResolved() { + this.resolver.setAllowFormEncodedBodyParameter(true); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setContentType("application/x-www-form-urlencoded"); + request.addParameter("access_token", ""); + assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.resolver.resolve(request)) + .withMessageContaining("The requested token parameter is an empty string") + .satisfies((e) -> { + BearerTokenError error = (BearerTokenError) e.getError(); + assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST); + assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST); + }); + } + } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java index 6d9c7a5b98f..b43329fc97c 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java @@ -187,9 +187,9 @@ public void resolveWhenQueryParameterIsEmptyAndSupportedThenOAuth2Authentication .isThrownBy(() -> convertToToken(request)) .satisfies((ex) -> { BearerTokenError error = (BearerTokenError) ex.getError(); - assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN); + assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST); assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1"); - assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED); + assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST); }); // @formatter:on } From 86f3cd6dc7c7c7bc0e44e934d8d0c9405ead1b89 Mon Sep 17 00:00:00 2001 From: Steve Riesenberg <5248162+sjohnr@users.noreply.github.com> Date: Mon, 4 Nov 2024 13:08:59 -0600 Subject: [PATCH 2/2] Polish gh-15940 Closes gh-15885 --- .../server/resource/web/DefaultBearerTokenResolver.java | 6 +++--- .../ServerBearerTokenAuthenticationConverter.java | 4 ++-- .../resource/web/DefaultBearerTokenResolverTests.java | 2 +- .../ServerBearerTokenAuthenticationConverterTests.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java index 1d61e11b0f6..d238e870178 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,7 +57,7 @@ public String resolve(final HttpServletRequest request) { ? resolveFromRequestParameters(request) : null; if (authorizationHeaderToken != null) { if (parameterToken != null) { - final BearerTokenError error = BearerTokenErrors + BearerTokenError error = BearerTokenErrors .invalidRequest("Found multiple bearer tokens in the request"); throw new OAuth2AuthenticationException(error); } @@ -65,7 +65,7 @@ public String resolve(final HttpServletRequest request) { } if (parameterToken != null && isParameterTokenEnabledForRequest(request)) { if (!StringUtils.hasText(parameterToken)) { - final BearerTokenError error = BearerTokenErrors + BearerTokenError error = BearerTokenErrors .invalidRequest("The requested token parameter is an empty string"); throw new OAuth2AuthenticationException(error); } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java index 4f8d33c6d09..bd07c59b747 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,7 +79,7 @@ private String token(ServerHttpRequest request) { } if (parameterToken != null && isParameterTokenSupportedForRequest(request)) { if (!StringUtils.hasText(parameterToken)) { - final BearerTokenError error = BearerTokenErrors + BearerTokenError error = BearerTokenErrors .invalidRequest("The requested token parameter is an empty string"); throw new OAuth2AuthenticationException(error); } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java index 7937a699fdc..f04fb69a3df 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java index b43329fc97c..1f4b17697fd 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.