Stack:
spring boot 2.7.15spring-boot-starter-data-jpa 2.7.15spring-data-envers 2.7.15
I have the following entity:
@Audited
@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyUser{
}
With the auditor config class JpaAuditingConfiguration:
@Configuration
@AutoConfigureAfter(name = "org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration")
@EnableJpaAuditing
public class JpaAuditingConfiguration {
@Bean
public AuditorAware<Long> auditorAware(MyUserService myUserService ) {
return myUserService::getCurrentUserId;
}
}
And the MyUserService class:
@Service
@RequiredArgsConstructor
public class MyUserService {
public Optional<Long> getCurrentUserId() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof OAuth2AuthenticatedPrincipal) {
// logic here
}
return Optional.empty();
}
}
My problem comes here: I have a Bean from our internal authorization/authentication framework which sets/enriches spring's Authentication object and it is triggered when the user logins in the UI. In this bean method, one entity is modified and persisted into the database:
public Set<String> retrieveUserAuthorities(String username) {
Optional<MyUser> userOptional = userRepository.findByUsername(username);
if (userOptional.isPresent()) {
MyUser user = userOptional.get();
// different setters for user
myUserService.saveUser(user); // <--- here is the problem
return ...
}
// ...
}
Problem:
Basically, the problem is that the entity is persisted into the database before the Authentication object is set, thus getting a NPE when the audit flow is triggered and it reaches method getCurrentUserId() where SecurityContextHolder.getContext().getAuthentication() is null.
In my case, I want only this database operation NOT TO BE persisted, but others on that entity to be persisted, so removing Audited or @EntityListeners is not an option.
Maybe a simple null check before accessing the
principalobject should do the trick.It is not surprising to find the
authenticationobject asnullin spring security.