Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot + Tomcat Error Handling

We have a web application built using spring boot and we are using spring security to manage authentication. Authentication is right now happening using basic mode.

We are using UserDetailsService to handle authentication. When we are running the application directly from STS using the embedded tomcat, when the user is not enabled, we receive the following error with status code 401.

{"timestamp":1485512173312,"status":401,"error":"Unauthorized","message":"User is disabled","path":"/trex/user"}

But, when I package the application into a war and deploy it to Tomcat we no longer receive the json error. Instead, we receive a html error similar to the following.

<html><head><title>Apache Tomcat/7.0.75 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 401 - User is disabled</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>User is disabled</u></p><p><b>description</b> <u>This request requires HTTP authentication.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.75</h3></body></html>

Is it possible to stop handling the standard error codes and let the json data pass back as it is?

Edited: Spring security config

/**
 * Security configuration. Defines configuration methods and security
 * constraints. Autowired bean definitions can be found in {@link AuthAppConfig}
 * 

 *
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    Logger logger = LoggerFactory.getLogger(getClass());

    /*userDetailsService
     * @Autowired TRexUserDetailsService customAuthenticationEntryPoint;
     * 
     */
    @Autowired
    TRexUserDetailsService userDetailsService;

    @Autowired
    private AmazonProperties amazonProperties;

    /**
     * Configuration related to authentication and authorization
     * 
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        AuthenticationEntryPoint entryPoint = new CustomAuthenticationEntryPoint();
        LogoutHandler myLogoutHandler = new MyLogoutSuccessHandler();

        logger.info("Configuring the security of the application");

        http

                // Basic Authentication
                .httpBasic().authenticationEntryPoint(entryPoint)
                .and().authorizeRequests()
                // Allowing index.html, login.html and / and
                // resetforgotpassword.html and all forgot user mappings since
                // we are using 2 way handshake for this purpose
                .antMatchers("/activate/user","/activate/token/**"
                        ,"/validate","/validateEmail","/user/resetpassword/**","/user/forgotpassword"
                        ,"/admin/masters/*.js","/admin/modeller/*.js", "/login.html", "/index.html","/activateuser.html","/savepassword.html","/forgotpassword.html","/","/lib/**"
                        ,"/directives/paginated-control.js"
                        , "/expense/js/summary.js"
                        ,"/travel/js/directive/uploadDirecetive.js"
                        ,"/travel/js/travelData.js"
                        ,"/travel/js/summary.js"
                        ,"/directives/paginated-control.js"
                        ,"/loginform.html"
                        ,"/infoDirective.html"
                        )
                .permitAll()
                // Admin ADMIN,
                .antMatchers("/admin/**").access("hasRole('ADMIN')")
                // Allow SA
                .antMatchers("/SA/**").access("hasRole('SUPER')")
                //Allow REPORTS
                .antMatchers("/reports/**").access("hasRole('REPORT')")
                // All other requests are to be authenticated.
                .anyRequest().authenticated().and()

                // Filter to prevent CSRF attacks.
                .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class).csrf()
                // Used to check which requests are to be checked for csrf
                // protection
                .requireCsrfProtectionMatcher(new CsrfRequestMatcher())
                // Add the renamed CSRF token header repository
                .csrfTokenRepository(csrfTokenRepository())
                .and()
                // Configuration for /logout
                .logout()
                // Logout requires form submit. Bypassing the same.
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/#/login")
                .addLogoutHandler(myLogoutHandler)
                //Session management to store session registry
                .and().sessionManagement()
                .maximumSessions(100)
                .maxSessionsPreventsLogin(false)
                .expiredUrl("/#/login")
                .sessionRegistry(sessionRegistry());

    }

    /**
     * Session Registry to store sessions
     * @return
     */
    @Bean
    SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    /**
     * Session event publisher.
     * @return
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    public static ServletListenerRegistrationBean httpSessionEventPublisher() {        
        return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
    }
    /**
     * This method specifies that the header name to be used is XSRF token
     * instead of the default CSRF cause Angular names the token as XSRF instead
     * of CSRF
     * 
     * @return
     */
    private CsrfTokenRepository csrfTokenRepository() {
        logger.info("Configuring the CSRF token name as XSRF-TOKEN");
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }

    /**
     * Configuration for Custom Authentication
     * 
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth, BCryptPasswordEncoder passwordEncoder)
            throws Exception {
        logger.info("Configuring the authentication to custom User Details Service");

        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);

        logger.info("Configuring the authentication to custom User Details Service");
    }

    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // TODO Auto-generated method stub
        return super.authenticationManagerBean();
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() throws Exception {
        BasicAuthenticationEntryPoint entryPoint = new CustomAuthenticationEntryPoint();
        entryPoint.setRealmName("Spring");

        return entryPoint;

    }
}
like image 365
Pavan Andhukuri Avatar asked Jan 27 '17 10:01

Pavan Andhukuri


People also ask

How do you handle DefaultHandlerExceptionResolver?

Class DefaultHandlerExceptionResolver. The default implementation of the HandlerExceptionResolver interface, resolving standard Spring MVC exceptions and translating them to corresponding HTTP status codes. This exception resolver is enabled by default in the common Spring DispatcherServlet .

How do you handle exception globally in spring boot?

You can define the @ExceptionHandler method to handle the exceptions as shown. This method should be used for writing the Controller Advice class file. Now, use the code given below to throw the exception from the API. The complete code to handle the exception is given below.

How does spring boot handle WhiteLabel error?

Another way of disabling the WhiteLabel Error is excluding the ErrorMvcAutoConfiguration . Alternatively, the exclusion can be done in an annotation. When the WhiteLabel Error Page is disabled and no custom error page is provided, the web server's error page (Tomcat, Jetty) is shown.


1 Answers

You should be able to fix this within your CustomAuthenticationEntryPoint. See this answer on how to avoid Tomcat's default error pages.

Assuming your custom EntryPoint is an extension of BasicAuthenticationEntryPoint (as the bean would suggest), see here: org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.java/#59

You'll need to replace:

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());

with:

response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
like image 52
mikeapr4 Avatar answered Oct 23 '22 02:10

mikeapr4