From b6afe66d32d5ef60d997e364b1cd71d867fd4595 Mon Sep 17 00:00:00 2001 From: Eric Deandrea Date: Fri, 17 Aug 2018 18:53:28 -0400 Subject: [PATCH] Add ServerAuthenticationConverter interface - Adding an ServerAuthenticationConverter interface - Retro-fitting ServerOAuth2LoginAuthenticationTokenConverter, ServerBearerTokenAuthentivationConverter, ServerFormLoginAuthenticationConverter, and ServerHttpBasicAuthenticationConverter to implement ServerAuthenticationConverter - Deprecate existing AuthenticationWebFilter.setAuthenticationConverter and add overloaded one which takes ServerAuthenticationConverter Fixes gh-5338 --- ...uth2LoginAuthenticationTokenConverter.java | 15 +++---- ...LoginAuthenticationTokenConverterTest.java | 2 +- ...verBearerTokenAuthenticationConverter.java | 7 ++-- ...arerTokenAuthenticationConverterTests.java | 2 +- ...erverFormLoginAuthenticationConverter.java | 7 ++-- ...erverHttpBasicAuthenticationConverter.java | 6 +-- .../AuthenticationWebFilter.java | 22 ++++++++-- .../ServerAuthenticationConverter.java | 40 +++++++++++++++++++ ...FormLoginAuthenticationConverterTests.java | 6 +-- ...HttpBasicAuthenticationConverterTests.java | 2 +- .../AuthenticationWebFilterTests.java | 23 ++++------- 11 files changed, 88 insertions(+), 44 deletions(-) create mode 100644 web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationConverter.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverter.java index 80d62789ec..982bc037ad 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverter.java @@ -16,8 +16,6 @@ package org.springframework.security.oauth2.client.web; -import java.util.function.Function; - import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; @@ -27,6 +25,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExch import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; +import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; @@ -34,16 +33,14 @@ import org.springframework.web.util.UriComponentsBuilder; import reactor.core.publisher.Mono; - /** * Converts from a {@link ServerWebExchange} to an {@link OAuth2LoginAuthenticationToken} that can be authenticated. The * converter does not validate any errors it only performs a conversion. * @author Rob Winch * @since 5.1 - * @see org.springframework.security.web.server.authentication.AuthenticationWebFilter#setAuthenticationConverter(Function) + * @see org.springframework.security.web.server.authentication.AuthenticationWebFilter#setAuthenticationConverter(ServerAuthenticationConverter) */ -public class ServerOAuth2LoginAuthenticationTokenConverter implements - Function> { +public class ServerOAuth2LoginAuthenticationTokenConverter implements ServerAuthenticationConverter { static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found"; @@ -72,7 +69,7 @@ public class ServerOAuth2LoginAuthenticationTokenConverter implements } @Override - public Mono apply(ServerWebExchange serverWebExchange) { + public Mono convert(ServerWebExchange serverWebExchange) { return this.authorizationRequestRepository.removeAuthorizationRequest(serverWebExchange) .switchIfEmpty(oauth2AuthenticationException(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE)) .flatMap(authorizationRequest -> authenticationRequest(serverWebExchange, authorizationRequest)); @@ -97,14 +94,14 @@ public class ServerOAuth2LoginAuthenticationTokenConverter implements }) .switchIfEmpty(oauth2AuthenticationException(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE)) .map(clientRegistration -> { - OAuth2AuthorizationResponse authorizationResponse = convert(exchange); + OAuth2AuthorizationResponse authorizationResponse = convertResponse(exchange); OAuth2LoginAuthenticationToken authenticationRequest = new OAuth2LoginAuthenticationToken( clientRegistration, new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse)); return authenticationRequest; }); } - private static OAuth2AuthorizationResponse convert(ServerWebExchange exchange) { + private static OAuth2AuthorizationResponse convertResponse(ServerWebExchange exchange) { MultiValueMap queryParams = exchange.getRequest() .getQueryParams(); String redirectUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI()) diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverterTest.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverterTest.java index 8ceb5b1727..ac20d8a508 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverterTest.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/ServerOAuth2LoginAuthenticationTokenConverterTest.java @@ -141,6 +141,6 @@ public class ServerOAuth2LoginAuthenticationTokenConverterTest { private OAuth2LoginAuthenticationToken applyConverter() { MockServerWebExchange exchange = MockServerWebExchange.from(this.request); - return (OAuth2LoginAuthenticationToken) this.converter.apply(exchange).block(); + return (OAuth2LoginAuthenticationToken) this.converter.convert(exchange).block(); } } diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java index 1025dfb9c3..14f1f9f767 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java @@ -25,11 +25,11 @@ 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 org.springframework.security.web.server.authentication.ServerAuthenticationConverter; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; -import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -41,13 +41,12 @@ import java.util.regex.Pattern; * @since 5.1 * @see RFC 6750 Section 2: Authenticated Requests */ -public class ServerBearerTokenAuthenticationConverter implements - Function> { +public class ServerBearerTokenAuthenticationConverter implements ServerAuthenticationConverter { private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-._~+/]+)=*$"); private boolean allowUriQueryParameter = false; - public Mono apply(ServerWebExchange exchange) { + public Mono convert(ServerWebExchange exchange) { return Mono.justOrEmpty(this.token(exchange.getRequest())) .map(BearerTokenAuthenticationToken::new); } diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java index 3326d17c9a..f4b9a09967 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java @@ -129,6 +129,6 @@ public class ServerBearerTokenAuthenticationConverterTests { private BearerTokenAuthenticationToken convertToToken(MockServerHttpRequest request) { MockServerWebExchange exchange = MockServerWebExchange.from(request); - return this.converter.apply(exchange).cast(BearerTokenAuthenticationToken.class).block(); + return this.converter.convert(exchange).cast(BearerTokenAuthenticationToken.class).block(); } } diff --git a/web/src/main/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverter.java b/web/src/main/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverter.java index 33ff40774d..7463ea3fa1 100644 --- a/web/src/main/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverter.java +++ b/web/src/main/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverter.java @@ -15,8 +15,7 @@ */ package org.springframework.security.web.server; -import java.util.function.Function; - +import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; import org.springframework.util.Assert; import reactor.core.publisher.Mono; @@ -32,14 +31,14 @@ import org.springframework.web.server.ServerWebExchange; * @author Rob Winch * @since 5.0 */ -public class ServerFormLoginAuthenticationConverter implements Function> { +public class ServerFormLoginAuthenticationConverter implements ServerAuthenticationConverter { private String usernameParameter = "username"; private String passwordParameter = "password"; @Override - public Mono apply(ServerWebExchange exchange) { + public Mono convert(ServerWebExchange exchange) { return exchange.getFormData() .map( data -> createAuthentication(data)); } diff --git a/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java b/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java index 961cbfb31f..245ecfd208 100644 --- a/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java +++ b/web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java @@ -16,12 +16,12 @@ package org.springframework.security.web.server; import java.util.Base64; -import java.util.function.Function; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @@ -32,12 +32,12 @@ import reactor.core.publisher.Mono; * @author Rob Winch * @since 5.0 */ -public class ServerHttpBasicAuthenticationConverter implements Function> { +public class ServerHttpBasicAuthenticationConverter implements ServerAuthenticationConverter { public static final String BASIC = "Basic "; @Override - public Mono apply(ServerWebExchange exchange) { + public Mono convert(ServerWebExchange exchange) { ServerHttpRequest request = exchange.getRequest(); String authorization = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION); diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java b/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java index bac0340579..846fd4cd06 100644 --- a/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java +++ b/web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java @@ -67,7 +67,7 @@ public class AuthenticationWebFilter implements WebFilter { private ServerAuthenticationSuccessHandler authenticationSuccessHandler = new WebFilterChainServerAuthenticationSuccessHandler(); - private Function> authenticationConverter = new ServerHttpBasicAuthenticationConverter(); + private ServerAuthenticationConverter authenticationConverter = new ServerHttpBasicAuthenticationConverter(); private ServerAuthenticationFailureHandler authenticationFailureHandler = new ServerAuthenticationEntryPointFailureHandler(new HttpBasicServerAuthenticationEntryPoint()); @@ -88,7 +88,7 @@ public class AuthenticationWebFilter implements WebFilter { public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { return this.requiresAuthenticationMatcher.matches(exchange) .filter( matchResult -> matchResult.isMatch()) - .flatMap( matchResult -> this.authenticationConverter.apply(exchange)) + .flatMap( matchResult -> this.authenticationConverter.convert(exchange)) .switchIfEmpty(chain.filter(exchange).then(Mono.empty())) .flatMap( token -> authenticate(exchange, chain, token)); } @@ -138,8 +138,24 @@ public class AuthenticationWebFilter implements WebFilter { * that no authentication attempt should be made. The default converter is * {@link ServerHttpBasicAuthenticationConverter} * @param authenticationConverter the converter to use + * @deprecated As of 5.1 in favor of {@link #setAuthenticationConverter(ServerAuthenticationConverter)} + * @see #setAuthenticationConverter(ServerAuthenticationConverter) */ + @Deprecated public void setAuthenticationConverter(Function> authenticationConverter) { + Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); + setAuthenticationConverter((ServerAuthenticationConverter) authenticationConverter); + } + + /** + * Sets the strategy used for converting from a {@link ServerWebExchange} to an {@link Authentication} used for + * authenticating with the provided {@link ReactiveAuthenticationManager}. If the result is empty, then it signals + * that no authentication attempt should be made. The default converter is + * {@link ServerHttpBasicAuthenticationConverter} + * @param authenticationConverter the converter to use + * @since 5.1 + */ + public void setAuthenticationConverter(ServerAuthenticationConverter authenticationConverter) { Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); this.authenticationConverter = authenticationConverter; } @@ -156,7 +172,7 @@ public class AuthenticationWebFilter implements WebFilter { /** * Sets the matcher used to determine when creating an {@link Authentication} from - * {@link #setAuthenticationConverter(Function)} to be authentication. If the converter returns an empty + * {@link #setAuthenticationConverter(ServerAuthenticationConverter)} to be authentication. If the converter returns an empty * result, then no authentication is attempted. The default is any request * @param requiresAuthenticationMatcher the matcher to use. Cannot be null. */ diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationConverter.java b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationConverter.java new file mode 100644 index 0000000000..80146ebf36 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/server/authentication/ServerAuthenticationConverter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.server.authentication; + +import org.springframework.security.core.Authentication; +import org.springframework.web.server.ServerWebExchange; + +import reactor.core.publisher.Mono; + +/** + * A strategy used for converting from a {@link ServerWebExchange} to an {@link Authentication} used for + * authenticating with a provided {@link org.springframework.security.authentication.ReactiveAuthenticationManager}. + * If the result is {@link Mono#empty()}, then it signals that no authentication attempt should be made. + * + * @author Eric Deandrea + * @since 5.1 + */ +@FunctionalInterface +public interface ServerAuthenticationConverter { + /** + * Converts a {@link ServerWebExchange} to an {@link Authentication} + * @param exchange The {@link ServerWebExchange} + * @return A {@link Mono} representing an {@link Authentication} + */ + Mono convert(ServerWebExchange exchange); +} diff --git a/web/src/test/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverterTests.java b/web/src/test/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverterTests.java index b10c1027eb..294b532079 100644 --- a/web/src/test/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/ServerFormLoginAuthenticationConverterTests.java @@ -55,7 +55,7 @@ public class ServerFormLoginAuthenticationConverterTests { this.data.add("username", username); this.data.add("password", password); - Authentication authentication = this.converter.apply(this.exchange).block(); + Authentication authentication = this.converter.convert(this.exchange).block(); assertThat(authentication.getName()).isEqualTo(username); assertThat(authentication.getCredentials()).isEqualTo(password); @@ -73,7 +73,7 @@ public class ServerFormLoginAuthenticationConverterTests { this.data.add(usernameParameter, username); this.data.add(passwordParameter, password); - Authentication authentication = this.converter.apply(this.exchange).block(); + Authentication authentication = this.converter.convert(this.exchange).block(); assertThat(authentication.getName()).isEqualTo(username); assertThat(authentication.getCredentials()).isEqualTo(password); @@ -82,7 +82,7 @@ public class ServerFormLoginAuthenticationConverterTests { @Test public void applyWhenNoDataThenCreatesTokenSuccess() { - Authentication authentication = this.converter.apply(this.exchange).block(); + Authentication authentication = this.converter.convert(this.exchange).block(); assertThat(authentication.getName()).isNullOrEmpty(); assertThat(authentication.getCredentials()).isNull(); diff --git a/web/src/test/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverterTests.java b/web/src/test/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverterTests.java index 5b130ee6c5..375360b17f 100644 --- a/web/src/test/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverterTests.java @@ -96,6 +96,6 @@ public class ServerHttpBasicAuthenticationConverterTests { } private Mono apply(MockServerHttpRequest.BaseBuilder request) { - return this.converter.apply(MockServerWebExchange.from(this.request.build())); + return this.converter.convert(MockServerWebExchange.from(this.request.build())); } } diff --git a/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java b/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java index 9aad8dc296..5715dbd237 100644 --- a/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/authentication/AuthenticationWebFilterTests.java @@ -16,8 +16,6 @@ package org.springframework.security.web.server.authentication; -import java.util.function.Function; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,16 +32,11 @@ import org.springframework.security.web.server.context.ServerSecurityContextRepo import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; import org.springframework.test.web.reactive.server.EntityExchangeResult; import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.web.server.ServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - +import static org.mockito.Mockito.*; /** * @author Rob Winch @@ -54,7 +47,7 @@ public class AuthenticationWebFilterTests { @Mock private ServerAuthenticationSuccessHandler successHandler; @Mock - private Function> authenticationConverter; + private ServerAuthenticationConverter authenticationConverter; @Mock private ReactiveAuthenticationManager authenticationManager; @Mock @@ -136,7 +129,7 @@ public class AuthenticationWebFilterTests { @Test public void filterWhenConvertEmptyThenOk() { - when(this.authenticationConverter.apply(any())).thenReturn(Mono.empty()); + when(this.authenticationConverter.convert(any())).thenReturn(Mono.empty()); WebTestClient client = WebTestClientBuilder .bindToWebFilters(this.filter) @@ -157,7 +150,7 @@ public class AuthenticationWebFilterTests { @Test public void filterWhenConvertErrorThenServerError() { - when(this.authenticationConverter.apply(any())).thenReturn(Mono.error(new RuntimeException("Unexpected"))); + when(this.authenticationConverter.convert(any())).thenReturn(Mono.error(new RuntimeException("Unexpected"))); WebTestClient client = WebTestClientBuilder .bindToWebFilters(this.filter) @@ -178,7 +171,7 @@ public class AuthenticationWebFilterTests { @Test public void filterWhenConvertAndAuthenticationSuccessThenSuccess() { Mono authentication = Mono.just(new TestingAuthenticationToken("test", "this", "ROLE_USER")); - when(this.authenticationConverter.apply(any())).thenReturn(authentication); + when(this.authenticationConverter.convert(any())).thenReturn(authentication); when(this.authenticationManager.authenticate(any())).thenReturn(authentication); when(this.successHandler.onAuthenticationSuccess(any(), any())).thenReturn(Mono.empty()); when(this.securityContextRepository.save(any(), any())).thenAnswer( a -> Mono.just(a.getArguments()[0])); @@ -203,7 +196,7 @@ public class AuthenticationWebFilterTests { @Test public void filterWhenConvertAndAuthenticationEmptyThenServerError() { Mono authentication = Mono.just(new TestingAuthenticationToken("test", "this", "ROLE_USER")); - when(this.authenticationConverter.apply(any())).thenReturn(authentication); + when(this.authenticationConverter.convert(any())).thenReturn(authentication); when(this.authenticationManager.authenticate(any())).thenReturn(Mono.empty()); WebTestClient client = WebTestClientBuilder @@ -245,7 +238,7 @@ public class AuthenticationWebFilterTests { @Test public void filterWhenConvertAndAuthenticationFailThenEntryPoint() { Mono authentication = Mono.just(new TestingAuthenticationToken("test", "this", "ROLE_USER")); - when(this.authenticationConverter.apply(any())).thenReturn(authentication); + when(this.authenticationConverter.convert(any())).thenReturn(authentication); when(this.authenticationManager.authenticate(any())).thenReturn(Mono.error(new BadCredentialsException("Failed"))); when(this.failureHandler.onAuthenticationFailure(any(), any())).thenReturn(Mono.empty()); @@ -268,7 +261,7 @@ public class AuthenticationWebFilterTests { @Test public void filterWhenConvertAndAuthenticationExceptionThenServerError() { Mono authentication = Mono.just(new TestingAuthenticationToken("test", "this", "ROLE_USER")); - when(this.authenticationConverter.apply(any())).thenReturn(authentication); + when(this.authenticationConverter.convert(any())).thenReturn(authentication); when(this.authenticationManager.authenticate(any())).thenReturn(Mono.error(new RuntimeException("Failed"))); WebTestClient client = WebTestClientBuilder