Skip to content

Commit cf74ad3

Browse files
ceremorwinch
authored andcommitted
Anonymous in ExceptionTranslationWebFilter
The ExceptionTranslationWebFilter does not support correctly when anonymous authentication is enabled. With this enabled provoked always the execution of the access denied handler, and with this fix it behaves like the ExceptionTranslationFilter (servlet), executing the access denied handler only if the principal is not empty and neither anonymous. Closes gh-9130
1 parent a7fbae8 commit cf74ad3

File tree

2 files changed

+71
-7
lines changed

2 files changed

+71
-7
lines changed

web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,9 +18,18 @@
1818

1919
import reactor.core.publisher.Mono;
2020

21+
import org.springframework.context.MessageSource;
22+
import org.springframework.context.MessageSourceAware;
23+
import org.springframework.context.support.MessageSourceAccessor;
2124
import org.springframework.http.HttpStatus;
2225
import org.springframework.security.access.AccessDeniedException;
2326
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
27+
import org.springframework.security.authentication.AuthenticationTrustResolver;
28+
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
29+
import org.springframework.security.authentication.InsufficientAuthenticationException;
30+
import org.springframework.security.core.Authentication;
31+
import org.springframework.security.core.AuthenticationException;
32+
import org.springframework.security.core.SpringSecurityMessageSource;
2433
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
2534
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
2635
import org.springframework.util.Assert;
@@ -30,20 +39,30 @@
3039

3140
/**
3241
* @author Rob Winch
42+
* @author César Revert
3343
* @since 5.0
3444
*/
35-
public class ExceptionTranslationWebFilter implements WebFilter {
45+
public class ExceptionTranslationWebFilter implements WebFilter, MessageSourceAware {
3646

3747
private ServerAuthenticationEntryPoint authenticationEntryPoint = new HttpBasicServerAuthenticationEntryPoint();
3848

3949
private ServerAccessDeniedHandler accessDeniedHandler = new HttpStatusServerAccessDeniedHandler(
4050
HttpStatus.FORBIDDEN);
4151

52+
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
53+
54+
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
55+
4256
@Override
4357
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
44-
return chain.filter(exchange).onErrorResume(AccessDeniedException.class,
45-
(denied) -> exchange.getPrincipal().switchIfEmpty(commenceAuthentication(exchange, denied))
46-
.flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)));
58+
return chain.filter(exchange).onErrorResume(AccessDeniedException.class, (denied) -> exchange.getPrincipal()
59+
.filter((principal) -> (!(principal instanceof Authentication) || (principal instanceof Authentication
60+
&& !(this.authenticationTrustResolver.isAnonymous((Authentication) principal)))))
61+
.switchIfEmpty(commenceAuthentication(exchange,
62+
new InsufficientAuthenticationException(
63+
this.messages.getMessage("ExceptionTranslationWebFilter.insufficientAuthentication",
64+
"Full authentication is required to access this resource"))))
65+
.flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)).then());
4766
}
4867

4968
/**
@@ -66,7 +85,28 @@ public void setAuthenticationEntryPoint(ServerAuthenticationEntryPoint authentic
6685
this.authenticationEntryPoint = authenticationEntryPoint;
6786
}
6887

69-
private <T> Mono<T> commenceAuthentication(ServerWebExchange exchange, AccessDeniedException denied) {
88+
/**
89+
* Sets the authentication trust resolver.
90+
* @param authenticationTrustResolver the authentication trust resolver to use.
91+
* Default is {@link AuthenticationTrustResolverImpl}
92+
*
93+
* @since 5.5
94+
*/
95+
public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
96+
Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver must not be null");
97+
this.authenticationTrustResolver = authenticationTrustResolver;
98+
}
99+
100+
/**
101+
* @since 5.5
102+
*/
103+
@Override
104+
public void setMessageSource(MessageSource messageSource) {
105+
Assert.notNull(messageSource, "messageSource cannot be null");
106+
this.messages = new MessageSourceAccessor(messageSource);
107+
}
108+
109+
private <T> Mono<T> commenceAuthentication(ServerWebExchange exchange, AuthenticationException denied) {
70110
return this.authenticationEntryPoint
71111
.commence(exchange, new AuthenticationCredentialsNotFoundException("Not Authenticated", denied))
72112
.then(Mono.empty());

web/src/test/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilterTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
import org.springframework.http.HttpStatus;
3131
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
3232
import org.springframework.security.access.AccessDeniedException;
33+
import org.springframework.security.authentication.AnonymousAuthenticationToken;
3334
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
3435
import org.springframework.web.server.ServerWebExchange;
3536
import org.springframework.web.server.WebFilterChain;
@@ -41,6 +42,7 @@
4142

4243
/**
4344
* @author Rob Winch
45+
* @author César Revert
4446
* @since 5.0
4547
*/
4648
@RunWith(MockitoJUnitRunner.class)
@@ -49,6 +51,9 @@ public class ExceptionTranslationWebFilterTests {
4951
@Mock
5052
private Principal principal;
5153

54+
@Mock
55+
private AnonymousAuthenticationToken anonymousPrincipal;
56+
5257
@Mock
5358
private ServerWebExchange exchange;
5459

@@ -129,6 +134,15 @@ public void filterWhenAccessDeniedExceptionAndAuthenticatedThenHandled() {
129134
this.entryPointPublisher.assertWasNotSubscribed();
130135
}
131136

137+
@Test
138+
public void filterWhenAccessDeniedExceptionAndAnonymousAuthenticatedThenHandled() {
139+
given(this.exchange.getPrincipal()).willReturn(Mono.just(this.anonymousPrincipal));
140+
given(this.chain.filter(this.exchange)).willReturn(Mono.error(new AccessDeniedException("Not Authorized")));
141+
StepVerifier.create(this.filter.filter(this.exchange, this.chain)).expectComplete().verify();
142+
this.deniedPublisher.assertWasNotSubscribed();
143+
this.entryPointPublisher.assertWasSubscribed();
144+
}
145+
132146
@Test
133147
public void setAccessDeniedHandlerWhenNullThenException() {
134148
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setAccessDeniedHandler(null));
@@ -139,4 +153,14 @@ public void setAuthenticationEntryPointWhenNullThenException() {
139153
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setAuthenticationEntryPoint(null));
140154
}
141155

156+
@Test
157+
public void setAuthenticationTrustResolver() {
158+
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setAuthenticationTrustResolver(null));
159+
}
160+
161+
@Test
162+
public void setMessageSource() {
163+
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setMessageSource(null));
164+
}
165+
142166
}

0 commit comments

Comments
 (0)