diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManager.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManager.java index b246fb939b..f25933cf9c 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManager.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManager.java @@ -40,10 +40,13 @@ import org.springframework.util.Assert; * @since 5.1 */ public final class JwtReactiveAuthenticationManager implements ReactiveAuthenticationManager { + private final ReactiveJwtDecoder jwtDecoder; + private Converter> jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverterAdapter(new JwtAuthenticationConverter()); - private final ReactiveJwtDecoder jwtDecoder; + private static final OAuth2Error DEFAULT_INVALID_TOKEN = + invalidToken("An error occurred while attempting to decode the Jwt: Invalid token"); public JwtReactiveAuthenticationManager(ReactiveJwtDecoder jwtDecoder) { Assert.notNull(jwtDecoder, "jwtDecoder cannot be null"); @@ -80,10 +83,15 @@ public final class JwtReactiveAuthenticationManager implements ReactiveAuthentic } private static OAuth2Error invalidToken(String message) { - return new BearerTokenError( - BearerTokenErrorCodes.INVALID_TOKEN, - HttpStatus.UNAUTHORIZED, - message, - "https://tools.ietf.org/html/rfc6750#section-3.1"); + try { + return new BearerTokenError( + BearerTokenErrorCodes.INVALID_TOKEN, + HttpStatus.UNAUTHORIZED, + message, + "https://tools.ietf.org/html/rfc6750#section-3.1"); + } catch (IllegalArgumentException malformed) { + // some third-party library error messages are not suitable for RFC 6750's error message charset + return DEFAULT_INVALID_TOKEN; + } } } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java index 2e52bd69cb..536f76cfec 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/JwtReactiveAuthenticationManagerTests.java @@ -88,6 +88,19 @@ public class JwtReactiveAuthenticationManagerTests { .isInstanceOf(OAuth2AuthenticationException.class); } + // gh-7549 + @Test + public void authenticateWhenDecoderThrowsIncompatibleErrorMessageThenWrapsWithGenericOne() { + BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1"); + when(this.jwtDecoder.decode(token.getToken())).thenThrow(new JwtException("with \"invalid\" chars")); + + assertThatCode(() -> this.manager.authenticate(token).block()) + .isInstanceOf(OAuth2AuthenticationException.class) + .hasFieldOrPropertyWithValue( + "error.description", + "An error occurred while attempting to decode the Jwt: Invalid token"); + } + @Test public void authenticateWhenNotJwtExceptionThenPropagates() { BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");