Description
If you enable the automatic index creation with spring.data.mongodb.auto-index-creation=true
or use the other documented ways to automatically create indexes on startup, it fails if you have spring-security-data extension on your classpath
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
because there is no SecurityContext active to initialize then context (getRootObject) in SecurityEvaluationContextExtension
.
It fails because the (default) EvaluationContext used for index creation search for all available extensions and find the problematic one SecurityEvaluationContextExtension
.
My current workaround was to programmatically create the indexes and wrap the call with a fake-SecurityContext.
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() throws Exception {
runWithSystemContext(this::createIndexes);
}
private Boolean createIndexes() {
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);
mappingContext.getPersistentEntities()
.stream()
.filter(it -> it.isAnnotationPresent(Document.class))
.forEach(it -> {
IndexOperations indexOps = mongoTemplate.indexOps(it.getType());
resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex);
});
return true;
}
static <T> T runWithSystemContext(Callable<T> runnable) throws Exception {
SecurityContext originalContext = SecurityContextHolder.getContext();
SecurityContext systemContext = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken("system", null, null);
systemContext.setAuthentication(authentication);
try {
SecurityContextHolder.setContext(systemContext);
return runnable.call();
} finally {
SecurityContextHolder.setContext(originalContext);
}
}
complete Stacktrace for the error:
java.lang.IllegalArgumentException: Authentication object cannot be null
at org.springframework.security.access.expression.SecurityExpressionRoot.(SecurityExpressionRoot.java:76) ~[spring-security-core-5.7.11.jar:5.7.11]
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension$1.(SecurityEvaluationContextExtension.java:124) ~[spring-security-data-5.7.11.jar:5.7.11]
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension.getRootObject(SecurityEvaluationContextExtension.java:124) ~[spring-security-data-5.7.11.jar:5.7.11]
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension.getRootObject(SecurityEvaluationContextExtension.java:89) ~[spring-security-data-5.7.11.jar:5.7.11]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider$EvaluationContextExtensionAdapter.(ExtensionAwareEvaluationContextProvider.java:415) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.lambda$toAdapters$3(ExtensionAwareEvaluationContextProvider.java:202) ~[spring-data-commons-2.7.18.jar:2.7.18]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.toAdapters(ExtensionAwareEvaluationContextProvider.java:203) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.access$000(ExtensionAwareEvaluationContextProvider.java:67) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider$ExtensionAwarePropertyAccessor.(ExtensionAwareEvaluationContextProvider.java:225) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.doGetEvaluationContext(ExtensionAwareEvaluationContextProvider.java:131) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.getEvaluationContext(ExtensionAwareEvaluationContextProvider.java:111) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.getEvaluationContext(ExtensionAwareEvaluationContextProvider.java:67) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.mapping.model.BasicPersistentEntity.getEvaluationContext(BasicPersistentEntity.java:557) ~[spring-data-commons-2.7.18.jar:2.7.18]
at org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity.getEvaluationContext(BasicMongoPersistentEntity.java:219) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.getEvaluationContextForProperty(MongoPersistentEntityIndexResolver.java:664) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.resolveCompoundIndexKeyFromStringDefinition(MongoPersistentEntityIndexResolver.java:499) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.createCompoundIndexDefinition(MongoPersistentEntityIndexResolver.java:437) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.createCompoundIndexDefinitions(MongoPersistentEntityIndexResolver.java:427) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.potentiallyCreateCompoundIndexDefinitions(MongoPersistentEntityIndexResolver.java:285) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.resolveIndexForEntity(MongoPersistentEntityIndexResolver.java:127) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.resolveIndexFor(MongoPersistentEntityIndexResolver.java:104) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at org.springframework.data.mongodb.core.index.IndexResolver.resolveIndexFor(IndexResolver.java:79) ~[spring-data-mongodb-3.4.18.jar:3.4.18]
at de.onestytech.bvo.documentstorage.config.MongoIndexCreator.lambda$createIndexes$1(MongoIndexCreator.java:45) ~[classes/:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) ~[na:na]
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[na:na]
at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[na:na]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[na:na]
at de.onestytech.bvo.documentstorage.config.MongoIndexCreator.createIndexes(MongoIndexCreator.java:43) ~[classes/:na]
at de.onestytech.bvo.documentstorage.config.MongoIndexCreator.initIndicesAfterStartup(MongoIndexCreator.java:31) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:569) ~[na:na]
at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:344) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:229) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:166) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:145) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:429) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:386) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:949) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:594) ~[spring-context-5.3.31.jar:5.3.31]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.18.jar:2.7.18]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[spring-boot-2.7.18.jar:2.7.18]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409) ~[spring-boot-2.7.18.jar:2.7.18]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.18.jar:2.7.18]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.7.18.jar:2.7.18]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) ~[spring-boot-2.7.18.jar:2.7.18]