From 464e506429b4d28cc08eca3c4fb572a639b9e539 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 21 Mar 2025 17:43:39 -0600 Subject: [PATCH] Polish ExceptionTranslateWebFilter - Isolated exception construction - Isolated entry point subscription Issue gh-16444 --- .../ExceptionTranslationWebFilter.java | 32 +++++++++++-------- .../ExceptionTranslationWebFilterTests.java | 3 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java b/web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java index 6be2a6258e..01d990f177 100644 --- a/web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java +++ b/web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 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. @@ -50,14 +50,19 @@ public class ExceptionTranslationWebFilter implements WebFilter { @Override public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange) - .onErrorResume(AccessDeniedException.class, (denied) -> exchange.getPrincipal() - .filter((principal) -> (!(principal instanceof Authentication) || (principal instanceof Authentication - && (this.authenticationTrustResolver.isAuthenticated((Authentication) principal))))) - .switchIfEmpty(commenceAuthentication(exchange, - new InsufficientAuthenticationException( - "Full authentication is required to access this resource"))) - .flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)) - .then()); + .onErrorResume(AccessDeniedException.class, + (denied) -> exchange.getPrincipal() + .switchIfEmpty(Mono.defer(() -> commenceAuthentication(exchange, null))) + .flatMap((principal) -> { + if (!(principal instanceof Authentication authentication)) { + return this.accessDeniedHandler.handle(exchange, denied); + } + if (this.authenticationTrustResolver.isAuthenticated(authentication)) { + return this.accessDeniedHandler.handle(exchange, denied); + } + return commenceAuthentication(exchange, authentication); + }) + .then()); } /** @@ -92,10 +97,11 @@ public class ExceptionTranslationWebFilter implements WebFilter { this.authenticationTrustResolver = authenticationTrustResolver; } - private Mono commenceAuthentication(ServerWebExchange exchange, AuthenticationException denied) { - return this.authenticationEntryPoint - .commence(exchange, new AuthenticationCredentialsNotFoundException("Not Authenticated", denied)) - .then(Mono.empty()); + private Mono commenceAuthentication(ServerWebExchange exchange, Authentication authentication) { + AuthenticationException cause = new InsufficientAuthenticationException( + "Full authentication is required to access this resource"); + AuthenticationException ex = new AuthenticationCredentialsNotFoundException("Not Authenticated", cause); + return this.authenticationEntryPoint.commence(exchange, ex).then(Mono.empty()); } } diff --git a/web/src/test/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilterTests.java b/web/src/test/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilterTests.java index e323572b1a..baed5b52d1 100644 --- a/web/src/test/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 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. @@ -129,7 +129,6 @@ public class ExceptionTranslationWebFilterTests { @Test public void filterWhenAccessDeniedExceptionAndAuthenticatedThenHandled() { given(this.deniedHandler.handle(any(), any())).willReturn(this.deniedPublisher.mono()); - given(this.entryPoint.commence(any(), any())).willReturn(this.entryPointPublisher.mono()); given(this.exchange.getPrincipal()).willReturn(Mono.just(this.principal)); given(this.chain.filter(this.exchange)).willReturn(Mono.error(new AccessDeniedException("Not Authorized"))); StepVerifier.create(this.filter.filter(this.exchange, this.chain)).expectComplete().verify();