Howto optionally add Spring Security captcha filter for specific URLs

I am looking for a non-invasive way to add a captcha filter for specific api calls.

My setup consists of two WebSecurityConfigurerAdapters with one filter each (and not with filters):

  • Internal api ("/ iapi" uses the A filter for all calls, but also ignores some public requests, such as / authenticate)
  • External api ("/ eapi" uses filter B for all calls)

How to add a filter to Spring's security tool for public, internal api calls or external api? I do not need a SecurityContext, I just need to check Captcha in the request headers, forward filterChain (regular filters) or manually deny access. I tried to declare a filter in web.xml, but this violates the ability to use dependency injection.

Here is my Spring Security Configuration:

 @EnableWebSecurity public class SpringSecurityConfig { @Configuration @Order(1) @EnableGlobalMethodSecurity(securedEnabled = true) public static class InternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter { @Autowired private Filter filterA; public InternalApiConfigurerAdapter() { super(true); } @Override public void configure(WebSecurity web) throws Exception { web .ignoring() .antMatchers("/public/**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/iapi/**") .exceptionHandling().and() .anonymous().and() .servletApi().and() .authorizeRequests() .anyRequest().authenticated().and() .addFilterBefore(filterA, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return authenticationManager(); } } @Configuration @Order(2) @EnableGlobalMethodSecurity(securedEnabled = true) public static class ExternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter { @Autowired private FilterB filterB; public ExternalApiConfigurerAdapter() { super(true); } @Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/external/**") .exceptionHandling().and() .anonymous().and() .servletApi().and() .authorizeRequests() .anyRequest().authenticated().and() .addFilterBefore(filterB, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return authenticationManager(); } } 

Update: I currently have a working configuration with a filter declared in web.xml. However, it has the disadvantage that it is separate from the Spring context (for example, without autowiring beans), so I'm looking for a better solution using Spring.

Summary : There are two remaining problems:

  • Add a filter for specific URLs only. using beforeFilter (...) inside any configuration adds a filter to all the URLs of this configuration. Anti-drivers did not work. I need something like this: / iapi / captcha /, / external / captcha /, / public / captcha / *.
  • I have a public api that completely bypasses Spring Security: (web .ignoring () .antMatchers ("/ open / **");). I need to get around Spring Security, but still declare a filter there using Spring autwiring, but not necessarily Spring Security functions, since my captcha filter only rejects or diverts calls without attacks.
+8
java spring spring-security captcha
source share
1 answer

You already have a working configuration with filters A and B inserted before the UsernamePasswordAuthenticationFilter , so it should be easy to add another custom filter.

First, you create a filter and declare it as a bean, either annotating the class using @Component , or as @Bean inside the @Configuration class, so it is ready to enter @Autowired .

Now you can enter it as filter A and B and use it. In the "Sort Filters" section of the Spring Security reference documentation, the very first filter in the chain is ChannelProcessingFilter , so to insert a filter before anything else in the Spring security filter chain, you must do this:

 @Autowired private CaptchaFilter captchaFilter; @Override protected void configure(HttpSecurity http) throws Exception { http .antMatcher("/iapi/**") .addFilterBefore(captchaFilter, (Class<? extends Filter>) ChannelProcessingFilter.class) .addFilterBefore(filterA, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class) .authorizeRequests() .anyRequest().authenticated(); } 

By the way, exceptionHandling() anonymous() and servletApi() not needed, because with the WebSecurityConfigurerAdapter extension they are already enabled, except for anonymous() , when you actually specify more configuration details, since it indicates HttpSecurity javadoc

Keep in mind that the Spring Security Access Point, DelegatingFilterProxy will still run in front of your filter, but this component delegates the request to only the first filter in the chain, which in this case will be CaptchaFilter, so that you really would execute your filter before anything still from Spring Security.

But if you still want the captcha filter to run before DelegatingFilterProxy , there is no way to do this in the Spring security configuration, and you need to declare it in the web.xml .


Update. If you do not want to include the captcha filter in other configurations, you can always add a third configuration, and the configuration class will be as follows:

 @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true) public class SpringSecurityConfig { @Configuration @Order(1) public static class CaptchaApiConfigurerAdatper extends WebSecurityConfigurerAdapter { @Autowired private CaptchaFilter captchaFilter; public CaptchaApiConfigurerAdatper() { super(true); } @Override public void configure(WebSecurity web) throws Exception { web .ignoring() .antMatchers("/public/**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .requestMatchers() .antMatcher("/iapi/captcha**") .antMatcher("/external/captcha**") .and() .addFilterBefore(captchaFilter, (Class<? extends Filter>) ChannelProcessingFilter.class) .authorizeRequests() .anyRequest().authenticated(); } } @Configuration @Order(2) public static class InternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter { // ommiting code for the sake of clarity } @Configuration @Order(3) public static class ExternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter { // ommiting code for the sake of clarity } 

By the way, one more tip, you can reorganize all the general configuration outside of certain configurations into a main class, for example @EnableGlobalMethodSecurity(securedEnabled = true) AuthenticationManager, WebSecurity to skip security for the public, but for those, the Main class does not extend anything you need @Autowire method declarations.

Although there will be a problem with WebSecurity if you ignore /public/** , the match for HttpSecurity with /public/captcha** will be ignored, so I think you should not reorganize WebSecurity and have a different template in the CaptchaConfig class, so it does not overlap .

+5
source share

All Articles