My question: How do I unit test my Filter class
Problem to solve: My Spring-Boot app includes Spring-Security with default config. This means that if a malicious URL is requested a RequestRejectedException is thrown.
e.g.
2023-06-20 10:08:19,716 ERROR ....[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String "%2e"
at org.springframework.security.web.firewall.StrictHttpFirewall.rejectedBlacklistedUrls(StrictHttpFirewall.java:349)
at org.springframework.security.web.firewall.StrictHttpFirewall.getFirewalledRequest(StrictHttpFirewall.java:316)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:194)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
This exception bubbles up to become an ERROR in my application log, which in turn triggers an alert.
My fix: I've written a Filter class to check all ServletRequests and handle the RequestRejectedException (if thrown). It's a solution from a related thread here: https://stackoverflow.com/a/52635656/22144884
How do I test it? The filter class is working well, but I need to write a unit test and I'm not sure how to approach it.
I need to assert that if the StrictHttpFirewall throws a RequestRejectedException, my filter class will catch it and handle it. Can I do this as a unit test, or do I need to have the application running so that I can actually test against the Spring-Security firewall?
Your advice on how to write the simplest test is appreciated!
I tried this:
public class RequestRejectedExceptionFilterTest {
private final RequestRejectedExceptionFilter filter = new RequestRejectedExceptionFilter();
@Test(expected = RequestRejectedException.class)
public void redirectTest() throws IOException, ServletException {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
req.setServletPath(";");
filter.doFilter(req, res, chain);
}
}
but it doesn't throw a RequestRejectedException. I assume this is because the mock request doesn't actually hit the StrictHTTPFirewall.
Test output:
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.004 sec <<< FAILURE!
redirectTest(com.mycompany.my_app.filter.RequestRejectedExceptionFilterTest) Time elapsed: 0.004 sec <<< FAILURE!
java.lang.AssertionError: Expected exception: org.springframework.security.web.firewall.RequestRejectedException
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:34)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)