When our Oracle Adaptive Case Management project started we initially used the default permissions on the case (Public, Restricted) to make sure our activities where available to the correct BPM application roles. A complex authorization model of roles, with LDAP groups, with users to allow access to the activities, but also custom UI and human tasks.
An important concept of knowledge worker automation (on which off course our whole case is based) is that the users should not be locked into rigid BPM processes (and access constraints I would like to add) which the IT department came up with. So activities on one hand would be allowed access to by all internal knowledge workers anyway, because: “hey .. they are knowledge workers and know best, right ?”
The first exception
However for some exceptions we got the requirements to only allow a specific role to a specific activity. So what we did was adding a new permission for that role and made sure that the activity was only available for that role.
And all was good, for a while …
This went pretty well for some time, until we ran into a new requirements which made us rethink our design:
- We had the requirement that on a specific activity where currently only permRoleSeniorEmployee had access now, we had to add the role Medior Employee. Therefor the original design thought that all activities are available for all employees OR for just 1 specific role (senior) for quality assurance was no longer valid.
So we looked at our options :
- We allowed the application role Medior to the permRoleSenior permission for a quick win for now, but looking at our naming convention this would be a bit confusing in the long run. All other options below required a code change, build and deploy so we tried to be smart to prevent this from ever happening again.
- The activity sadly doesn’t have a multi-select (both 11g and 12.2.1) so it is not possible to select both permRoleSenior and permRoleMedior
- We could add a new permission like permRoleMediorAndSenior, but still limiting ourselves to the code base
- In future identical requirements we do not want to change the codebase of our ACM project and permissions should be able to change on runtime. So both option 2 and 3 are not smart in the long run.
Our “Best Practice”
We have long running cases (like, really long) and redeployment of a new version will not fix any new permissions requirements on running instances. However since we have 50+ activities in our case where most of them are (currently) allowed access to by all employee levels (the example here just uses 2, but in reality we have much more roles). So the idea of creating a separate permission for each activity was not appealing, we eventually decided that we just had to. So for each activity we created a unique permission and configured in on the activity.
Because know we have a LOT of permissions and roles we are gratefull for having a WLST script to make sure these are automatically configured through our environments. Scripts have some customization, but the main logic was found on the big WWW (sorry, not sure where and who to give credits).
So first we need a property file
permission.total=2 # permActMyProcess2 permission.1.appstripe=OracleBPMProcessRolesApp permission.1.principalclass=oracle.security.jps.service.policystore.ApplicationRole permission.1.principalname=RubixCasus_1.0.MediorEmployee permission.1.permclass=oracle.bpm.casemgmt.permission.CasePermission permission.1.permtarget=RubixCasus_1.0.PERMACTMYPROCESS2.ACTIVITY permission.1.permactions=INVOKE permission.2.appstripe=OracleBPMProcessRolesApp permission.2.principalclass=oracle.security.jps.service.policystore.ApplicationRole permission.2.principalname=RubixCasus_1.0.SeniorEmployee permission.2.permclass=oracle.bpm.casemgmt.permission.CasePermission permission.2.permtarget=RubixCasus_1.0.PERMACTMYPROCESS2.ACTIVITY permission.2.permactions=INVOKE
And the WLST script
from java.util import Properties from java.io import FileInputStream from java.io import File from oracle.security.jps.mas.mgmt.jmx.policy import PortablePrincipal from oracle.security.jps.mas.mgmt.jmx.policy import PortablePermission from oracle.security.jps.mas.mgmt.jmx.policy.PortablePrincipal import PrincipalType import os, sys PROPERTIES = sys.argv propInputStream = FileInputStream(PROPERTIES) configProps = Properties() configProps.load(propInputStream) propInputStream.close() pmTotal=configProps.get("permission.total") print '... property permission.total:',pmTotal connect('weblogic', 'welcome1', 't3://myserver:7001') print '=============================' print 'Granting permissions...' print '=============================' print '... property permission.total:',pmTotal i=1 while (i <= int(pmTotal)) : pmAppStripe=configProps.get("permission."+str(i)+".appstripe") pmPrincipalClass=configProps.get("permission."+str(i)+".principalclass") pmPrincipalName=configProps.get("permission."+str(i)+".principalname") pmPermClass=configProps.get("permission."+str(i)+".permclass") pmPermTarget=configProps.get("permission."+str(i)+".permtarget") pmPermActions=configProps.get("permission."+str(i)+".permactions") domainRuntime() jpsBean = ObjectName('com.oracle.jps:type=JpsApplicationPolicyStore') print 'INFO - Index:',str(i),'| Name:',pmPrincipalName,'| Target:',pmPermTarget,' |Action:',pmPermActions principal = PortablePrincipal(pmPrincipalClass, pmPrincipalName,PrincipalType.CUSTOM) params = [pmAppStripe, principal.toCompositeData(None)] sign = ["java.lang.String", "javax.management.openmbean.CompositeData"] perms = mbs.invoke(jpsBean, "getPermissions", params, sign) permExists = false for perm in perms: p = PortablePermission.from(perm) if(p.target==pmPermTarget and p.permissionClassName==pmPermClass and pmPermActions in p.actions): permExists = true print 'INFO - Permission',pmPermTarget,'(',pmPermActions,') already set for ',pmPrincipalName break if(permExists==false): try: grantPermission(appStripe=''+pmAppStripe,principalClass=''+pmPrincipalClass,principalName=''+pmPrincipalName, permClass=''+pmPermClass, permTarget=''+pmPermTarget,permActions=''+pmPermActions) print 'INFO - Permission',pmPermTarget,'(',pmPermActions,') set for ',pmPrincipalName except: print 'ERROR - Failed adding permission ',pmPermTarget,'(',pmPermActions,') to',pmPrincipalName dumpStack() print sys.exc_info() os._exit(1) i = i + 1
The longer we thought about this the more we think the current permission solution lacks some maintainability. It would (for instance) be nice if the BPM WorkSpace would allow some graphical interface where all activities could be easily connected to the (already their) BPM Application Roles. So hopefully in the near future ?