Exception while using repository from CubaAuthProvider.doFilter()

I’ve create repository in app-global :


import com.company.cuba.entity.CustomUser;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component(CustomUserRepository.NAME)
public class CustomUserRepository {
    public static final String NAME = "cuba_CustomUserRepository";

    private DataManager dataManager;

    public CustomUserRepository(DataManager dataManager) {
        this.dataManager = dataManager;
    }

    public Optional<CustomUser> findUserByCustomId(String customId) {
      
        LoadContext<CustomUser> loadContext = new LoadContext(CustomUser.class);
        loadContext.setQueryString("select u from custom$User u where u.customId = :customId")
                .setParameter("customId", customId);

        CustomUser customUser = dataManager.load(loadContext);  //????? ????????? ??????.

        return Optional.ofNullable(customUser);
    }
}

When I try to use this repository in app-web module -

CubaAuthProvider.doFilter()

method I have an exception:


java.lang.SecurityException: No security context bound to the current thread
    at com.haulmont.cuba.core.sys.AppContext.getSecurityContextNN(AppContext.java:148)
    at com.haulmont.cuba.core.sys.ServiceInterceptor.aroundInvoke(ServiceInterceptor.java:85)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy107.load(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy153.load(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.remoting.support.RemoteInvocation.invoke(RemoteInvocation.java:212)
    at com.haulmont.cuba.core.sys.remoting.CubaRemoteInvocationExecutor.invoke(CubaRemoteInvocationExecutor.java:109)
    at org.springframework.remoting.support.RemoteInvocationBasedExporter.invoke(RemoteInvocationBasedExporter.java:78)
    at org.springframework.remoting.support.RemoteInvocationBasedExporter.invokeAndCreateResult(RemoteInvocationBasedExporter.java:114)
    at com.haulmont.cuba.core.sys.remoting.HttpServiceExporter.handleRequest(HttpServiceExporter.java:77)
    at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:51)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
    at com.haulmont.cuba.core.sys.remoting.RemotingServlet.doService(RemotingServlet.java:149)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
    at org.springframework.remoting.support.RemoteInvocationUtils.fillInClientStackTraceIfPossible(RemoteInvocationUtils.java:45)
    at org.springframework.remoting.support.RemoteInvocationResult.recreate(RemoteInvocationResult.java:149)
    at org.springframework.remoting.support.RemoteInvocationBasedAccessor.recreateRemoteInvocationResult(RemoteInvocationBasedAccessor.java:85)
    at com.haulmont.cuba.core.sys.remoting.HttpServiceProxy.recreateRemoteInvocationResult(HttpServiceProxy.java:53)
    at org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor.invoke(HttpInvokerClientInterceptor.java:150)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    at com.sun.proxy.$Proxy192.load(Unknown Source)
    at com.haulmont.cuba.client.sys.DataManagerClientImpl.load(DataManagerClientImpl.java:47)
    at com.company.cuba.repository.CustomUserRepository.findUserByCustomId(CustomUserRepository.java:34)
    at com.company.cuba.security.CheckUserService.checkUserInSession(CheckUserService.java:62)
    at com.company.cuba.security.CustomAuthProvider.doFilter(CustomAuthProvider.java:49)
    at com.haulmont.cuba.web.sys.CubaHttpFilter.filterByAuthProvider(CubaHttpFilter.java:114)
    at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:91)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

What is wrong with this code? How can I read from DB in CubaAuthProvider.doFilter()?

The similar exception occurs when I try to use EntityManager in core module and use it through a service.

I’ve added the service interface in app-global:


package com.company.cuba.service;

import com.company.cuba.entity.CustomUser;

import java.util.Optional;

public interface CustomUserService {
    String NAME = "cuba_CustomUserService";

    public Optional<CustomUser> findUserByCustomId(String customId);
}

I’ve added the service implementation in app-core:


package com.company.cuba.service;

import com.company.cuba.entity.CustomUser;
import com.company.cuba.repository.CustomUserRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service(CustomUserService.NAME)
public class CustomUserServiceBean implements CustomUserService {

    private final CustomUserRepository userRepository;

    public CustomUserServiceBean(CustomUserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public Optional<CustomUser> findUserByCustomId(String customId) {
        return userRepository.findUserByCustomId(customId);
    }

}

I’ve added bean creator in web-spring.xml (app-web):


<bean class="com.haulmont.cuba.web.sys.remoting.WebRemoteProxyBeanCreator">
        <property name="clusterInvocationSupport"
                  ref="cuba_clusterInvocationSupport"/>
        <property name="remoteServices">
            <map>
                <entry key="cuba_ CustomUserService" value="com.company.cuba.service. CustomUserService"/>
            </map>
        </property>
    </bean>

I’ve inject service in custom component in app-web:


@Component(CheckUserService.NAME)
public class CheckUserService {
    public static final String NAME = "cuba_CheckUserService";

    private CustomUserService customUserService;

    public CheckUserService(CustomUserService customUserService) {
        this.customUserService = customUserService;
    }

    public Optional<CustomUser> checkUserInSession(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            // some logic...
            return customUserService.findUserByCustomId(customId);
    }
}

Then finally I use injected component in CubaAuthProvider implementation:


public class CustomAuthProvider implements CubaAuthProvider {

    @Inject
    CheckUserService checkUserService;

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
       
       // some logic...

       // java.lang.SecurityException: No security context bound to the current thread
       Optional<CustomUser> userOpt = checkUserService.checkUserInSession(request, response);  

    }
}

Am I able to use JPA in CubaAuthProvider.doFilter() ?

Oh, CustomUserRepository (app-core) become:


package com.company.cuba.repository;

import com.company.cuba.entity.CustomUser;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.TypedQuery;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component(CustomUserRepository.NAME)
public class CustomUserRepository {
    public static final String NAME = "cuba_CustomUserRepository";

    private Persistence persistence;

    public CustomUserRepository(Persistence persistence) {
        this.persistence = persistence;
    }

    public Optional<CustomUser> findUserByCustomId(String customId) {
        EntityManager em = persistence.getEntityManager();
       
        TypedQuery<CustomUser> query = em.createQuery("select u from custom$User u where u.customId = :customId", CustomUser.class);
        query.setParameter("customId", customId);
        CustomUser customUser = query.getSingleResult();
        
        return Optional.ofNullable(customUser);
    }
}

But there is a difference. With service-way there are not even

CustomUserServiceBean.findUserByCustomId()

method invoked.

Hi,

You cannot call JPA directly from CubaAuthProvider since it is executed on web tier. The only way to call JPA code is to call Service that will perform DB operations.

In case of CubaAuthProvider you cannot use services until you obtain SecurityContext. CubaAuthProvider doFilter is executed when standard anonymous session is not available and you can only perform a service call if you obtain user session and set SecurityContext manually.

You can obtain anonymous session from LoginService and then use it in the following way:


LoginService loginService = AppBeans.get(LoginService.class);
WebAuthConfig webAuthConfig = AppBeans.get(Configuration.class).getConfig(WebAuthConfig.class);

UserSession anonymousSession;
try {
    anonymousSession = loginService.getSystemSession(webAuthConfig.getTrustedClientPassword());
} catch (LoginException e) {
    throw new RuntimeException("Unable to obtain anonymous session");
}

AppContext.withSecurityContext(new SecurityContext(anonymousSession), () -> {
    // perform your service call here
});

Please note, that Optional<> is not Serializable in Java. Thus your service code will not work in cluster.

1 Like