30

I'm trying to add web security in spring but I don't want the filter to apply to certain things. How is that done in java?

And maybe there's a better way to do this because I created a custom filter but this is the only way I can think to instantiate it because of its dependencies.

Overall, what I want to do is this:

/resources/** SHOULD NOT go through the filter, /login (POST) SHOULD NOT go through the filter, everything else SHOULD go through the filter

Through various example I found through spring I was able to come up with this as for a start but it obviously doesn't work:

@Configuration
@EnableWebSecurity
@Import(MyAppConfig.class)
public class MySecurityConfig extends WebSecurityConfigurerAdapter
{
    @Override
    public void configure(WebSecurity webSecurity) throws Exception
    {
        webSecurity.ignoring().antMatchers("/resources/**");
    }

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity
                .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers("/login").permitAll();

        httpSecurity.httpBasic();
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    @Autowired
    public TokenFilterSecurityInterceptor<TokenInfo> tokenInfoTokenFilterSecurityInterceptor(MyTokenUserInfoCache userInfoCache, ServerStatusService serverStatusService, HttpSecurity httpSecurity) throws Exception
    {
        TokenService<TokenInfo> tokenService = new TokenServiceImpl(userInfoCache);
        TokenFilterSecurityInterceptor<TokenInfo> tokenFilter = new TokenFilterSecurityInterceptor<TokenInfo>(tokenService, serverStatusService, "RUN_ROLE");
        httpSecurity.addFilter(tokenFilter);
        return tokenFilter;
    }
}
jensengar
  • 6,117
  • 17
  • 58
  • 90

2 Answers2

32

Are you interested in all of Spring Security ignoring the URLs or do you only want that specific filter to ignore the request? If you want all of Spring Security to ignore the request it can be done using the following:

@Configuration
@EnableWebSecurity
@Import(MyAppConfig.class)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyTokenUserInfoCache userInfoCache;
    @Autowired
    private ServerStatusService serverStatusService;

    @Override
    public void configure(WebSecurity webSecurity) throws Exception
    {
        webSecurity
            .ignoring()
                // All of Spring Security will ignore the requests
                .antMatchers("/resources/**")
                .antMatchers(HttpMethod.POST, "/login");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .addFilter(tokenInfoTokenFilterSecurityInterceptor())
            .authorizeRequests()
                // this will grant access to GET /login too do you really want that?
                .antMatchers("/login").permitAll()
                .and()
            .httpBasic().and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    public TokenFilterSecurityInterceptor<TokenInfo> tokenInfoTokenFilterSecurityInterceptor() throws Exception
    {
        TokenService<TokenInfo> tokenService = new TokenServiceImpl(userInfoCache);
        return new TokenFilterSecurityInterceptor<TokenInfo>(tokenService, serverStatusService, "RUN_ROLE");
    }
}

If you want to have only that specific Filter ignore particular requests you can do something like this:

@Configuration
@EnableWebSecurity
@Import(MyAppConfig.class)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyTokenUserInfoCache userInfoCache;
    @Autowired
    private ServerStatusService serverStatusService;

    @Override
    public void configure(WebSecurity webSecurity) throws Exception
    {
        webSecurity
            .ignoring()
                // ... whatever is here is ignored by All of Spring Security
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .addFilter(tokenInfoTokenFilterSecurityInterceptor())
            .authorizeRequests()
                // this will grant access to GET /login too do you really want that?
                .antMatchers("/login").permitAll()
                .and()
            .httpBasic().and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    public TokenFilterSecurityInterceptor<TokenInfo> tokenInfoTokenFilterSecurityInterceptor() throws Exception
    {
        TokenService<TokenInfo> tokenService = new TokenServiceImpl(userInfoCache);
        TokenFilterSecurityInterceptor tokenFilter new TokenFilterSecurityInterceptor<TokenInfo>(tokenService, serverStatusService, "RUN_ROLE");


        RequestMatcher resourcesMatcher = new AntPathRequestMatcher("/resources/**");
        RequestMatcher posLoginMatcher = new AntPathRequestMatcher("/login", "POST");
        RequestMatcher ignored = new OrRequestMatcher(resourcesMatcher, postLoginMatcher);
        return new DelegateRequestMatchingFilter(ignored, tokenService);
    }
}


public class DelegateRequestMatchingFilter implements Filter {
    private Filter delegate;
    private RequestMatcher ignoredRequests;

    public DelegateRequestMatchingFilter(RequestMatcher matcher, Filter delegate) {
        this.ignoredRequests = matcher;
        this.delegate = delegate;
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
         HttpServletRequest request = (HttpServletRequest) req;
         if(ignoredRequests.matches(request)) {
             chain.doFilter(req,resp,chain);
         } else {
             delegate.doFilter(req,resp,chain);
         }
    }
}
Rob Winch
  • 21,440
  • 2
  • 59
  • 76
  • shouldn't you pass the tokenFilter instead of the tokenService to the constructor of your DelegateRequestMachingFilter? In the tokenInfoTokenFilterSecurityInterceptor method, you are creating a filter, but you are not using it. – Jean-François Beauchef Jul 09 '17 at 15:15
  • I was serching everhwere if permitall urls could be passed to my custom filter like the http basic filter. But I can see now that it is impossible. – Young Hyun Yoo Jan 07 '18 at 22:34
  • 2
    I know that everyone uses it, but I cannot see the advantage of that long method chaining in `configure(HttpSecurity http)` , especially considering that the type changes along it. Isn't everthing (much) more clear if we remove those `and()` and write a new `http.something()` statement ? What am I missing here? – leonbloy Feb 13 '19 at 00:06
  • @Rob Winch we have one question if webSecurity.ignoring() is working then why we need custom logic to ignore the given url. Any idea why webSecurity.ignoring() is not working. – ManojP Dec 24 '20 at 11:10
1

1 In xml configuration of spring-security I use

<http pattern="/resources/**" security="none"/> 

<http use-expressions="true">
<intercept-url pattern="/login" access="permitAll"/> 
</http>    

to retrieve it from security check.

2 After that add mvc:resource tag in your spring configuration

<mvc:resources mapping="/resource/**" location="/resource/"/>

Important: this config will only work if url is handled by dispatcher servlet. This means that in web.xml you must have

   <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping> 
mvb13
  • 1,514
  • 3
  • 18
  • 33
  • Well I have a similar xml config for a different app, but I'm really trying to do it in java for various reasons. The problem is the version of spring security that supports the java config is 3.2.0.RC2 so it's not even released yet.... – jensengar Nov 12 '13 at 14:18