Steve Maring
Steve Maring

Reputation: 195

session management in Spring Security 6.3.0 not working

I'm using Spring Boot 3.3.0. I have a custom provider and filter. The very first request from a user contains the credentials with which to authenticate. I can get my provider to successfully authenticate on the first request, but it won't create and save a session and subsequent requests, even to download images on a page, are unauthorized.

The log claims that the auth is getting stored in the securityContextImpl and I do see a session id getting created in the browser. It seems to redirect to "/" after the auth though and bypass the SecurityContextHolderFilter to land on my filter and attempt an auth again.

org.springframework.security.web.session.DisableEncodeUrlFilter@59ed17ae, 
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@631e59ca, 
org.springframework.security.web.context.SecurityContextHolderFilter@16a37ca7, 
org.springframework.security.web.header.HeaderWriterFilter@1b55440b, 
org.springframework.web.filter.CorsFilter@59262938, 
org.springframework.security.web.authentication.logout.LogoutFilter@4a28e790, 
com.example.download.config.security.filter.RefererAuthenticationFilter@293a75f6, 
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@25686005, 
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@621fef60, 
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@185b5718, 
org.springframework.security.web.session.SessionManagementFilter@532dc865, 
org.springframework.security.web.access.ExceptionTranslationFilter@f5df3ac, 
org.springframework.security.web.access.intercept.AuthorizationFilter@43ef24d5
@Configuration
@AllArgsConstructor
@EnableWebSecurity(debug = true)
public class SecurityConfig {

  @Autowired
  RefererAuthenticationProvider refererAuthenticationProvider;

  @Bean
  public AuthenticationManager authManager(HttpSecurity http) throws Exception {
    AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
    authenticationManagerBuilder.authenticationProvider(refererAuthenticationProvider);
    return authenticationManagerBuilder.build();
  }

  @Bean
  public HttpSessionSecurityContextRepository securityContextRepository() {
    return new HttpSessionSecurityContextRepository();
  }

  @Bean
  SecurityFilterChain securityFilterChain(HttpSecurity http,
                                          AuthenticationManager authManager) throws Exception {

    RefererAuthenticationFilter refererAuthenticationFilter = new RefererAuthenticationFilter(authManager);
    refererAuthenticationFilter.setSecurityContextRepository(securityContextRepository());
    return http
      .csrf(AbstractHttpConfigurer::disable)
      .addFilterAt(refererAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
      .sessionManagement((session) -> {
        session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
      })
      .authorizeHttpRequests( request -> { request
        .anyRequest().authenticated();
      })
      .headers( headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable) )
      .authenticationManager( authManager )
      .build();

  }

}
@Slf4j
@Component
public class RefererAuthenticationProvider implements AuthenticationProvider {

  @Value("${referer}")
  private String validReferer;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    UsernamePasswordAuthenticationToken challengeAuth = (UsernamePasswordAuthenticationToken) authentication;
    log.debug( "starting authentication ..." );
    Referer referer = (Referer) challengeAuth.getPrincipal();
    if ( referer.getUrl().startsWith(validReferer) &&
         referer.getFetchDest().equals("iframe")
    ) {
      log.debug( "auth requirements met" );
      SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_CUSTOMER");
      List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
      grantedAuthorities.add(authority);
      return new UsernamePasswordAuthenticationToken( referer, null, grantedAuthorities);
    } else {
      log.debug( "unable to auth referer " + referer.getUrl() + " with fetchDest " + referer.getFetchDest() );
    }
    throw new BadCredentialsException("referer did not match within the iframe");
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals( UsernamePasswordAuthenticationToken.class );
  }

}
@Slf4j
public class RefererAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

  private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("**","GET");

  public RefererAuthenticationFilter(AuthenticationManager authenticationManager) {
    super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
    setAuthenticationManager(authenticationManager);
  }

  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
    String url        = request.getHeader( "Referer" );
    String fetchDest  = request.getHeader( "Sec-Fetch-Dest" );
    String id         = request.getParameter( "id" );
    String name       = request.getParameter( "name" );
    String email      = request.getParameter( "email" );
    String ipAddress = request.getHeader("X-FORWARDED-FOR");
    if (ipAddress == null) {
      ipAddress = request.getRemoteAddr();
    }

    log.debug( "referer: "      + url );
    log.debug( "secFetchDest: " + fetchDest );
    log.debug( "id: "           + id );
    log.debug( "name: "         + name );
    log.debug( "email: "        + email );
    log.debug( "ipAddress: "    + ipAddress );

    if (  url == null ||          url.isEmpty() ||
          fetchDest == null ||    fetchDest.isEmpty() ||
          ipAddress == null ||    ipAddress.isEmpty() ||
          id == null ||           id.isEmpty() ||
          name == null ||         name.isEmpty() ||
          email == null ||        email.isEmpty()
    ) {
      log.debug( "requirements not met for RefererAuthenticationFilter" );
      throw new AuthenticationServiceException( "requirements not met for RefererAuthenticationFilter");
    }

    Referer referer = new Referer();
    referer.setUrl(url);
    referer.setFetchDest(fetchDest);
    referer.setId(id);
    referer.setName(name);
    referer.setEmail(email);
    referer.setIpAddress(ipAddress);

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( referer, null);
    Authentication authentication = this.getAuthenticationManager().authenticate(authRequest);

    return authentication;
  }

}
DEBUG [http-nio-8080-exec-3] o.s.s.w.FilterChainProxy: Securing GET /10.1.0.0-GA?id=c49c60eb0435c2dcdeeae6305c44b3216b4bf083&[email protected]&name=John%20Doe
2024-07-12 06:28:20,809 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.f.RefererAuthenticationFilter: referer: http://support.example.com/
2024-07-12 06:28:20,810 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.f.RefererAuthenticationFilter: secFetchDest: iframe
2024-07-12 06:28:20,810 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.f.RefererAuthenticationFilter: id: c49c60eb0435c2dcdeeae6305c44b3216b4bf083
2024-07-12 06:28:20,810 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.f.RefererAuthenticationFilter: name: John Doe
2024-07-12 06:28:20,810 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.f.RefererAuthenticationFilter: email: [email protected]
2024-07-12 06:28:20,810 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.f.RefererAuthenticationFilter: ipAddress: 0:0:0:0:0:0:0:1
2024-07-12 06:28:20,811 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.p.RefererAuthenticationProvider: starting authentication ...
2024-07-12 06:28:20,811 DEBUG [http-nio-8080-exec-3] c.p.d.c.s.p.RefererAuthenticationProvider: auth requirements met
2024-07-12 06:28:20,812 DEBUG [http-nio-8080-exec-3] o.s.s.w.c.HttpSessionSecurityContextRepository: Stored SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=Referer(url=http://support.example.com/, fetchDest=iframe, id=c49c60eb0435c2dcdeeae6305c44b3216b4bf083, name=John Doe, [email protected], ipAddress=0:0:0:0:0:0:0:1), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_CUSTOMER]]] to HttpSession [org.apache.catalina.session.StandardSessionFacade@3b6cf243]
2024-07-12 06:28:20,812 DEBUG [http-nio-8080-exec-3] o.s.s.w.a.AbstractAuthenticationProcessingFilter: Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=Referer(url=http://support.example.com/, fetchDest=iframe, id=c49c60eb0435c2dcdeeae6305c44b3216b4bf083, name=John Doe, [email protected], ipAddress=0:0:0:0:0:0:0:1), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_CUSTOMER]]
2024-07-12 06:28:20,812 DEBUG [http-nio-8080-exec-3] o.s.s.w.DefaultRedirectStrategy: Redirecting to /
2024-07-12 06:28:20,822 DEBUG [http-nio-8080-exec-4] o.s.s.w.FilterChainProxy: Securing GET /
2024-07-12 06:28:20,825 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: referer: http://support.example.com/
2024-07-12 06:28:20,826 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: secFetchDest: iframe
2024-07-12 06:28:20,827 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: id: null
2024-07-12 06:28:20,827 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: name: null
2024-07-12 06:28:20,827 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: email: null
2024-07-12 06:28:20,828 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: ipAddress: 0:0:0:0:0:0:0:1
2024-07-12 06:28:20,828 DEBUG [http-nio-8080-exec-4] c.p.d.c.s.f.RefererAuthenticationFilter: requirements not met for RefererAuthenticationFilter
2024-07-12 06:28:20,828 DEBUG [http-nio-8080-exec-4] o.s.s.w.a.SimpleUrlAuthenticationFailureHandler: Sending 401 Unauthorized error

Upvotes: 0

Views: 26

Answers (0)

Related Questions