Mithun
Mithun

Reputation: 8067

Spring Boot & Spring Security not serving content from /static folder

I am creating a simple web application using Spring Boot and Spring Security. I have a custom filter to check if x-auth-token is present and valid. I have the static content under /src/main/resources/static folder. But, the URL pointing to static content are also passing through the custom filter and failing the token validation. Could anybody help in figuring out the mistake with my configuration?

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private StatelessAuthenticationFilter statelessAuthenticationFilter;

    @Autowired
    private UserDetailsService userDetailsService;

    public SpringSecurityConfig() {
        super(true);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
            .anyRequest().authenticated().and()

            // Custom Token based authentication based on the header
            .addFilterBefore(statelessAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

    @Override
    public UserDetailsService userDetailsService() {
        return userDetailsService;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/auth");
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setEnabled(false);
        filterRegistrationBean.setFilter(statelessAuthenticationFilter);
        return filterRegistrationBean;
    }
}

Custom filter:

@Component
public class StatelessAuthenticationFilter extends GenericFilterBean {

    @Value("${security.token.secret:asdfasdfasdf}")
    private String tokenSecret;

    @Autowired
    private UserRepository userRepository;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
                            throws IOException, ServletException {
        System.out.println("stateless authentication filter");
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        try {

            String token = httpRequest.getHeader(Constants.X_AUTH_TOKEN_HEADER_NAME);
            if(!StringUtils.hasText(token)) {
                throw new AuthenticationException(AirlineError.AUTHENTICATION_AUTH_TOKEN_MISSING);
            }

            JWTPayload jwtPayload = new JWTPayload();
            byte[] secret = tokenSecret.getBytes();
            DefaultJwtParser defaultJwtParser = new DefaultJwtParser();
            defaultJwtParser.setSigningKey(secret);

            Claims claims = defaultJwtParser.parseClaimsJws(token).getBody();
            jwtPayload.setEmail((String) claims.get("email"));
            jwtPayload.setExp((Long) claims.get("exp"));

            if (new DateTime(jwtPayload.getExp()).isBeforeNow()) {
                throw new AuthenticationException(AirlineError.AUTHENTICATION_AUTH_TOKEN_EXPIRED);
            }

            User user = userRepository.findOne(jwtPayload.getEmail());
            SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(user.getEmail()));
            chain.doFilter(request, response);
        } catch(Exception e) {
            httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        }
    }

}

index.html is in /src/main/resources/static folder, but it is not being served when I open http://localhost:8080 from browser.

EDIT 1 I have created a sample project in github to replicate the issue. Hope this helps:

https://github.com/mgooty/spring-boot-security

when I hit:

  1. http://localhost:8080 or http://localhost:8080/index.html I get An Authentication object was not found in the SecurityContext
  2. http://localhost:8080/static/index.html I get 404 error

Upvotes: 0

Views: 3169

Answers (1)

Maciej Marczuk
Maciej Marczuk

Reputation: 3733

If you want to permit all access to your static content then just configure it in your security configuration:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
            .antMatchers("/index.html").permitAll()
            .anyRequest().authenticated().and()

            // Custom Token based authentication based on the header
            .addFilterBefore(statelessAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

However, this won't work in your case because of errors in your custom security filters. But you can still disable all web security (disable all fiilters) for index.html file or other static resources.

Just change:

web.ignoring().antMatchers("/auth");

to:

web.ignoring().antMatchers("/auth", "/index.html");

Remember that your application maps /src/main/resources/static directory to / url (there is no /static prefix in your resource urls).

Upvotes: 0

Related Questions