Spring beans available in scripts and expressions

Hi,

Migrating from 7.9 to 7.13, I encountered a small problem with the way Spring beans are made accessible in scripts and expressions.

I have a process engine plugin which declares custom beans which can be accessed by Groovy scripts. All the other contextual Spring beans should not be accessible in scripts / expressions, but they seem to be. What worse is that they override my custom beans (for 2 beans with identical name).

Camunda version: 7.13
Setup: Spring Boot Application
DB: H2

As stated by the documentation, it should at least not be the case for expressions : https://docs.camunda.org/manual/latest/user-guide/spring-framework-integration/expressions/#using-spring-beans-in-scripting

This change seems to have been introduced in 7.12, which register a SpringBeansResolverFactory.

I’ve created a repository which reproduce this bug, and give a more detailed analyze in the README : https://github.com/hbeaufils/camunda-limit-exposed-beans-sample

To sum it up, here’s what I do :

Using the lastest simple Camunda Webapp sample, I declare a Spring bean in my application :

@Component
public class SomeBean {

    public void printMessage() {
        System.out.println("Expression bean: SomeBean");
    }
}

I also add a class to represent a custom bean which I’d like to override someBean with:

public class MyCustomScriptBean {

    public void printMessage() {
        System.out.println("Expression bean: MyCustomScriptBean");
    }
}

Then I declare a process engine plugin to configure my custom beans which should be accessible in scripts and expressions :

@Component
public class MyCustomBeanPlugin extends AbstractProcessEnginePlugin {

    @Override
    public void postInit(ProcessEngineConfigurationImpl conf) {

        conf.getBeans().put("someBean", new MyCustomScriptBean());
        conf.getBeans().put("someBeanWithADifferentName", new MyCustomScriptBean());
    }
}

Finally, I updated the sample model to contain 2 activies :

  • one Groovy script
  • one Expression delegate task

The Groovy script does this:

def beanClass = someBean.getClass().getName()
def beanClass2 = someBeanWithADifferentName.getClass().getName()

println("Bean class: " + beanClass)
println("Bean class (when using a different name): " + beanClass2)

And the expression this:

#{someBean.printMessage()}

When I start a process instance, I will see the following logs:

Bean class: org.camunda.bpm.spring.boot.example.autodeployment.SomeBean
Bean class (when using a different name): org.camunda.bpm.spring.boot.example.autodeployment.MyCustomScriptBean
Expression bean: SomeBean

So it appears that the Spring beans are always accessible, and override all custom beans.
This is due to the way the ScriptBindings#get(...) method works, and the order of the resolver factories.

Is this a known issue ? A problem in the documentation ?
I feel like it would be great to at least be able to override the contextual Spring beans, and maybe to limit their exposure with a property or something.

Of course, there’s still a hack to bypass this, by removing the SpringBeansResolverFactory, but it’s not really clean / user friendly.

I would say it would be cleaner to create a new SessionManager for accessing the beans. So you can access the beans using Context.getSessionManager() (or something like that).

You can create a new session manager / session class and then register it in the process engine config using a plugin.

When a thread is created it creates the session class (or reuses the cached class) and you can easily access it with Context

It’s Context.getCommandContext().getSession(MyBeansManagerSession.class)

And then you use that session instance to access your beans

Alright, this might be a good solution to access specific beans, but it’s not really the problem here.
The fact is that we cannot prevent the access, from expressions and scripts, to internal Spring beans which should be service related only. Depending on the use case, this might be a security problem if the people writing scripts don’t have the right to manage the Camunda application.

Additionally, this solution is not really “user friendly”, because if you’re supposed to regularly use these beans in your expressions, you would always have to refer to the MyBeansManagerSession first.

Also, if this is actually a choice of Camunda, the documentation should be consistent with the implementation.