Zala Pierre GOUPIL
Zala Pierre GOUPIL

Reputation: 123

JHipster: web service without an authentication

I have a web service in my JHipster app which I need to call without an authentication:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

 @Override
    public void configure(WebSecurity web) {
        web.ignoring()
            .antMatchers(HttpMethod.OPTIONS, "/**")
            .antMatchers("/api/my_method_to_call_unauthenticated")
            .antMatchers("/app/**/*.{js,html}")
            .antMatchers("/i18n/**")
            .antMatchers("/content/**")
            .antMatchers("/swagger-ui/index.html")
            .antMatchers("/test/**");
    }
}

Then in my Java code, I have a call to (Neo4j) DB:

@Override
    public Optional<MyObject> find(String connectionId) {
        return connectionRepository.find(connectionId);
    }

Which fails with this stacktrace:

2020-11-16 14:04:36.637 ERROR 3348 --- [  XNIO-1 task-1] o.a.s.w.r.Resource    : Exception in connectionSynced() with cause = 'NULL' and exception = 'Authentication object cannot be null'

java.lang.IllegalArgumentException: Authentication object cannot be null
    at org.springframework.security.access.expression.SecurityExpressionRoot.<init>(SecurityExpressionRoot.java:60)
    at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension$1.<init>(SecurityEvaluationContextExtension.java:108)
    at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension.getRootObject(SecurityEvaluationContextExtension.java:108)
    at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider$EvaluationContextExtensionAdapter.<init>(ExtensionAwareEvaluationContextProvider.java:369)
    at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.lambda$toAdapters$2(ExtensionAwareEvaluationContextProvider.java:159)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
    at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.toAdapters(ExtensionAwareEvaluationContextProvider.java:160)
    at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.access$000(ExtensionAwareEvaluationContextProvider.java:65)
    at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider$ExtensionAwarePropertyAccessor.<init>(ExtensionAwareEvaluationContextProvider.java:182)
    at org.springframework.data.spel.ExtensionAwareEvaluationContextProvider.getEvaluationContext(ExtensionAwareEvaluationContextProvider.java:110)
    at org.springframework.data.repository.query.ExtensionAwareQueryMethodEvaluationContextProvider.getEvaluationContext(ExtensionAwareQueryMethodEvaluationContextProvider.java:89)
    at org.springframework.data.repository.query.SpelEvaluator.evaluate(SpelEvaluator.java:59)
    at org.neo4j.springframework.data.repository.query.StringBasedNeo4jQuery.bindParameters(StringBasedNeo4jQuery.java:163)
    at org.neo4j.springframework.data.repository.query.StringBasedNeo4jQuery.prepareQuery(StringBasedNeo4jQuery.java:152)
    at org.neo4j.springframework.data.repository.query.AbstractNeo4jQuery.execute(AbstractNeo4jQuery.java:69)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:618)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:605)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy184.findOwningPortfolio(Unknown Source)
    at service.impl.ConnectionServiceImpl.find(ConnectionServiceImpl.java:85)

Here is my repository:

@Repository
public interface ConnectionRepository extends Neo4jRepository<UserConnection, String> {

    @Query("MATCH (t:UserConnection { connection_id: $0 })-[:IN]-(p:Portfolio) RETURN p")
    Optional<Portfolio> find(String connectionId);
}

Indeed, I need to be authenticated in my (Neo4j) repository but I would like not to, what am I missing?

Upvotes: 1

Views: 309

Answers (2)

Zala Pierre GOUPIL
Zala Pierre GOUPIL

Reputation: 123

You're right Gaël, but the problem occurring right after this is the CSRF protection, which is unwanted here. So, I managed to have my unauthenticated web service work without CSRF with this:

@Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
            .ignoringAntMatchers("/api/my_method_to_call_unauthenticated") <<<
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
--- snip ---
        .and()
            .authorizeRequests()
            .antMatchers("/api/my_method_to_call_unauthenticated").permitAll()
            .antMatchers("/api/**").authenticated()

See here: Spring Boot

Upvotes: 1

Ga&#235;l Marziou
Ga&#235;l Marziou

Reputation: 16284

In SecurityConfiguration, web.ignoring().antMatchers("/api/my_method_to_call_unauthenticated") conflicts with .antMatchers("/api/**").authenticated() due to URL overlapping

You should rather remove it and add a permitAll() in right order:

        .antMatchers("/api/my_method_to_call_unauthenticated").permitAll()
        .antMatchers("/api/**").authenticated()

Upvotes: 0

Related Questions