November 10, 2021
The Maximo security model provides a robust set of options for defining and refining security restrictions. However, I have encountered several projects where the security rules involve complicated logic and trying to implement these with conditional expressions and data restrictions becomes unwieldy and difficult to manage. In these cases Automation Scripts may be used to implement granular security restrictions with complex logic.
In this post we will discuss the mechanisms and best practices for securing Maximo business objects in automation scripts.
For this post we are going to explore two use cases: The first is making an attribute read-only and the second is hiding an attribute.
Setting an attribute to be read only is as simple as using the setFieldFlag
method on Mbo with the name of the attribute, the MboConstants.READONLY
constant, and a true
value.
For the example below and in the rest of this post, we are going to assume that the Automation Script has an Object launch point and that it is configured for the WORKORDER
object and the Initialize Value
event.
To start we are going to make the WORKTYPE
attribute read only.
MboConstants = Java.type("psdi.mbo.MboConstants");mbo.setFieldFlag("WORKTYPE", MboConstants.READONLY, true);
If we want to make the Work Type Textbox in the Work Order Tracking application screen not visible, we first need to identify its Control ID
value. Open the Application Designer application then search for the WOTRACK
application. Select the Work Type Textbox within the screen designer and then select the Properties for the Textbox. In the field labeled Control ID
node the value. The screenshot below shows that the ID for the Work Type Textbox is main_grid3_7
.
With the control ID available, we can now use that to get the ControlInstance
from the WebClientSession
and set the visibility to false
.
if (interactive) {var wcs = service.webclientsession();wcs.getControlInstance("main_grid3_7").setVisibility(false);}
In the example above we are using some of the available implicit variables Maximo provides to the Automation Script:
interactive
variable indicates that the script is executing within the context of an active user session and not as part of a background process, such as an integration action or Cron Task. service
variable provides an instance of the com.ibm.tivoli.maximo.script.ScriptService
class that has the webclientsession()
method that provides access to the psdi.webclient.system.session.WebClientSession
, which then provides access to the current session and user interface components. Older versions of Maximo have a
com.ibm.tivoli.maximo.script.ScriptService
class that does not have thewebclientsession()
method. In these cases you can use thepsdi.common.context.UIContext
class and then callUIContext.getCurrentContext().getWebClientSession()
. Just make sure to import the UIContext withUIContext = Java.type("psdi.common.context.UIContext")
.
A full list and descriptions of the implicit variables is available at https://www.ibm.com/docs/en/cdfsp/7.6.1.2?topic=scripts-implicit-variables .
The previous examples provide the means to hide or make data read only, but this is not very useful since these rules are applied to everyone. To make this more useful we need to be able to apply conditions for when data should be hidden or made read only.
A common approach is to determine if a user is part of a group and then apply the rules as needed. I think this stems from workshops discussing who should have access based on their roles, such as coming up with requirements like "Supervisors should have access to the work type field.". The requirement may then be literally implemented, since there is likely already a security group called "SUPERVISOR", a check is made to see if the user is a member of that group and then apply the condition. Using the lessons from our previous post on using functions, this might be implemented with the following:
SqlFormat = Java.type("psdi.mbo.SqlFormat");MboConstants = Java.type("psdi.mbo.MboConstants");main();function main() {if (interactive) {if (isMemberOfGroup("SUPERVISOR", userInfo.getUserName())) {mbo.setFieldFlag("WORKTYPE", MboConstants.READONLY, false);} else {mbo.setFieldFlag("WORKTYPE", MboConstants.READONLY, true);}}}function isMemberOfGroup(groupName, userName) {var groupUserSet;try {groupUserSet = service.getMboSet("GROUPUSER");var sqlf = new SqlFormat("groupname = :1 and userid = :2");sqlf.setObject(1, "GROUPUER", "GROUPNAME", groupName);sqlf.setObject(2, "GROUPUER", "USERID", userName);groupUserSet.setWhere(sqlf.format());return !groupUserSet.isEmpty();} finally {close(groupUserSet);}}function close(set) {if (set) {set.cleanup();set.close();}}
Variations of this is may include granting access based on membership to a PERSONGROUP
or even a CREW
.
The fundamental problem with this approach is that it creates magic groups that bestow special powers outside of the normal use of assigning security options. Without carefully auditing of all the automation scripts in a system, there is no way to discover what permissions have been granted to a user, since simply being part of a group now has special meaning, a member may have access to additional functionality without that access being declared.
A much better approach is to define additional security options and then grant that option to the desired group. This adheres to the standard Maximo security model and avoids the creation of security or person groups with special meaning.
We will refactor our previous example and create a new security option for granting access to the WORKTYPE
attribute.
Open the Application Designer application, then search for the WOTRACK
application. From the Select Action
menu select Add/Modify Security Options
.
Click the New Row
button and then enter in EDITWORKTYPE
as the Option
value and Edit Work Type
as the description. Then click the OK
button to save the changes.
Open the Security Groups application, then search for the security group that you want to grant access to, in our example it is the "SUPERVISOR" security group. Select the Applications tab and then search for the Work Order Tracking application in the Applications table. In the Options for Work Order Tracking table either filter or page to the Edit Work Type
security option that was created in the previous step, then click the check box and save the record to grant the option to the group.
Now that we have the security option and have granted it to the desired group we can update our Automation Script to use that option.
MboConstants = Java.type("psdi.mbo.MboConstants");MXServer = Java.type("psdi.server.MXServer");main();function main() {if (interactive) {if (hasAppOption("wotrack", "editworktype")) {mbo.setFieldFlag("WORKTYPE", MboConstants.READONLY, false);} else {mbo.setFieldFlag("WORKTYPE", MboConstants.READONLY, true);}}}function hasAppOption(app, optionName){return MXServer.getMXServer().lookup("SECURITY").getProfile(mbo.getUserInfo()).hasAppOption(app, optionName);}
Not only does this provide a clearer definition of access rights, it also simplifies the code, reduces database access and improves performance, since the user's security profile is already cached in memory.
According to the documentation the
userinfo
implicit variable is available in all Automation Scripts contexts, but in testing I received errors that it was not defined. I have worked around this by using thembo
implicit variable to get a reference to the current user'sUserInfo
object. This may be specific to my environment, version, or context in which I am using it, if possible it is preferable to use theuserinfo
implicit variable.
Using Automation Scripts to implement security restrictions provides significant flexibility and options beyond the capabilities offered by Conditional Expressions. By using Maximo's Security Options, Automation Scripts can also be incorporated into the standard Maximo security model and access rights can continue to be managed through Maximo's security groups.