Java – handling custom exceptions in spring security
We are using spring MVC spring security hibernate to create a restful API
Authentication can occur in a variety of ways: basic auth, through different parameters in post requests, and through web login For each authentication mechanism, the namespace element configured in < HTTP > spring security XML
We handle all our spring exceptions in the custom handlerexceptionresolver This is good for all exceptions thrown in our controller, but I don't know how to handle custom exceptions thrown in the custom spring safety filter Because the spring safety filter didn't see us throw an exception in the custom spring safety filter before any of our controllers were called
I found this problem on stackoverflow: use custom exceptions in spring security But I don't understand where they handle exceptions thrown We tried this method, but our custom handlerexceptionresolver is not called Instead, the user is presented with an ugly stack trace presented by Tomcat
Why do we need this? Users can be activated and deactivated If they are disabled and try to do something, we want to return JSON with a custom error message This should be different from what is displayed when spring security raises accessdeniedexception Accessdeniedexception somehow makes it to our handlerexceptionresolver, but I can't follow exactly how
Possible solutions we consider using exceptiontranslationfilter, but when we throw our custom exception (set a breakpoint in the catch statement of the dofilter () method), this will not be called) In my understanding, this catch block should be called and an authentication entry point should be used
Another possibility: we can perform operations similar to exceptiontranslationfilter and accessdeniedhandler in the spring security filter chain:
RequestDispatcher dispatcher = request.getRequestDispatcher(errorPage); dispatcher.forward(request,response);
We can add some parameters (error code, reason, etc.) to the request and point them to the controller that will handle rendering in JSON or HTML
Here is a brief excerpt of our configuration:
Spring safety:
<http create-session="stateless" use-expressions="true" > <!-- Try getting the authorization object from the request parameters. --> <security:custom-filter ref="filter1" after="Security_CONTEXT_FILTER"/> <security:custom-filter ref="filter2" before="logoUT_FILTER"/> <!-- Intercept certain URLS differently --> <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" /> <!-- Some more stuff here --> <intercept-url pattern="/**" access="denyAll" /> <http-basic /> </http>
AppConfig for handlerexceptionresolver
@Bean public HandlerExceptionResolver handlerExceptionResolver(){ logger.info("creating handler exception resolver"); return new AllExceptionHandler(); }
Our custom handlerexceptionresolver
public class AllExceptionHandler implements HandlerExceptionResolver { private static final Logger logger = LoggerFactory .getLogger(AppConfig.class); @Override public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) { // This is just a snipped of the real method code return new ModelAndView("errorPage"); }
The relevant part of one of our filters:
try { Authentication authResult = authenticationmanger.authenticate(authRequest); SecurityContextHolder.getContext().setAuthentication(authResult); } catch(AuthenticationException Failed) { SecurityContextHolder.clearContext(); throw Failed; }
On the web xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <context-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>xxx.xxx.xxx.config</param-value> </context-param> <context-param> <param-name>spring.profiles.default</param-name> <param-value>LIVE</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> <!-- Add multipart support for files up to 10 MB --> <multipart-config> <max-file-size>10000000</max-file-size> </multipart-config> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>openEntityManagerInViewFilter</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openEntityManagerInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <!-- Map filters --> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <error-page> <error-code>404</error-code> <location>/handle/404</location> </error-page> </web-app>
Does anyone have any instructions on how to solve this problem? I have read many articles about Google, most of which describe how to deal with the accessdenied exception thrown by spring security when there is no filter to verify the request
We use spring security 3.1 0 and spring web MVC 3.1 0
Solution
It is important to remember that the order of filters in spring security is important
From the spring security 3 Book:
If your filter is about authorization, it is a good practice to use the method used by the default authorization filter as the end of the chain So you don't have to reinvent it
Standard filter: table in documentation
After you configure the filter chain correctly, you can configure the error page and even customize the handler For more information, see documentation