javaspringspring-securitywaffle

waffle custom error page in spring


I am using waffle 1.7 + spring 4 + spring security 3.2 + thymeleaf. My problem is, that I am unable to provide custom error page when fall-back form logging fails. This is my configuration: @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/**") .authenticated() .and() .exceptionHandling() .authenticationEntryPoint(negotiateSecurityFilterEntryPoint()) .accessDeniedPage("/access-denied") .and() .addFilterBefore(waffleNegotiateSecurityFilter(), BasicAuthenticationFilter.class); }

When user uses browser with SNPENGO off and enters wrong credentials, the default system 500 page appears with following information:

com.sun.jna.platform.win32.Win32Exception: The logon attempt failed. waffle.windows.auth.impl.WindowsAuthProviderImpl.acceptSecurityToken(WindowsAuthProviderImpl.java:134) waffle.servlet.spi.NegotiateSecurityFilterProvider.doFilter(NegotiateSecurityFilterProvider.java:103) waffle.servlet.spi.SecurityFilterProviderCollection.doFilter(SecurityFilterProviderCollection.java:130) ...

How can I provide my custom page (access-denied.html thymeleaf template) ? So far I have tried everything from http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc but without success.


Solution

  • After digging into Spring documentation and tracking what actually waffle does I have been able to solve it in the following "ugly" way. 1. disabling security for /access-denied page to prevent endless redirection loop 2. wrapping waffle filter to catch all exceptions and redirect it

    Does anyone have better solution ?

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/access-denied")
                .permitAll()
                .and()
                .authorizeRequests()
                .antMatchers("/**")
                .authenticated()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(negotiateSecurityFilterEntryPoint())
                .accessDeniedPage("/access-denied")
                .and()
                .addFilterBefore(waffleNegotiateSecurityFilter(),
                        BasicAuthenticationFilter.class);
    }
    
    public class WaffleWrapperSecurityBean extends GenericFilterBean {
        @NotNull
        private final GenericFilterBean wrappedFilter;
        public WaffleWrapperSecurityBean(GenericFilterBean filter) {
            wrappedFilter = filter;
        }
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            try {
                wrappedFilter.doFilter(request, response, chain);
            } catch (Exception e) {
                ((HttpServletResponse) response)
                        .sendRedirect("access-denied?message="
                                + e.getLocalizedMessage());
            }
        }
        @Override
        public void destroy() {
            wrappedFilter.destroy();
        }
    }
    // controller code ommited