Identity Service
The identity service is an API abstraction over various user/group repositories. The basic entities are
- User: a user identified by a unique Id
- Group: a group identified by a unique Id
- Membership: the relationship between users and groups
- Tenant: a tenant identified by a unique Id
- Tenant Membership: the relationship between tenants and users/groups
Example:
User demoUser = processEngine.getIdentityService()
.createUserQuery()
.userId("demo")
.singleResult();
CIB seven distinguishes between read-only and writable user repositories. A read-only user repository provides read-only access to the underlying user/group database. A writable user repository allows write access to the user database which includes creating, updating and deleting users and groups.
To provide a custom identity provider implementation, the following interfaces can be implemented:
- org.cibseven.bpm.engine.impl.identity.ReadOnlyIdentityProvider
- org.cibseven.bpm.engine.impl.identity.WritableIdentityProvider
Custom Whitelist for User, Group and Tenant IDs
User, Group and Tenant IDs can be matched against a Whitelist Pattern to determine if the provided ID is acceptable or not. The default (global) Regular Expression pattern to match against is "[a-zA-Z0-9]+|camunda-admin" i.e. any combination of alphanumeric values or ‘camunda-admin’.
If your organisation allows the usage of additional characters (ex.: special characters), the ProcessEngineConfiguration propery generalResourceWhitelistPattern should be set with the appropriate pattern in the engine’s configuration file. Standard Java Regular Expression syntax can be used. For example, to accept any character, the following property value can be used:
<property name="generalResourceWhitelistPattern" value=".+"/>
The definition of different patterns for User, Group and Tenant IDs is possible by using the appropriate configuration propery:
<property name="userResourceWhitelistPattern" value="[a-zA-Z0-9-]+" />
<property name="groupResourceWhitelistPattern" value="[a-zA-Z]+" />
<property name="tenantResourceWhitelistPattern" value=".+" />
Note that if a certain pattern isn’t defined (ex. the tenant whitelist pattern), the general pattern will be used, either the default one ("[a-zA-Z0-9]+|camunda-admin") or one defined in the configuration file.
The Database Identity Service
The database identity service uses the process engine database for managing users and groups. This is the default identity service implementation used if no alternative identity service implementation is provided.
The database identity service implements both ReadOnlyIdentityProvider and WritableIdentityProvider providing full CRUD functionality in Users, Groups and Memberships.
The LDAP Identity Service
The LDAP identity service provides read-only access to an LDAP-based user/group repository. The identity service provider is implemented as a Process Engine Plugin and can be added to the process engine configuration. In that case it replaces the default database identity service.
To use the LDAP identity service, the camunda-identity-ldap.jar library has to be added to the classloader of the process engine.
Please import the CIB seven BOM to ensure correct versions for every CIB seven project.
<dependency>
<groupId>org.cibseven.bpm.identity</groupId>
<artifactId>cibseven-identity-ldap</artifactId>
</dependency>
Activate the LDAP Plugin
The following is an example of how to configure the LDAP Identity Provider Plugin using Spring XML:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration" class="org.cibseven.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
...
<property name="processEnginePlugins">
<list>
<ref bean="ldapIdentityProviderPlugin" />
</list>
</property>
</bean>
<bean id="ldapIdentityProviderPlugin" class="org.cibseven.bpm.identity.impl.ldap.plugin.LdapIdentityProviderPlugin">
<property name="serverUrl" value="ldap://localhost:3433/" />
<property name="managerDn" value="uid=daniel,ou=office-berlin,o=camunda,c=org" />
<property name="managerPassword" value="daniel" />
<property name="baseDn" value="o=camunda,c=org" />
<property name="userSearchBase" value="" />
<property name="userSearchFilter" value="(objectclass=person)" />
<property name="userIdAttribute" value="uid" />
<property name="userClass" value="person" />
<property name="userFirstnameAttribute" value="cn" />
<property name="userLastnameAttribute" value="sn" />
<property name="userEmailAttribute" value="mail" />
<property name="userPasswordAttribute" value="userpassword" />
<property name="groupSearchBase" value="" />
<property name="groupSearchFilter" value="(objectclass=groupOfNames)" />
<property name="groupIdAttribute" value="ou" />
<property name="groupNameAttribute" value="cn" />
<property name="groupMemberAttribute" value="member" />
<property name="authorizationCheckEnabled" value="false" />
<!-- Optional LDAP cache, disabled by default -->
<property name="cacheEnabled" value="false" />
<property name="cacheUserQueriesTtlSeconds" value="30" />
<property name="cacheUserQueriesMaxWeight" value="20000" />
<property name="cacheGroupTtlSeconds" value="120" />
<property name="cacheGroupMaxWeight" value="8000" />
<property name="cacheStatsLogEnabled" value="false" />
<property name="cacheStatsLogInterval" value="1000" />
</bean>
</beans>
The following is an example of how to configure the LDAP Identity Provider Plugin in bpm-platform.xml/processes.xml:
<process-engine name="default">
<job-acquisition>default</job-acquisition>
<configuration>org.cibseven.bpm.engine.impl.cfg.StandaloneProcessEngineConfiguration</configuration>
<datasource>java:jdbc/ProcessEngine</datasource>
<properties>...</properties>
<plugins>
<plugin>
<class>org.cibseven.bpm.identity.impl.ldap.plugin.LdapIdentityProviderPlugin</class>
<properties>
<property name="serverUrl">ldap://localhost:4334/</property>
<property name="managerDn">uid=jonny,ou=office-berlin,o=camunda,c=org</property>
<property name="managerPassword">s3cr3t</property>
<property name="baseDn">o=camunda,c=org</property>
<property name="userSearchBase"></property>
<property name="userSearchFilter">(objectclass=person)</property>
<property name="userIdAttribute">uid</property>
<property name="userClass">person</property>
<property name="userFirstnameAttribute">cn</property>
<property name="userLastnameAttribute">sn</property>
<property name="userEmailAttribute">mail</property>
<property name="userPasswordAttribute">userpassword</property>
<property name="groupSearchBase"></property>
<property name="groupSearchFilter">(objectclass=groupOfNames)</property>
<property name="groupIdAttribute">ou</property>
<property name="groupNameAttribute">cn</property>
<property name="groupMemberAttribute">member</property>
<property name="authorizationCheckEnabled">false</property>
<!-- Optional LDAP cache, disabled by default -->
<property name="cacheEnabled">false</property>
<property name="cacheUserQueriesTtlSeconds">30</property>
<property name="cacheUserQueriesMaxWeight">20000</property>
<property name="cacheGroupTtlSeconds">120</property>
<property name="cacheGroupMaxWeight">8000</property>
<property name="cacheStatsLogEnabled">false</property>
<property name="cacheStatsLogInterval">1000</property>
</properties>
</plugin>
</plugins>
</process-engine>
Administrator Authorization Plugin
The LDAP Identity Provider Plugin is usually used in combination with the Administrator Authorization Plugin which allows you to grant administrator authorizations for a particular LDAP User/Group.
Multi-Tenancy
Currently, the LDPA Identity Service doesn’t support multi-tenancy. That means it is not possible to get tenants from LDAP and the transparent multi-tenancy access restrictions don’t work by default.
Configuration Properties of the LDAP Plugin
The LDAP Identity Provider provides the following configuration properties:
| Property | Description |
|---|---|
serverUrl |
The url of the LDAP server to connect to. |
managerDn |
The absolute DN of the manager user of the LDAP directory. |
managerPassword |
The password of the manager user of the LDAP directory |
baseDn |
The base DN: Identifies the root of the LDAP directory. Is appended to all DN names composed for searching for users or groups. Example: |
userSearchBase |
Identifies the node in the LDAP tree under which the plugin should search for users. Must be relative to Example: |
userSearchFilter |
LDAP query string used when searching for users. Example: |
userIdAttribute |
Name of the user Id property. Example: |
userClass |
LDAP attribute when searching for users. Example: |
userFirstnameAttribute |
Name of the firstname property. Example: |
userLastnameAttribute |
Name of the lastname property. Example: |
userEmailAttribute |
Name of the email property. Example: |
userPasswordAttribute |
Name of the password property. Example: |
groupSearchBase |
Identifies the node in the LDAP tree under which the plugin should search for groups. Must be relative to Example: |
groupSearchFilter |
LDAP query string used when searching for groups. Example: |
groupIdAttribute |
Name of the group Id property. Example: |
groupNameAttribute |
Name of the group Name property. Example: |
groupTypeAttribute |
Name of the group Type property. Example: |
groupMemberAttribute |
Name of the member attribute. Example: |
acceptUntrustedCertificates |
Accept of untrusted certificates if LDAP server uses SSL. Warning: We strongly advise against using this property. Better install untrusted certificates to JDK key store. |
useSsl |
Set to true if LDAP connection uses SSL. Default: |
initialContextFactory |
Value for the |
securityAuthentication |
Value for the |
usePosixGroups |
Indicates whether posix groups are used. If true, the connector will use a simple
(unqualified) user id when querying for groups by group member instead of the full DN.
Default: |
allowAnonymousLogin |
Allows to login anonymously without a password. Default: Warning: We strongly advise against using this property. You should configure your LDAP to use simple authentication without anonymous login. |
authorizationCheckEnabled |
If this property is set to
Note: If you have a huge amount of LDAP users or groups we advise to set this property to |
sortControlSupported |
If this property is set to Note: The support of search result ordering is not be implemented by every LDAP server. Make sure that your currently used LDAP Server implements the RFC 2891. |
pageSize |
When you define a number higher or equal to 1, pagination is enabled, and results are loaded page per page. Therefore, the query sent to the LDAP Server expects support for the LDAPv3 Control for paged results as defined in RFC 2696. Note:
|
passwordCheckCatchAuthenticationException |
When a login attempt fails with an |
cacheEnabled |
Enables LDAP query result caching. Default: |
cacheUserQueriesTtlSeconds |
Time to live in seconds for cached user-query results (for high-cardinality, rarely-repeated user searches). Default: |
cacheUserQueriesMaxWeight |
Maximum total cache weight for user-query results. Each entry weight equals the size of its result list (minimum 1), so this limits cached users rather than distinct queries. Default: |
cacheGroupTtlSeconds |
Time to live in seconds for cached group lookup results (for low-cardinality, frequently-repeated group lookups). Default: |
cacheGroupMaxWeight |
Maximum total cache weight for group lookup results. Each entry weight equals the size of its result list (minimum 1), so this limits cached groups rather than distinct queries. Default: |
cacheStatsLogEnabled |
Enables periodic INFO logging of cache hit/miss statistics for debugging purposes. Default: |
cacheStatsLogInterval |
Defines how often (in cache lookups) the cache statistics summary is logged when |
Performance of the LDAP Plugin
Every user and group lookup of the LDAP identity service is a live search against the directory server – the plugin keeps no local copy of users and groups. Two things therefore dominate the response time of the web applications and of every authorization check: how much of the directory a single query has to touch, and whether results are cached.
Keep the user and group search narrow
If userSearchBase/groupSearchBase point at the root of the directory and the search filters only restrict the object class, every query scans the whole directory. This happens on each login, on each page render that resolves user names, and for each authorization check.
Restrict both the searched subtree and the filter to the entries CIB seven actually needs:
<property name="groupSearchBase">ou=cibseven,ou=roles</property>
<property name="groupSearchFilter">(&(objectclass=groupOfNames)(cn=cibseven-*))</property>
Note that & is the XML escape for the LDAP AND operator & – written as a plain &, the configuration file would not be valid XML.
groupSearchFilter is combined with an AND into every group query, including the “which groups does this user belong to” lookup that runs on login. A user who is a member of several hundred directory groups then only yields the CIB seven ones, instead of all of them being fetched, transformed and authorization-checked. The same applies to userSearchBase and userSearchFilter.
Fewer groups per user also make the engine’s own authorization checks cheaper, because every group of the authenticated user ends up in the database query performing the check. See Identity Provider.
Two further properties matter here: pageSize is mandatory if your LDAP server refuses to serve unbounded result sets, and authorizationCheckEnabled can be set to false to skip the per-result authorization check on large directories.
Caching
Caching is disabled by default. With cacheEnabled set to true, the plugin keeps LDAP query results in memory, in two independently sized cache groups:
| Cache group | Caches | Properties (defaults) |
|---|---|---|
| User queries | Searches by id, name or email. Many distinct keys, each rarely repeated – sized large, expires quickly. | cacheUserQueriesTtlSeconds (30)cacheUserQueriesMaxWeight (20000) |
| Group lookups | Group queries and the members of a group. Few distinct keys, hit repeatedly by page renders and authorization checks – sized small, kept longer. | cacheGroupTtlSeconds (120)cacheGroupMaxWeight (8000) |
How it works:
- Each entry expires individually once its TTL has passed since it was written. There is no background refresh – the first query after expiry hits LDAP again.
- The caches are bounded by weight, not by entry count. An entry weighs as many units as its result list has elements (an empty result counts as 1).
maxWeighttherefore limits how many users or groups stay resident, so one broad query returning thousands of users cannot exhaust the heap. - Passwords are never cached.
checkPasswordalways authenticates against LDAP. - The caches live in the memory of the process engine. In a cluster, every node has its own.
Choosing the parameters:
- The TTL is your staleness window: a user or a membership changed in LDAP becomes visible after at most TTL seconds. Shorten it for directories that change often.
- Raise
cacheGroupTtlSecondsfirst. Group membership drives the authorization checks, is queried constantly and usually changes rarely. - Size
maxWeightby the number of user and group objects you want to keep resident, not by the number of queries you expect. - Paginated results are cached per page. If entries are added, removed or reordered in LDAP between two page fetches, the pages can skew. Keep the TTL short if exact consistency across pages matters.
- To validate a setting, switch on
cacheStatsLogEnabled. Hit/miss statistics are then logged atINFOeverycacheStatsLogIntervallookups. Increase TTL and weight as long as the hit ratio still improves.
The OAuth2 Identity Service
See the Spring Security OAuth2 Integration’s OAuth2 Identity Provider documentation.
The SCIM2 Identity Service
The SCIM2 identity service provides access to a SCIM 2.0 compliant user and group repository. It is implemented as a Process Engine Plugin and can replace the default database identity service.
The SCIM2 identity service is primarily read-oriented and is intended for integrating CIB seven with external SCIM 2.0 compliant providers.
To use the SCIM2 identity service, add the cibseven-identity-scim library to the process engine classpath.
Activate the SCIM2 Plugin
The following is an example of how to configure the SCIM2 Identity Provider Plugin in bpm-platform.xml for Tomcat:
<process-engine name="default">
<job-acquisition>default</job-acquisition>
<configuration>org.cibseven.bpm.engine.impl.cfg.StandaloneProcessEngineConfiguration</configuration>
<datasource>java:jdbc/ProcessEngine</datasource>
<plugins>
<plugin>
<class>org.cibseven.bpm.identity.impl.scim.plugin.ScimIdentityProviderPlugin</class>
<properties>
<property name="serverUrl">https://scim.example.com</property>
<property name="authenticationType">oauth2</property>
<property name="oauth2TokenUrl">https://auth.example.com/oauth/token</property>
<property name="oauth2ClientId">your-client-id</property>
<property name="oauth2ClientSecret">your-client-secret</property>
<property name="verbose">true</property>
</properties>
</plugin>
</plugins>
</process-engine>
The plugin also supports basic authentication and OAuth2 client credentials. For production use, keep SSL/TLS enabled and configure the authentication method that fits your SCIM server.
SCIM2 Plugin Configuration Properties
The SCIM2 Identity Provider Plugin provides the following configuration properties:
| Property | Description |
|---|---|
serverUrl |
The base URL of the SCIM server. |
authenticationType |
The authentication type used for the SCIM connection: bearer, basic, or oauth2. |
bearerToken |
The bearer token used when authenticationType is set to bearer. |
username |
The username used when authenticationType is set to basic. |
password |
The password used when authenticationType is set to basic. |
oauth2TokenUrl |
The OAuth2 token endpoint URL used when authenticationType is set to oauth2. |
oauth2ClientId |
The OAuth2 client ID. |
oauth2ClientSecret |
The OAuth2 client secret. |
userAuthenticationEnabled |
Enables user authentication via SCIM or OIDC. The default value is false. |
userIdAttribute |
The SCIM attribute used as the user ID. |
userFirstnameAttribute |
The SCIM attribute used as the user first name. |
userLastnameAttribute |
The SCIM attribute used as the user last name. |
userEmailAttribute |
The SCIM attribute used as the user email address. |
groupIdAttribute |
The SCIM attribute used as the group ID. |
groupNameAttribute |
The SCIM attribute used as the group name. |
groupMemberAttribute |
The SCIM attribute used to resolve group members. |
acceptUntrustedCertificates |
Accepts self-signed certificates. This is not recommended for production. |
useSsl |
Enables SSL/TLS for the SCIM connection. The default value is true. |
authorizationCheckEnabled |
Enables authorization checks when querying users or groups. The default value is true. |
pageSize |
The number of results to load per page. The default value is 100. |
Additional Notes
The plugin supports user and group queries, pagination, and configurable attribute mappings. Basic user and group management is intended for use in test environments only. In production, manage users and groups in the SCIM server itself.
Throttle login attempts
A mechanism exists for preventing subsequent unsuccessful login attempts.The essence of it is that the user is not able to log in for a specific amount of time after unsuccessful login attempts. The amount of time is calculated after each attempt but it is limited by maximum delay time. After a predefined number of unsuccessful attempts, the user will be locked and only an administrator has permissions to unlock them.
The mechanism is configurable with the following properties and respective default values.
loginMaxAttempts=10loginDelayFactor=2loginDelayMaxTime=60loginDelayBase=3
For more information, please check the process engine’s login properties section.
Calculation of the delay is done via the formula: baseTime * factor^(attempt-1).
The behaviour with the default configuration will be:
3 seconds delay after the first unsuccessful attempt, 6 seconds after the 2nd attempt, 12 seconds, 24 seconds, 48 seconds, 60 seconds, 60 seconds, etc. After the 10th attempt, if the user fails to login again, the user will be locked.
LDAP specifics
If you have a LDAP setup on your engine, you need to handle the throttling on the LDAP side. The login mechanism in your system will not be affected by the above properties.