DEV Community

Salad Lam
Salad Lam

Posted on

Spring Security: Redirect to login page if access pages which is for authorized user only

Code is extracted from my notice board example application, which uses Spring Security 5.6.7

Spring Security configuration class

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // must put more restricted rule at first
                .antMatchers("/manage/*/approve").hasAuthority("ADMIN")
                .antMatchers("/manage/**").hasAuthority("USER")
            .and()
                .httpBasic().disable()
                .formLogin()
                    .loginPage("/login")
                    .loginProcessingUrl("/loginHandler")
                    .failureUrl("/login?error=true")
                    .permitAll()
            .and()
                .logout().logoutSuccessUrl("/");
    }
    // ...
}
Enter fullscreen mode Exit fullscreen mode

The chain in SecurityFilterChain

(begin)
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CsrfFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
(end)
Enter fullscreen mode Exit fullscreen mode

Flow of anonymous user access /manage page by browser

  • AnonymousAuthenticationToken is created by AnonymousAuthenticationFilter
  • Permission check is performed in FilterSecurityInterceptor. The user does not have the required authority "USER", so org.springframework.security.access.AccessDeniedException is thrown
  • The exception is caught by ExceptionTranslationFilter. In org.springframework.security.web.access.ExceptionTranslationFilter#handleAccessDeniedException method
private void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response,
        FilterChain chain, AccessDeniedException exception) throws ServletException, IOException {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    boolean isAnonymous = this.authenticationTrustResolver.isAnonymous(authentication);
    if (isAnonymous || this.authenticationTrustResolver.isRememberMe(authentication)) {
        if (logger.isTraceEnabled()) {
            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")));
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace(
                    LogMessage.format("Sending %s to access denied handler since access is denied", authentication),
                        exception);
        }
        this.accessDeniedHandler.handle(request, response, exception);
    }
}
Enter fullscreen mode Exit fullscreen mode
  • sendStartAuthentication method is called, and an instance of org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint is passed into FilterSecurityInterceptor on instance creation.
  • LoginUrlAuthenticationEntryPoint then delegates the control to org.springframework.security.web.DefaultRedirectStrategy. Finally reply the browser, redirect to "/login" page

Flow of user access /manage/4/approve page without "ADMIN" authority

  • org.springframework.security.access.AccessDeniedException is throw by FilterSecurityInterceptor and caught by ExceptionTranslationFilter
  • In org.springframework.security.web.access.ExceptionTranslationFilter#handleAccessDeniedException method, this time this.accessDeniedHandler.handle method is called
  • Directly return 403 Forbidden status

Add extra handling rules for anonymous user

Modifying Spring Security configuration class to following

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // must put more restricted rule at first
                .antMatchers("/manage/*/approve").hasAuthority("ADMIN")
                .antMatchers("/manage/**").hasAuthority("USER")
            .and()
                .httpBasic().disable()
                .formLogin()
                    .loginPage("/login")
                    .loginProcessingUrl("/loginHandler")
                    .failureUrl("/login?error=true")
                    .permitAll()
            .and()
                .logout().logoutSuccessUrl("/")
            .and()
                .exceptionHandling()
                    .defaultAuthenticationEntryPointFor(new Http403ForbiddenEntryPoint(), new AntPathRequestMatcher("/manage/1"))
                    .defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.GONE), new AntPathRequestMatcher("/manage/2"));
    }
    // ...
}
Enter fullscreen mode Exit fullscreen mode
  • When accessing "/manage/1", HTTP status 403 will return
  • When accessing "/manage/2", HTTP status 410 will return
  • When accessing "/manage", will redirect to "/login"

The property authenticationEntryPoint in ExceptionTranslationFilter becomes org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint.

Reference

  1. Handling Security Exceptions

Top comments (0)