Issue
I have implemented a filter to check an IP adresses white list with Spring Security. It works, but if i throw an error in my doFilter method, the throw is called 3 times oO.
I found a solution with "return;", but i am not that happy with it. It means i have to log my error without using throw...
What do you think, is there any better way ? a best practice ?
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Here is the web configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").permitAll().and()
.addFilterBefore(new CustomIpFilter(),
BasicAuthenticationFilter.class)
.csrf().disable()
.formLogin().disable();
}
}
Here is my filter
@Log4j2
@WebFilter
public class CustomIpFilter implements Filter {
Set<String> whitelist = new HashSet<>();
public CustomIpFilter() {
whitelist.add("0:0:0:0:0:0:0:1"); //localhost
whitelist.add("127.0.0.1");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String ipAdress = request.getRemoteAddr();
if (!whitelist.contains(ipAdress)) {
log.error("Unknown IP adress");
/* if the return is replaced by throw line, it still works, but doFilter will be called 3 times and throw 3 times the same error
throw new UnknownHostException("Unknown IP adress");*/
return;
}
chain.doFilter(request, response); //Continue
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
The controller used to test
@RestController
@RequestMapping(value = "test")
public class LoggerController {
@GetMapping("/go")
public String logsTest() {
System.out.println("ok");
return "Ok";
}
}
i have tried the same stuff with an interceptor removing Spring Security using "preHandle" method and i still have 3 times the Throw. So i start to understand why, look at the logs:
1st Throw
java.net.UnknownHostException: Unknown IP adress
2nd Throw
[nio-8181-exec-5] c.e.d.S.IpAdressInterceptor : Unknown IP adress
[nio-8181-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception
3rd Throw:
[nio-8181-exec-5] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing ErrorPage[errorCode=0, location=/error]
Thanks for your help !
Solution
You are running in a Servlet environment. The servlet spec doesn't say you should respond to errors by throwing exceptions. Instead, you are supposed to respond with an HTTP status code and message. When you throw the exception the servlet container is going to do its best to figure out what to do but frequently that will result in a 500 Internal Server Error being returned to the user, which isn't accurate or helpful.
Just returning from the filter isn't correct either as you haven't put anything into the HTTP response. Again, you should be setting an appropriate status code in the response, such as 403 Forbidden, which gives the caller an indication that something isn't configured correctly.
Answered By - rgoers