Spring Boot api gives 403 after lots of successful 200 responses

I have a Spring Boot app which uses spring security as a dependency. I am migrating Spring boot version from 2.7.16 to 3.2.1. Everything works fine in version 2.7.16. But in 3.2.1, the rest APIs give 403 after a while. Sometimes 5 mins later, sometimes 1 hour later. So, it gives 200 successful responses in the beginning, but gives 403 after some time. I couldn’t fix the issue after many attempts. I am sharing security configs. Any help is appreciated

2.7.16 security config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final AuthenticationConfiguration configuration;

    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/h2-console/**").permitAll()
                .antMatchers("/manage/info").permitAll()
                .antMatchers("/manage/health").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(authenticationFilter())
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .httpBasic()
                .and()
                .headers().frameOptions().disable();

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public RequestHeaderAuthenticationFilter authenticationFilter() throws Exception {
        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
        filter.setPrincipalRequestHeader(HeaderConstants.PRINCIPAL_HEADER);
        filter.setExceptionIfHeaderMissing(false);
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationDetailsSource(new HeaderAuthenticationDetailsSource());
        return filter;
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider authenticationProvider() {
        PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
        provider.setPreAuthenticatedUserDetailsService(new PreAuthenticatedGrantedAuthoritiesUserDetailsService());
        return provider;
    }
}

And here is 3.2.1 security config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;

import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final AuthenticationConfiguration configuration;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(antMatcher("/h2-console/**")).permitAll()
                        .requestMatchers(antMatcher("/manage/info")).permitAll()
                        .requestMatchers(antMatcher("/manage/health")).permitAll()
                        .anyRequest().authenticated()
                )
                .addFilter(authenticationFilter())
                .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
        ;

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public RequestHeaderAuthenticationFilter authenticationFilter() throws Exception {
        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
        filter.setPrincipalRequestHeader(HeaderConstants.PRINCIPAL_HEADER);
        filter.setExceptionIfHeaderMissing(false);
        filter.setAuthenticationManager(authenticationManager());
        filter.setAuthenticationDetailsSource(new HeaderAuthenticationDetailsSource());
        return filter;
    }

    @Bean
    public PreAuthenticatedAuthenticationProvider authenticationProvider() {
        PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
        provider.setPreAuthenticatedUserDetailsService(new PreAuthenticatedGrantedAuthoritiesUserDetailsService());
        return provider;
    }
}

Logs:

Debug logs

2024-01-05T18:59:40.276Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint     : Pre-authenticated entry point called. Rejecting access
2024-01-05T18:59:40.279Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /error
2024-01-05T18:59:40.281Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.security.web.FilterChainProxy        : Secured GET /error
2024-01-05T18:59:40.282Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}
2024-01-05T18:59:40.282Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2024-01-05T18:59:40.283Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2024-01-05T18:59:40.284Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/cbor]
2024-01-05T18:59:40.285Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Fri Jan 05 18:59:40 GMT 2024, status=403, error=Forbidden, path=/worklogEntries/health}]
2024-01-05T18:59:40.288Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2024-01-05T18:59:40.288Z DEBUG 1 --- [xxxx-time] [nio-8061-exec-2] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 403

  • 2

    Show your Spring Security DEBUG logs.

    – 

  • logs are added @dur

    – 

  • These are Jenkins logs, not your application log. I don’t understand the role of Jenkins in you question.

    – 

  • I shared app logs as well. Jenkins log is just a bonus. But above the Jenkins log, there is already application logs.

    – 




  • why are you posting app logs when we asked for DEBUG logs, please look up how to enable debug logs

    – 

Leave a Comment