Access core component from global module without SecurityContext

Good day,

I cannot find a way to inject a custom @Component-annotated class from the core module into the global module.

I have a custom controller in the web module which will be called without a user having been signed in. I then pass the work to the global module to handle the received data (this involves creating a new thread). This part is working fine.

In the handling class in global, I am trying to pass filtered data to a different method in order to make changes to the database. The database work is spread across multiple nested transactions, meaning I cannot make use of DataManager. Since EntityManager is only available in the core module, I am then trying to inject the necessary code into the global handling class.

Since no user has signed in to perform this action, if I inject a @Service-annotated class I get the error No security context bound to the current thread. I do not want to allow anonymous access to these methods. I don’t want to allow these to be accessed by the REST API at all. They are only for internal use.

To work around that problem, I try to make the class annotated with @Component instead. But now I get the error No qualifying bean of type '<my interface type>' available: expected at least 1 bean which qualifies as autowire candidate. I declared the interface in the global module, and implemented it in the core module, the same way as is done for services.

Do I need to add extra configuration to make this work? Is this even possible?

EDIT:
Platform version: 6.10

I have been able to work around this problem by using the Global Events add-on, and sending events instead of directly calling the components. So far it looks like it’s working well, and was easy to set up.

1 Like

You can use authentication on demand when you need to access middleware from unauthenticated client code:

@Inject
private DemoService demoService;
@Inject
private AuthenticationService authenticationService;
@Inject
private WebAuthConfig webAuthConfig;
@Inject
private UserSessionService userSessionService;

private UUID userSessionId;

// some method invoked from unauthenticated code
public String echo(String input) {
    UserSession userSession = null;

    // if there is a saved session id, try to find this session
    if (userSessionId != null) {
        try {
            userSession = userSessionService.getUserSession(userSessionId);
        } catch (NoUserSessionException e) {
            // session is expired
        }
    }

    // if session wasn't created or is expired, login
    if (userSession == null) {
        AuthenticationDetails authenticationDetails = authenticationService.login(
                new TrustedClientCredentials("admin", webAuthConfig.getTrustedClientPassword(), Locale.ENGLISH));
        userSession = authenticationDetails.getSession();
        userSessionId = userSession.getId(); // save the session id
    }

    return AppContext.withSecurityContext(
            new SecurityContext(userSession),
            () -> demoService.echo(input) // code to execute
    );
}

Or even simpler: use TrustedClientService as shown here.

So using Global Events can be an overkill for your task.

1 Like

Actually, in our case it might not be overkill, since we need to run the code asynchronously anyway. We’re using @Authenticated in order to make changes to the DB, which also saves us from storing a password in our files or making a call to retrieve the password from the external system we use.

But thank you for this alternative. I had done lots of research to try to find something like that, and somehow missed the docs on that and the link you posted. It could be useful in the future, so thanks for bringing it to my attention!