Describe the bug When a rest resource is protected by a SecurityFilterChain as a oauth2ResourceServer with jwt enabled and there is no security Bearer token or incorrect(unable to parse) provided, this is not reported as a AUTHENTICATION_FAILURE event by the ProviderManager.
Spring-boot version used: 2.7.11
To Reproduce @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http.oauth2ResourceServer(oauth2 -> {
oauth2.jwt();
})
.build();
// @formatter:on
} Provide also a AuditEventRepository
@Bean
public AuditEventRepository auditEventRepository() {
// constructor also takes a default number of items to store in-memory for
// tuning
return new InMemoryAuditEventRepository();
}
Dump Audit events to logging:
` @Component public class AuditApplicationEventLogger {
private final Log logger = LogFactory.getLog(getClass());
@Autowired
private Jackson2ObjectMapperBuilder builder;
@EventListener
public void auditEventHappened(AuditApplicationEvent auditApplicationEvent) {
AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
try {
String auditApplicationEventAsString = builder.build().writeValueAsString(auditEvent);
if (StringUtils.endsWithIgnoreCase(auditEvent.getType(), "SUCCESS")) {
if( logger.isDebugEnabled()) {
logger.debug(auditApplicationEventAsString);
}
} else {
logger.warn(auditApplicationEventAsString);
}
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
logger.warn(e);
}
}
} `
Call rest endpoint without any security Bearer token and there will be no auditevent created
Expected behavior Empty / none or miss formed Bearer token should be also reported as a AUTHENTICATION_FAILURE . The same as if the token is invalid (time expired)
Comment From: jzheaux
Hi, @mancave, thanks for the report. If there is no bearer token or it is malformed, the ProviderManager is never invoked. In Spring Security, authentication is attempted for only well-formed authentication requests. In the cases you described, no authentication is attempted, so there is no failure to report.
Moreover, all authentication failure event classes use the Authentication request instance as the event source, meaning that there is no AbstractAuthenticationFailureEvent that can be constructed without a fully-qualified authentication request. For example, you cannot construct BadCredentialsAuthenticationFailureEvent with a null Authentication instance.
Given those constraints, I'd recommend that you create a custom event for when the request is malformed. You could create a custom BearerTokenResolver that fires such an event like so:
@Component
public final class EventPublishingBearerTokenResolver implements BearerTokenResolver, ApplicationContextAware {
private final BearerTokenResolver delegate = new DefaultBearerTokenResolver();
private ApplicationContext context;
@Override
String resolve(HttpServletRequest request) {
try {
return this.delegate.resolve(request);
} catch (OAuth2AuthenticationException ex) {
// ... publish event to application context
throw ex;
}
}
@Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
}
If you must use an instance of BearerTokenAuthenticationToken or must use AuthenticationEventPublisher for your metrics to function correctly, you can alternatively place a dummy value into BearerTokenAuthenticationToken and publish that:
@Component
public final class EventPublishingBearerTokenResolver implements BearerTokenResolver {
private final BearerTokenResolver delegate = new DefaultBearerTokenResolver();
private final AuthenticationEventPublisher publisher;
@Autowired
public EventPublishingBearerTokenResolver(AuthenticationEventPublisher publisher) {
this.publisher = publisher;
}
@Override
String resolve(HttpServletRequest request) {
try {
return this.delegate.resolve(request);
} catch (OAuth2AuthenticationException ex) {
this.publisher.publishAuthenticationFailure(
new InvalidBearerTokenException(ex.getMessage()),
new BearerTokenAuthenticationToken("no-token"));
throw ex;
}
}
}
I don't think that Spring Security should publish an event in this way for malformed requests and as such I'll close this issue. However, please feel free to add more detail if it seems I've misunderstood.