Security via Automation Scripts

November 10, 2021

Introduction

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.

Securing Data

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.

Read Only

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);

Managing Attribute Visibility

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.

Work Type Textbox ID

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:

  • The 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.
  • The 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.

Note

Older versions of Maximo have a com.ibm.tivoli.maximo.script.ScriptService class that does not have the webclientsession() method. In these cases you can use the psdi.common.context.UIContext class and then call UIContext.getCurrentContext().getWebClientSession(). Just make sure to import the UIContext with UIContext = 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 .

Managing Rules

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.

Access by Groups

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.

Access by Security Options

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.

Configuring a Security Option

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.

Select Action > 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.

Enter EDITWORKTYPE security option

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.

Grant EDITWORKTYPE security option

Update Automation Script

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.

Note

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 the mbo implicit variable to get a reference to the current user's UserInfo object. This may be specific to my environment, version, or context in which I am using it, if possible it is preferable to use the userinfo implicit variable.

Conclusion

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.