Global authorization allows non-authenticated users on the process engine to read defintions

Hi,

I am using an identity plugin to add users dynamically to process engines in my system.

In my case I have two process engine instances: PE 1 and PE 2. When a process engine PE 1 authorizes process definitions for all users in the process engine using:

Authorization processDefinitionAuth
            = processEngine.getAuthorizationService()
            .createNewAuthorization(Authorization.AUTH_TYPE_GLOBAL);
auth.setResource(Resources.PROCESS_DEFINITION);
auth.setResourceId("*");
auth.addPermission(Permissions.ALL);
processEngine.getAuthorizationService().saveAuthorization(auth);

A user, who is authenticated on process engine PE 2 but not on PE 1, is authorized also to access definitions from PE 1 in Optimize.
Is there a way to allow only users authenticated on the process engine can read the definitions on that process engine?

Hi @Abdelrahman_Ibrahim,

This is unusual, I replicated this scenario and could not reproduce this behaviour. Usually, Optimize differentiates between different engine data sources when checking user authorizations, lets try to figure out why this is not happening correctly in your setup.

Can you confirm that the definition keys are unique, ie that the key of the definition the user is trying to access only exists on PE 1 and not on PE 2? Same question also for the user, lets confirm that this user definitely only exists on PE 2.

Also, can you give some more information about the setup itself: were both engines configured in Optimize from the first start? Or did Optimize start, import some data and then later on the second engine was added?

Hi @Helene ,

Thanks for replying.

Can you confirm that the definition keys are unique

Yes, I can confirm that they are different.

lets confirm that this user definitely only exists on PE 2

I debugged the identity plugin and the ReadOnlyIdentityProvider.checkPassword() method returns false for the user in PE 1 and also UserQueryImpl.executeList() method with the user Id returns an empty list in case of PE 1, while PE 2 the ReadOnlyIdentityProvider.checkPassword() method returns true and the UserQueryImpl.executeList() returns a list of length 1 as expected.

To double check, when querying the process engines’ API for user “userx”

For PE 1

{
    "authenticatedUser": "userx",
    "groups": null,
    "tenants": null,
    "authenticated": false
}

For PE 2

{
    "authenticatedUser": "userx",
    "groups": null,
    "tenants": null,
    "authenticated": true
}

The process engine end points return the following results when queried for the permissions for the user.
For PE 1

[
    {
        "id": "2301",
        "type": 0,
        "permissions": [
            "ALL"
        ],
        "userId": "*",
        "groupId": null,
        "resourceType": 6,
        "resourceId": "*",
        "removalTime": null,
        "rootProcessInstanceId": null
    },
    {
        "id": "2302",
        "type": 0,
        "permissions": [
            "ALL"
        ],
        "userId": "*",
        "groupId": null,
        "resourceType": 0,
        "resourceId": "optimize",
        "removalTime": null,
        "rootProcessInstanceId": null
    }
]

And for PE 2

[
    {
        "id": "2501",
        "type": 0,
        "permissions": [
            "ALL"
        ],
        "userId": "*",
        "groupId": null,
        "resourceType": 6,
        "resourceId": "*",
        "removalTime": null,
        "rootProcessInstanceId": null
    },
    {
        "id": "2502",
        "type": 0,
        "permissions": [
            "ALL"
        ],
        "userId": "*",
        "groupId": null,
        "resourceType": 0,
        "resourceId": "optimize",
        "removalTime": null,
        "rootProcessInstanceId": null
    }
]

were both engines configured in Optimize from the first start?

Yes, they were configured from the first start.

Hi @Abdelrahman_Ibrahim ,

So this looks like both PE 1 and PE 2 return a result which includes a global authorization for the definitions on each engine for this user (authorization with id 2301 for PE 1 and 2501 for PE 2), this is probably why the user can see definitions from both engines in Optimize.
Do both engines share the same Database or does each engine have its own Database?

Hi @Helene ,

They have different databases.

Hi again,

Hm that’s not it then. You wrote above that you are using an identity plugin, so it sounds like these users don’t exist on the engines but rather an external identity service.
What exactly is the identity service you’re using? And is the same service connected to both engines? If so then this could be the reason both engines return all permissions for this user. Also, could you tell me which endpoint you used above for querying the permissions of the user?

Hi @Helene ,

it sounds like these users don’t exist on the engines but rather an external identity service

Yes, that is correct.

What exactly is the identity service you’re using?

I implemented the ReadOnlyIdentityProvider interface using java code that returns results based on users in my system.

And is the same service connected to both engines?

I pass different ReadOnlyIdentityProvider objects with different states for each engine. This is why userx is authenticated on PE 2 and not PE 1 as shown in the JSON responses of my reply

this is using the following endPoints

for authentication a POST request to

https://[processEngineRestUrl]/engine/[Process engine name]/identity/verify

with body

{
    "username": "userx",
    "password": "[userxpassword]"
}

for authorization

GET
https://[processEngineRestUrl]/engine/[Process engine name]/authorization?userIdIn=userx%2C%2A&firstResult=0

Hi @Abdelrahman_Ibrahim ,

Thanks again for the detailed reply, currently to me it looks like this userx exists on both engines but is just not authenticated on one of them, lets see if we can confirm this.

I think using /verify doesn’t necessarily tell us whether the user exists on this engine or not, because the result for a user that exists but just isn’t authenticated looks the same as the result for a user which actually does not exist on this engine.
Could you try the get users endpoint instead, with userx’ ID as query parameter?

Hi @Helene ,

Thanks for replying.

I tried the endpoint you suggested with the id as the query parameter. PE 1 returned an empty list while PE 2 returned a list with one entry corresponding to "userx"

Hi again,
Thanks again for the quick reply.

That’s odd, this really doesn’t explain why userx still receives the global authorizations from PE 1 if they do not exist there. I will reach out to someone from the engine team now, they are more familiar with the product than me so should hopefully be able to help us figure out this issue.

1 Like

Hi @Abdelrahman_Ibrahim ,

So, turns out what we are observing here is actually expected behaviour. I’ve had a chat with the engine team and have learned the following:

Because the engine supports setups where user management is not integrated with the engine, authorizations are generally independent of whether the user exists in the identity provider. This is what’s leading to your global authorizations being returned for userx on both engines even though userx is only authenticated on one of them.
Optimize currently mirrors this behaviour, we also ask the engine(s) to give us all authorizations of userx, the engine then returns all the global authorizations you’ve listed above, and then Optimize grants the user access to all definitions included in those authorizations.
Technically, this is Optimize following the authorizations that are given by the engine, but I agree that this behaviour is confusing, which is why I’ve opened a ticket for us to evaluate whether we can adjust the Optimize authorization handling to additionally take authentication into account, thereby filtering authorizations and only respecting those for engines that the given user really exists on.

For now though, the only workaround I see to your problem is to avoid global authorizations in general. Instead, you could add all users on each engine to a group and then grant definition access to this specific group.

Hope that helps!

3 Likes