Provide Authentication to AuthenticationExceptions
Issue gh-16444
This commit is contained in:
+6
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2022 the original author or authors.
|
||||
* Copyright 2004-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.
|
||||
@@ -194,10 +194,11 @@ public class ExceptionTranslationFilter extends GenericFilterBean implements Mes
|
||||
logger.trace(LogMessage.format("Sending %s to authentication entry point since access is denied",
|
||||
authentication), exception);
|
||||
}
|
||||
sendStartAuthentication(request, response, chain,
|
||||
new InsufficientAuthenticationException(
|
||||
this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication",
|
||||
"Full authentication is required to access this resource")));
|
||||
AuthenticationException ex = new InsufficientAuthenticationException(
|
||||
this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication",
|
||||
"Full authentication is required to access this resource"));
|
||||
ex.setAuthenticationRequest(authentication);
|
||||
sendStartAuthentication(request, response, chain, ex);
|
||||
}
|
||||
else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
||||
+5
-2
@@ -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.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
||||
@@ -46,7 +47,9 @@ public final class RequestMatcherDelegatingAuthenticationManagerResolver
|
||||
private final List<RequestMatcherEntry<AuthenticationManager>> authenticationManagers;
|
||||
|
||||
private AuthenticationManager defaultAuthenticationManager = (authentication) -> {
|
||||
throw new AuthenticationServiceException("Cannot authenticate " + authentication);
|
||||
AuthenticationException ex = new AuthenticationServiceException("Cannot authenticate " + authentication);
|
||||
ex.setAuthenticationRequest(authentication);
|
||||
throw ex;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcherEntry;
|
||||
@@ -46,8 +47,11 @@ public final class ServerWebExchangeDelegatingReactiveAuthenticationManagerResol
|
||||
|
||||
private final List<ServerWebExchangeMatcherEntry<ReactiveAuthenticationManager>> authenticationManagers;
|
||||
|
||||
private ReactiveAuthenticationManager defaultAuthenticationManager = (authentication) -> Mono
|
||||
.error(new AuthenticationServiceException("Cannot authenticate " + authentication));
|
||||
private ReactiveAuthenticationManager defaultAuthenticationManager = (authentication) -> {
|
||||
AuthenticationException ex = new AuthenticationServiceException("Cannot authenticate " + authentication);
|
||||
ex.setAuthenticationRequest(authentication);
|
||||
return Mono.error(ex);
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct an
|
||||
|
||||
+3
@@ -101,6 +101,9 @@ public class ExceptionTranslationWebFilter implements WebFilter {
|
||||
AuthenticationException cause = new InsufficientAuthenticationException(
|
||||
"Full authentication is required to access this resource");
|
||||
AuthenticationException ex = new AuthenticationCredentialsNotFoundException("Not Authenticated", cause);
|
||||
if (authentication != null) {
|
||||
ex.setAuthenticationRequest(authentication);
|
||||
}
|
||||
return this.authenticationEntryPoint.commence(exchange, ex).then(Mono.empty());
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2024 the original author or authors.
|
||||
* Copyright 2004-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.
|
||||
@@ -27,6 +27,7 @@ import jakarta.servlet.http.HttpSession;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
@@ -38,6 +39,7 @@ import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -107,6 +109,23 @@ public class ExceptionTranslationFilterTests {
|
||||
assertThat(response.getRedirectedUrl()).isEqualTo("/mycontext/login.jsp");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessDeniedWhenAnonymousThenIncludesAuthenticationRequest() throws Exception {
|
||||
// Setup our HTTP request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
|
||||
FilterChain fc = mockFilterChainWithException(new AccessDeniedException(""));
|
||||
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("ignored", "ignored",
|
||||
AuthorityUtils.createAuthorityList("IGNORED"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
AuthenticationEntryPoint entryPoint = mock(AuthenticationEntryPoint.class);
|
||||
ExceptionTranslationFilter filter = new ExceptionTranslationFilter(entryPoint);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filter.doFilter(request, response, fc);
|
||||
ArgumentCaptor<AuthenticationException> ex = ArgumentCaptor.forClass(AuthenticationException.class);
|
||||
verify(entryPoint).commence(any(), any(), ex.capture());
|
||||
assertThat(ex.getValue().getAuthenticationRequest()).isEqualTo(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessDeniedWithRememberMe() throws Exception {
|
||||
// Setup our HTTP request
|
||||
|
||||
+14
@@ -21,6 +21,7 @@ import java.security.Principal;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
@@ -39,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
@@ -146,6 +149,17 @@ public class ExceptionTranslationWebFilterTests {
|
||||
this.entryPointPublisher.assertWasSubscribed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterWhenAccessDeniedExceptionAndAnonymousAuthenticatedThenIncludesAuthenticationRequest() {
|
||||
given(this.entryPoint.commence(any(), any())).willReturn(this.entryPointPublisher.mono());
|
||||
given(this.exchange.getPrincipal()).willReturn(Mono.just(this.anonymousPrincipal));
|
||||
given(this.chain.filter(this.exchange)).willReturn(Mono.error(new AccessDeniedException("Not Authorized")));
|
||||
StepVerifier.create(this.filter.filter(this.exchange, this.chain)).expectComplete().verify();
|
||||
ArgumentCaptor<AuthenticationException> ex = ArgumentCaptor.forClass(AuthenticationException.class);
|
||||
verify(this.entryPoint).commence(any(), ex.capture());
|
||||
assertThat(ex.getValue().getAuthenticationRequest()).isEqualTo(this.anonymousPrincipal);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAccessDeniedHandlerWhenNullThenException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setAccessDeniedHandler(null));
|
||||
|
||||
Reference in New Issue
Block a user