Reputation: 195
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