diff --git a/core/src/main/resources/org/springframework/security/messages_de.properties b/core/src/main/resources/org/springframework/security/messages_de.properties index f376c13fcef..65d809adbf0 100644 --- a/core/src/main/resources/org/springframework/security/messages_de.properties +++ b/core/src/main/resources/org/springframework/security/messages_de.properties @@ -28,6 +28,7 @@ DigestAuthenticationFilter.nonceExpired=Die Nonce ist nicht mehr g\u00FCltig DigestAuthenticationFilter.nonceNotNumeric=Das erste Element der Nonce sollte numerisch sein. Gefundener Inhalt\: {0} DigestAuthenticationFilter.nonceNotTwoTokens=Nonce sollte zwei Elemente beinhalten. Gefundener Inhalt\: {0} DigestAuthenticationFilter.usernameNotFound=Benutzername {0} wurde nicht gefunden +ExceptionTranslationFilter.insufficientAuthentication=Vollst\u00E4ndige Authentifikation wird ben\u00f6tigt um auf diese Resource zuzugreifen #JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority #JdbcDaoImpl.notFound=User {0} not found LdapAuthenticationProvider.badCredentials=Ung\u00FCltige Anmeldedaten diff --git a/core/src/main/resources/org/springframework/security/messages_en.properties b/core/src/main/resources/org/springframework/security/messages_en.properties index 665a742002e..bb3f64317d4 100644 --- a/core/src/main/resources/org/springframework/security/messages_en.properties +++ b/core/src/main/resources/org/springframework/security/messages_en.properties @@ -28,6 +28,7 @@ DigestAuthenticationFilter.nonceExpired=Nonce has expired/timed out DigestAuthenticationFilter.nonceNotNumeric=Nonce token should have yielded a numeric first token, but was {0} DigestAuthenticationFilter.nonceNotTwoTokens=Nonce should have yielded two tokens but was {0} DigestAuthenticationFilter.usernameNotFound=Username {0} not found +ExceptionTranslationFilter.insufficientAuthentication=Full authentication is required to access this resource JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority JdbcDaoImpl.notFound=User {0} not found LdapAuthenticationProvider.badCredentials=Bad credentials diff --git a/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java b/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java index 633760f0c20..0fb87f73d92 100644 --- a/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java +++ b/web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java @@ -21,6 +21,7 @@ import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; @@ -30,6 +31,8 @@ import org.springframework.util.Assert; import org.springframework.web.filter.GenericFilterBean; +import org.springframework.context.support.MessageSourceAccessor; + import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -83,6 +86,8 @@ public class ExceptionTranslationFilter extends GenericFilterBean { private RequestCache requestCache = new HttpSessionRequestCache(); + private final MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + public ExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint) { this(authenticationEntryPoint, new HttpSessionRequestCache()); } @@ -179,7 +184,9 @@ else if (exception instanceof AccessDeniedException) { response, chain, new InsufficientAuthenticationException( - "Full authentication is required to access this resource")); + messages.getMessage( + "ExceptionTranslationFilter.insufficientAuthentication", + "Full authentication is required to access this resource"))); } else { logger.debug( diff --git a/web/src/main/resources/org/springframework/security/web/messages_de.properties b/web/src/main/resources/org/springframework/security/web/messages_de.properties new file mode 100644 index 00000000000..8113d860a11 --- /dev/null +++ b/web/src/main/resources/org/springframework/security/web/messages_de.properties @@ -0,0 +1 @@ +ExceptionTranslationFilter.insufficientAuthentication=Vollst\u00e4ndige Authentifikation wird ben\u00f6tigt um auf diese Resource zuzugreifen diff --git a/web/src/main/resources/org/springframework/security/web/messages_en.properties b/web/src/main/resources/org/springframework/security/web/messages_en.properties new file mode 100644 index 00000000000..46aea33b1b8 --- /dev/null +++ b/web/src/main/resources/org/springframework/security/web/messages_en.properties @@ -0,0 +1 @@ +ExceptionTranslationFilter.insufficientAuthentication=Full authentication is required to access this resource diff --git a/web/src/test/java/org/springframework/security/web/access/ExceptionTranslationFilterTests.java b/web/src/test/java/org/springframework/security/web/access/ExceptionTranslationFilterTests.java index 09207729408..5602c71a2c7 100644 --- a/web/src/test/java/org/springframework/security/web/access/ExceptionTranslationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/access/ExceptionTranslationFilterTests.java @@ -18,6 +18,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.MockPortResolver; @@ -41,6 +42,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; +import java.util.Locale; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -167,6 +169,36 @@ public void testAccessDeniedWhenNonAnonymous() throws Exception { assertThat(request.getAttribute(WebAttributes.ACCESS_DENIED_403)).isExactlyInstanceOf(AccessDeniedException.class); } + @Test + public void testLocalizedErrorMessages() throws Exception { + // Setup our HTTP request + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setServletPath("/secure/page.html"); + + // Setup the FilterChain to thrown an access denied exception + FilterChain fc = mock(FilterChain.class); + doThrow(new AccessDeniedException("")).when(fc).doFilter( + any(HttpServletRequest.class), any(HttpServletResponse.class)); + + // Setup SecurityContextHolder, as filter needs to check if user is + // anonymous + SecurityContextHolder.getContext().setAuthentication( + new AnonymousAuthenticationToken("ignored", "ignored", AuthorityUtils + .createAuthorityList("IGNORED"))); + + // Test + ExceptionTranslationFilter filter = new ExceptionTranslationFilter( + (req, res, ae) -> res.sendError(403, ae.getMessage())); + filter.setAuthenticationTrustResolver(new AuthenticationTrustResolverImpl()); + assertThat(filter.getAuthenticationTrustResolver()).isNotNull(); + + LocaleContextHolder.setDefaultLocale(Locale.GERMAN); + MockHttpServletResponse response = new MockHttpServletResponse(); + filter.doFilter(request, response, fc); + assertThat(response.getErrorMessage()) + .isEqualTo("Vollst\u00e4ndige Authentifikation wird ben\u00f6tigt um auf diese Resource zuzugreifen"); + } + @Test public void redirectedToLoginFormAndSessionShowsOriginalTargetWhenAuthenticationException() throws Exception {