This section summarizes the configuration issues when integrating Stardust into an existing security infrastructure. For an in-depth discussion of the underlying concepts, see the Programming Guide.
Note: Server side properties described in the configurations below are meant to be set in the server side carnot.properties. Client side properties have to be set in the client side carnot.properties.
Authentication can be done in one of the following modes:
The following table summarizes the different authentication options.
| Custom Registry | Spring Local Mode | Client Bean Factory | |
|---|---|---|---|
| Internal Login | no | yes | no |
| Implicit Login | yes | no | yes |
| JAAS Login | yes | yes | no |
Authorization in Stardust, i.e. the assignment of participants (roles/organizations) to users is normally stored in the audit trail. If an external user registry is used the authorization information has to be replicated from the external registry every time a login is done. This role mapping logic has to be implemented by providing an implementation of the
org.eclipse.stardust.engine.core.spi.security.DynamicParticipantSynchronizationProvider
interface. The details for implementing a synchronization provider can be found in the Programming Guide.
Internal authentication mode is turned on by default when no security related properties are explicitly set. It always uses the audit trail database as authentication and authorization source. You can document the use of internal authentication explicitly by setting the following property on the server:
Security.Authentication.Mode = internal
The following table summarizes other server side configuration options for internal authentication:
| Property | Range/Default Value | Remarks |
|---|---|---|
| Security.Authentication.Mode | String / internal | internal authentication mode |
| Security.Authentication.MaximumNumberLoginRetries | integer / 3 | A re-login try threshold. If exceeded the account is temporarily disabled |
| Security.Authentication.InvalidationTimeInMinutes | integer / 1 min | The time an account is disabled after unsuccessful login |
Please note that in case you like to perform a stateless deployment for internal authentication you have to adjust some settings in your deployment descriptor. Please refer to the section Stateless Bean Deployment for Internal Authentication of the chapter Deploying Stardust Components to an EJB Application Server in the Deployment Guide for detailed information.
Implicit authentication is turned on by setting the following server side property:
Security.Authentication.Mode = principal.
If you use an external user registry you also have to configure participant synchronization (see below).
Configuring a Stardust Java client for implicit authentication means specifying the secure session factory and the credential provider to be used. The Secure.Session.Factory client side property should contain the name of a class implementing the org.eclipse.stardust.engine.api.ejb2.SecureSessionFactory interface, while correspondingly the Credential.Provider property must contain the name of a class extending the org.eclipse.stardust.engine.api.runtime.CredentialProvider class.
Also, you have to provide the necessary JAAS configuration file. The content of the configuration file must be conforming to the specifications of the application server used. The configuration file should be specified according to the JAAS standards, either in the client JVM security properties, placed in the user home path or by explicitly providing the configuration file path in the JVM system property java.security.auth.login.config.
By default, the security configuration is named carnot. If necessary, you can specify another security configuration by providing the corresponding name in the Security.Authentication.ConfigurationName client side property.
Stardust provides security examples with source code for example implementations. Refer to the Examples section for details.
For a WebLogic authentication example, download the following zip file:
This example provides a secure session factory for WebLogic, that you can use by setting the property Secure.Session.Factory in your carnot.properties file:
Secure.Session.Factory = org.eclipse.stardust.examples.authentication.weblogic.WeblogicSecureSessionFactory
For a WebSphere authentication example, download the following zip file:
This example provides a secure session factory and a credential provider for WebSphere, that you can use by setting the properties Secure.Session.Factory and Credential.Provider in your carnot.properties file:
Credential.Provider = org.eclipse.stardust.examples.authentication.websphere.WASCredentialProvider Secure.Session.Factory = org.eclipse.stardust.examples.authentication.websphere.WASSecureSessionFactory
No Stardust specific configuration has to be done because the principal association is a matter of the servlet container setup.
Server side JAAS Authentication is set by:
Security.Authentication.Mode = jaas
Additionally, you have to provide the following properties:
| Property | Range / Default Value | Remarks |
|---|---|---|
| Security.Authentication. ConfigurationName |
String / - | The JAAS login configuration name |
| Security.Authentication.PrincipalClass | String / - | The class name of the principal to use from the returned JAAS Subject |
You also have to set up a login configuration in the server configuration itself. Please refer to your application server security documentation for detailed information on how to do this. Note, that the exact method of authentication tried depends on the credentials present in the JAAS subject and the JAAS configuration set by the application.
The JAAS authentication mode is transparent to the client. No configuration is necessary.
Participant synchronization has to be done if authentication is done against an authentication source different from the audit trail database. The Stardust Process Engine then has to synchronize the participant mappings at login time. The configuration to be provided is the name of the SynchronizationProvider to use, and probably provider specific settings:
Security.Authorization.SynchronizationProvider = classname
To control the frequency of participant synchronization, Stardust evaluates the property:
Security.Authorization.SynchronizationStrategy = classname
The strategy implementation has to be an implementation of the interface:
org.eclipse.stardust.engine.core.spi.security.DynamicParticipantSynchronizationStrategy
By implementing this interface it is possible to tell the engine if a specific dynamic participant's external representation is likely to have been, thus requiring a new synchronization operation. By default the class:
org.eclipse.stardust.engine.core.spi.security.TimebasedSynchronizationStrategy
is used, which itself by default synchronizes any participant only every 10 seconds. This delay may be configured by setting the properties:
Security.Authorization.TimebasedSynchronizationStrategy.UserSyncTimeout
and
Security.Authorization.TimebasedSynchronizationStrategy.UserGroupSyncTimeout
to the desired number of seconds.
If you want to invalidate a user or usergroup, which does not exist in external registry, you can set the following property:
Security.Authorization.InvalidateNonexistingParticipants
The validTo property of the non-existing user or usergroup will then be set to current date.
To enable tracing for user or usergroup synchronization with external registry evaluate the following property:
Security.Authorization.TraceSynchronization
Participant synchronization is transparent to Stardust clients. It only has to be configured on the server side.
The LDAP synchronization example located in the examples/ldap-sync directory is maybe useful to you if you have to synchronize against an LDAP repository and if you can express the user-to-participant mapping by an LDAP search filter.
This provider can be configured using the following properties:
| Property | Range/ Default Value |
Remarks |
|---|---|---|
| LDAPSynchronization.ServerName | Hostname / - | The host name of the LDAP server to connect |
| LDAPSynchronization.ServerPort | Port number / 389 | The port number to connect |
| LDAPSynchronization.RootDN | LDAP distinguished name | The distinguished name where all operations are relative to |
| LDAPSynchronization.BindMode | 'anonymous' or 'dedicated' /'anonymous' | Flag indicating whether to connect anonymously |
| LDAPSynchronization.BindUserDN | String | User DN to use for connecting if bind mode is dedicated |
| LDAPSynchronization.BindPassword | String | Password to use for connecting if bind mode is dedicated |
| LDAPSynchronization.SearchTimeLimit | Integer / 0 (unlimited) |
The time limit for searches in milliseconds |
| LDAPSynchronization.UserFilter | LDAP search filter | The search filter to get user information for a principal name. The wildcard %v is used to include the principal name. |
| LDAPSynchronization.ParticipantFilter | LDAP search filter | The search filter to get the participants for a principal name. The wildcard %v is used to include the principal name. |
| LDAPSynchronization. ParticipantNamingAttribute |
LDAP attribute name/'cn' | The attribute name for getting the Stardust participant ID from a found participant |
As an example here is a configuration which:
Security.Authorization.SynchronizationProvider = org.eclipse.stardust.examples.authorization.ldap.LDAPSynchronizationProvider
LDAPSynchronization.ServerName=ldap.de.carnot.ag LDAPSynchronization.RootDN=dc=de,dc=carnot,dc=ag,dc=test LDAPSynchronization.UserFilter="(&(uid=%v)(objectclass=inetOrgPerson)) LDAPSynchronization.ParticipantFilter=(&(objectClass=groupOfUniqueNames)(uniqueMember=uid=%v*))
If you want to enforce Java 2 Security in your application server you have to relax somehow the permissions mandated in the J2EE specification to allow access to Stardust resources. Also, Stardust uses advanced Java reflection you have to permit.
Here are the permissions you have to set to operate CANROT:
java.io.FilePermission "carnot-engine.jar" "read";
to read resources from the Stardust jar:
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
permission java.lang.RuntimePermission "accessDeclaredMembers";
to allow advanced Java reflection.
Dependent on the JAXP implementation your application server is using you may need additional permissions, like
permission:
java.io.FilePermission "xalan.jar", "read";
If you intend to use Stardust mail functionality (notifications or triggers) you also have to relax the permissions to get access to JDK specific mail resources.
The following table shows the service operations provided by Stardust depending on the model element and the permission to be used:
| Model Element | Permission/Default Participant | Service Operations concerned |
|---|---|---|
| Model | Deploy and Modify Process Model/Administrator | AdministrationService.deployModel AdministrationService.modifyModel AdministrationService.overwriteModel |
| Model | Modify Audit Trail Content/Administrator | AdministrationService.cleanupRuntime AdministrationService.cleanupRuntimeAndModels |
| Model | Run Recovery/Administrator | AdministrationService.recoverProcessInstances AdministrationService.recoverRuntimeEnvironment |
| Model | Manage Daemons/Administrator | AdministrationService.getDaemon AdministrationService.startDaemon AdministrationService.stopDaemon |
| Model | Control process engine/Administrator | AdministrationService.flushCashes |
| Model | Obtain Audit Trail Statistics/Administrator | AdministrationService.getAuditTrailHealthReport QueryService.getLogEntriesCount(LogEntryQuery query) QueryService.findFirstLogEntry(LogEntryQuery query) QueryService.getAllLogEntries(LogEntryQuery query) |
| Model | Obtain User Data/Administrator | QueryService.getAllUserGroups(UserGroupQuery query) QueryService.getAllUsers(UserQuery query) QueryService.getUserGroupsCount(UserGroupQuery query) QueryService.getUsersCount(UserQuery query) QueryService.findFirstUser(UserQuery query) QueryService.findFirstUserGroup(UserGroupQuery query) UserService.getUser(String account) UserService.getUser(String realm, String account) UserService.getUser(long userOID) UserService.getUserGroup(String id) UserService.getUserGroup(long oid) UserService.getUserRealms() |
| Model | Modify User Data/Administrator |
UserService.modifyUser(User user) UserService.createUser(String account, String firstName, String lastName, String description, String password, String eMail, Date validFrom, Date validTo) UserService.createUser(String realm, String account, String firstName, String lastName, String description, String password, String eMail, Date validFrom, Date validTo) UserService.invalidateUser(String account) UserService.invalidateUser(String realm, String account) UserService.createUserGroup(String id, String name, String description, Date validFrom, Date validTo) UserService.modifyUserGroup(UserGroup userGroup) UserService.invalidateUserGroup(String id) UserService.invalidateUserGroup(long oid) UserService.createUserRealm(String id, String name, String description) UserService.dropUserRealm(String id) |
| Model | Obtain Model Data/All | QueryService.getProcessDefinition(long modelOID, String id) QueryService.getProcessDefinition(String id) QueryService.getModel(long modelOID) QueryService.getModel(long modelOID, boolean computeAliveness) QueryService.getModels(DeployedModelQuery query) QueryService.getModelAsXML(long modelOID) QueryService.getModelDescription(long modelOID) QueryService.getActiveModel() (deprecated) QueryService.getActiveModelDescription() QueryService.getAllProcessDefinitions() QueryService.getAllProcessDefinitions(long modelOID) QueryService.getAllAliveModelDescriptions() QueryService.getAllParticipants() QueryService.getAllParticipants(long modelOID) QueryService.getParticipant(long modelOID, String id) QueryService.getAllModelDescriptions() QueryService.wasRedeployed(long modelOid, int revision) QueryService.getParticipant(String id) |
| Model | Read Departments | AdministrationService.getDepartment(long oid) |
| Model | Modify Departments | AdministrationService.createDepartment(String id, String name, String description, DepartmentInfo parent, OrganizationInfo organization) AdministrationService.modifyDepartment(long oid, String name, String description) AdministrationService.removeDepartment(long oid) |
| Process Definition | Start Process/Implicitly via manual trigger | WorkflowService.startProcess(String id, Map data, boolean synchronously) |
| Process Definition | Abort Process Instances/Administrator | AdministrationService.abortProcessInstance WorkflowService.abortProcessInstance(long processInstanceOID) |
| Process Definition | Delete Process Instances/Administrator | AdministrationService.deleteProcesses |
| Process Definition | Read Process Instance Data/Administrator | QueryService.getAllProcessInstances(ProcessInstanceQuery query) QueryService.findFirstProcessInstance(ProcessInstanceQuery query) QueryService.getProcessInstancesCount(ProcessInstanceQuery query) |
| Process Definition | Manage Event Handlers/Administrator | WorkflowService.getProcessInstanceEventHandler(long processInstanceOID,
String handler) WorkflowService.bindProcessEventHandler(long processInstanceOID, EventHandlerBinding eventHandler) WorkflowService.bindProcessEventHandler(long processInstanceOID, String handler) WorkflowService.unbindProcessEventHandler(long processInstanceOID, String handler) |
| Data | Read Data Values/All | |
| Activity | Perform Activity Permission/Implicitly via performer assignment | WorkflowService.getWorklist(WorklistQuery query) WorkflowService.getActivityInstance(long activityInstanceOID) WorkflowService.abortActivityInstance(long activityInstanceOID) WorkflowService.abortActivityInstance(long activityInstanceOid, AbortScope abortScope) WorkflowService.activate(long activityInstanceOID) WorkflowService.activateAndComplete(long activityInstanceOID, String context, Map outData) WorkflowService.activateAndComplete(long activityInstanceOID, String context, Map outData, int flags) WorkflowService.activateNextActivityInstance(long activityInstanceOID) WorkflowService.activateNextActivityInstanceForProcessInstance(long processInstanceOID) WorkflowService.complete(long activityInstanceOID, String context, Map outData) WorkflowService.complete(long activityInstanceOID, String context, Map outData, int flags) WorkflowService.hibernate(long activityInstanceOID) WorkflowService.suspendToUser(long activityInstanceOID) |
| Activity | Delegation to other users | WorkflowService.delegateToDefaultPerformer(long activityInstanceOID) WorkflowService.delegateToParticipant(long activityInstanceOID, String performer) WorkflowService.delegateToParticipant(long activityInstanceOID, ParticipantInfo participant) WorkflowService.delegateToUser(long activityInstanceOID, long userOID) WorkflowService.suspendToDefaultPerformer(long activityInstanceOID) WorkflowService.suspendToDefaultPerformer(long activityInstanceOID, String context, Map outData) WorkflowService.suspendToParticipant(long activityInstanceOID, String participant) WorkflowService.suspendToParticipant(long activityInstanceOID, String participant, String context, Map outData) WorkflowService.suspendToParticipant(long activityInstanceOID, ParticipantInfo participant, ContextData outData) WorkflowService.hibernate(long activityInstanceOID) WorkflowService.suspend(long activityInstanceOID, ContextData outData) WorkflowService.suspendToUser(long activityInstanceOID, long userOID) WorkflowService.suspendToUser(long activityInstanceOID, long userOID, String context, Map outData) WorkflowService.suspendToUser(long activityInstanceOID, String context, Map outData) |
| Activity | Manage Event Handlers/Administrator | WorkflowService.getActivityInstanceEventHandler(long activityInstanceOID,
String handler) WorkflowService.bindActivityEventHandler(long activityInstanceOID, EventHandlerBinding eventHandler) WorkflowService.bindActivityEventHandler(long activityInstanceOID, String handler) WorkflowService.unbindActivityEventHandler(long activityInstanceOID, String handler) |
| Activity | Read Activity Instance Data/All | QueryService.findFirstActivityInstance(ActivityInstanceQuery query) QueryService.getAllActivityInstances(ActivityInstanceQuery query) QueryService.getActivityInstancesCount(ActivityInstanceQuery query) QueryService.getAuditTrail(long processInstanceOID) |
For a detailed description on the permissions for specific services, refer to chapter Declarative Security Usage in Stardust Services API in the Programming Guide.
The grant OWNER is either the user, the user group, or the model participant that is currently assigned as performer of an activity instance. The following methods of the WorkflowService are restricted to the OWNER by the means of the activity.performActivity permission, which is fixed and cannot be changed by the modeler:
If the current user does not qualify as an OWNER of the activity instance, an AccessForbiddenException will be thrown.
The following two methods require the current user to become the OWNER of the next activity instance:
If that is not possible, because the permission is denied, a value of null is returned and no authorization specific exception will be thrown.
The method AdministrationService.forceCompletion is restricted to the Administrator by the means of the activity.performActivity permission, which is fixed and cannot be changed by the modeler.
If the current user does not qualify as an Administrator, an AccessForbiddenException will be thrown.
The following service methods can be executed without permission: