ServiceNow Service Catalog integration
Introduction
Memority offers a Service Now plugin available in ServiceNow store.
This new Memority app addresses the needs of our clients using ServiceNow by offering their employees a single portal to make their requests. Thus, end users can view the list of their roles, submit an additional request that may trigger a workflow, and track the status of the request. Approvals can be carried out either on the ServiceNow side or the Memority side, depending on the configuration.
The app installed on the ServiceNow platform interacts with Memority via API and benefits from the rules and settings configured on our side. For example, end users can only request the roles they are authorized for. All actions performed on the ServiceNow side are logged in the Memority audit. It is also possible to track the status of requests from Memority. No data is stored on the ServiceNow side, as all interactions are dynamic and do not require data synchronization. Consequently, adding a new role on the Memority side is directly visible from ServiceNow if the end user has the necessary rights.
This new app responds to our clients’ needs to improve user experience, rationalize the use of tools while ensuring a complete audit of their activity within IAM.
This app adds to the existing integration functions between ServiceNow and Memority: SSO, account management and rights provisioning, two-way ticket opening between the platforms.
The Memority app for ServiceNow is supported on the Washington DC, Vancouver and Utah platforms.
Users in ServiceNow should be able to :
list their assigned applicative roles in Memority
request an applicative role from the list of applicative roles published by Memority
approve a workflow task
The following diagram represents the use case where a user, in ServiceNow, request a "Salesforce" applicative role, interacting with Memority:
The user requests an applicative role (ex. Salesforce), via a Memority Service Catalog Item
It calls Memority to create the request in Memority. An approval workflow may be created in Memority, depending on the requested role.
The Memority approval task in Memority is duplicated in ServiceNow to let the manager approving in ServiceNow instead of in Memority portal.
The manager approves the request in ServiceNow portal
It calls Memority to approve the request in Memority workflow
In case the Memority workflow is a two step workflow, the Application owner approves the request in Memority portal
The Salesforce account is created by Memority
Memority call ServiceNow to close the request
Service Catalog Item
A new Service Catalog Item, "Application Access", is created to request an application role for a beneficiary :
Questions are:
Requested For : the beneficiary user
Choose an application : displays a drop-down based on a remote table (that call Memority) that list the applicative roles published for the beneficiary
Start Date
End Date
Business Justification : text field
The request activity stream allows to track the progress and actions taken on both ServiceNow and Memority sides.
How it works?
Integration between Memority and ServiceNow
The following diagram describes the interaction between Memority and ServiceNow:
This solution implies to create a scoped application on ServiceNow side, with following artifacts:
The user requests the new Memority Service Catalog Item called "Application Access". He chooses an applicative role via a dropdown list which is based on a new “Memority Published Roles” remote table that is dynamically built by calling Memority via an Action spoke.
A new RITM is created in ServiceNow native table.
A new flow is triggered by this RITM creation.
The flow then create the request on Memority side.
A workflow is created in Memority.
A validation task in Memority workflow is configured to create an approval task for the requested RITM, in Service Now : Memority creates a record in a new Memority custom table, with the source RITM id and the approver id. Then a new Flow is triggered to create the approvals for the RITM in ServiceNow.
The approver approves or rejects the request (native interface). A new flow is triggered to propagate the approval or rejection to Memority workflow.
Memority workflow continues with additional validation inside Memority (ex. Application Owner validation)
A comment to trace who has validated is written to the RITM by Memority. The RITM is closed by Memority.
In case the request is fully approved, the account or applicative role corresponding to the request is provisioned by Memority.
Memority initial configuration
ServiceNow rule
ServiceNow library (BUM) allows to simplify ServiceNow API calling.
Three kind of calls are available:
Comment
Allows to send a new message in the activity stream of the ServiceNow request. This provides a view and status update of the request directly from the ServiceNow interfaces.
Change ServiceNow request state
Allows to change the status of a ServiceNow request. There are two statuses:
"3" to successfully close a request
"7" to reject a request
Create a ServiceNow approval task
Allows to trigger an approval task on the ServiceNow side.
<ruleaddon:Rule id="snow-library"
xmlns:ruleaddon="http://www.memority.com/toolkit/addons/rule/1_0">
<category>ANY</category>
<engine>GROOVY</engine>
<name>snow-library</name>
<script><![CDATA[
import com.memority.toolkit.core.api.security.UsernamePasswordCredentials
import com.memority.toolkit.rule.api.LibraryInitializationOutcome
import java.time.Instant
public boolean requestSnowCallState(String requestRITMId, String state, String work_notes, String comments) {
String endpointUrl = SETTINGS.get("bum.snow.endpointUrl")
def body = [
"state" : state,
"work_notes": work_notes,
"comments" : comments
]
HTTP.patch(endpointUrl + '/api/x_memor_memority/memority/ritm/' +requestRITMId) {
basicAuth(usernamePassword("bum.snow.credentials"))
json body
onSuccess {
LOG.trace("Response - {}", it.json)
LOG.trace("Response.code - {}", it.code)
return true
}
onError {
LOG.trace("Response - {}", it)
LOG.trace("Response.code - {}", it.code)
return false
}
}
}
public boolean requestSnowCallSendComment(String requestRITMId, String comments) {
String endpointUrl = SETTINGS.get("bum.snow.endpointUrl")
def body = [
"comments" : comments
]
HTTP.patch(endpointUrl + '/api/x_memor_memority/memority/ritm/' + requestRITMId) {
basicAuth(usernamePassword("bum.snow.credentials"))
json body
onSuccess {
LOG.trace("Response - {}", it)
LOG.trace("Response.code - {}", it.code)
}
onError {
LOG.trace("Response - {}", it)
LOG.trace("Response.code - {}", it.code)
}
}
}
public boolean requestSnowCallCreateApprovalTask(String requestRITMId,
Instant enabledFrom,
Instant enabledUntil,
Map dimensions,
String approvers,
String taskInstanceId) {
String endpointUrl = SETTINGS.get("bum.snow.endpointUrl")
def roleAssignmentChanges = ["enabledFrom" :
["value": enabledFrom],
"enabledUntil":
["value": enabledUntil],
"comment" : null,
"dimensions" : dimensions
]
def identitySnowCorrelationKey = FIND.identity().withAttributesProjection("snowCorrelationKey").withId(approvers)?.snowCorrelationKey
def body = [
"approver" : identitySnowCorrelationKey,
"ritm" : requestRITMId,
"memority_task" : taskInstanceId,
"role_assignement_changes": toJson(roleAssignmentChanges)
]
HTTP.post(endpointUrl + '/api/x_memor_memority/memority/ritm_approval') {
basicAuth(usernamePassword("bum.snow.credentials"))
json body
onSuccess {
LOG.trace("Response - {}", it)
LOG.trace("Response.code - {}", it.code)
}
onError {
LOG.trace("Response - {}", it)
LOG.trace("Response.code - {}", it.code)
}
}
}
return LibraryInitializationOutcome.success()
]]></script>
<type>LIB</type>
</ruleaddon:Rule>
Service Now Identity Correlation Key
A new attribute is mandatory for Memority identities. This attribute need to be called “snowCorrelationKey”
<ctdidm:AttributeDefinition id="snowCorrelationKey"
xmlns:ctdidm="http://www.memority.com/citadel/idm/1_0">
<name>snowCorrelationKey</name>
<description/>
<objectKind>IDENTITY</objectKind>
<valueType>STRING</valueType>
<uniqueConstraint>
<checkOnUpdate>true</checkOnUpdate>
<constrainOnType>false</constrainOnType>
<searchOperator>EQUALS</searchOperator>
</uniqueConstraint>
<validationRules/>
<normalizeRules/>
<confidentiality>0</confidentiality>
<virtual>false</virtual>
<multiValued>false</multiValued>
<readOnly>false</readOnly>
<immutable>false</immutable>
<secret>false</secret>
<encrypted>false</encrypted>
<searchCriterion>true</searchCriterion>
<system>false</system>
<highPriority>false</highPriority>
<minLength>2</minLength>
<maxLength>255</maxLength>
</ctdidm:AttributeDefinition>
Dedicated Service Now features
A set of dedicated ServiceNow features are required to communicate with Memority ServiceNow plugin.
<ctdbum:FeatureConfiguration id="identity-snowplugin-search"
xmlns:ctdbum="http://www.memority.com/citadel/bum/1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>identity-snowplugin-search</name>
<type>SEARCH</type>
<scope type="EXPRESSION" objectKind="IDENTITY">
<objectTypes>
<objectType>internal</objectType>
</objectTypes>
</scope>
<options>
<formLabelOnTop>false</formLabelOnTop>
<initialization/>
<pendingOperationBehaviour>WARN</pendingOperationBehaviour>
<submit>
<reportDisplay>DISPLAY_ALL</reportDisplay>
</submit>
</options>
<screen>
<views>
<view id="identity-snow-search-view">
<description/>
<icon>fa fa-search</icon>
<sections>
<section id="identity-snow-search-identity">
<layout>SINGLE</layout>
<columns>
<column>
<widgets>
<widget id="search-widget" xsi:type="ctdbum:SearchWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<actions>
<action id="view-entry-btn" xsi:type="ctdbum:ButtonWidgetType">
<hidden>false</hidden>
<config>
<authenticationLevelSufficient>false</authenticationLevelSufficient>
<borderless>false</borderless>
<circle>true</circle>
<color>blue</color>
<icon>fa fa-eye</icon>
<label>true</label>
<link>feature://identity-snowplugin-role/{dataKey.id}</link>
<linkTarget>SELF</linkTarget>
<outline>true</outline>
<size>XS</size>
</config>
</action>
</actions>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>id</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>firstName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>lastName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>email</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>snowCorrelationKey</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>false</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
</config>
</widget>
</widgets>
</column>
</columns>
</section>
</sections>
</view>
</views>
</screen>
<authentication>
<authenticationLevelComparison>MINIMUM</authenticationLevelComparison>
</authentication>
<operations>
<operation>
<actions/>
<attributes/>
<checkInheritedAttributes>
<attributes/>
<level>WARN</level>
</checkInheritedAttributes>
<type>READ</type>
</operation>
</operations>
<operationOnSelf>false</operationOnSelf>
</ctdbum:FeatureConfiguration>
<ctdbum:FeatureConfiguration id="identity-snowplugin-role"
xmlns:search="http://www.memority.com/toolkit/search-expression/1_0"
xmlns:ctdbum="http://www.memority.com/citadel/bum/1_0"
xmlns:ctdrule="http://www.memority.com/citadel/rule/1_0"
xmlns:ctd="http://www.memority.com/citadel/1_0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<name>identity-snowplugin-role</name>
<type>UI_FOR_OBJECT</type>
<scope type="EXPRESSION" objectKind="IDENTITY">
<objectTypes>
<objectType>internal</objectType>
</objectTypes>
</scope>
<options>
<formLabelOnTop>false</formLabelOnTop>
<initialization/>
<pendingOperationBehaviour>WARN</pendingOperationBehaviour>
<submit>
<reportDisplay>HIDE_ALL</reportDisplay>
</submit>
</options>
<screen>
<views>
<view id="identity-common-role-view">
<icon>fa fa-snowflake-o</icon>
<sections>
<section id="identity-common-role-section-application">
<layout>SINGLE</layout>
<frame>
<actions>
<action id="identity-common-role-section-application-assignment" xsi:type="ctdbum:ButtonWidgetType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<hidden>false</hidden>
<config>
<align>RIGHT</align>
<authenticationLevelSufficient>false</authenticationLevelSufficient>
<borderless>false</borderless>
<circle>true</circle>
<color>green-meadow</color>
<icon>fa fa-plus</icon>
<label>true</label>
<linkTarget>SELF</linkTarget>
<outline>true</outline>
<size>SM</size>
<widgetToOpen id="application-assignment" xsi:type="ctdbum:RoleAssignmentWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>false</title>
<assignment>
<fields>
<field id="serviceNowRitmId">
<hidden>false</hidden>
<config>
<editor>
<editWidget xsi:type="ctdbum:TextInputEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>false</required>
<type>text</type>
</config>
</editWidget>
</editor>
<label/>
<lockedInUi>false</lockedInUi>
<mode>READ_WRITE</mode>
<multiValued>false</multiValued>
<validationRule>
<script>import com.memority.toolkit.rule.api.ValidationRuleResult
if (VALUE) {
return ValidationRuleResult.valid()
}else{
return ValidationRuleResult.invalid("Attribute is mandatory")
}
</script>
</validationRule>
</config>
<fieldId>serviceNowRitmId</fieldId>
</field>
</fields>
</assignment>
<scope type="EXPRESSION" objectKind="ROLE">
<searchExpression>
<search:Prop op="EQUALS" name="roleRequestableBySnow">
<value script="false">true</value>
</search:Prop>
</searchExpression>
<objectTypes>
<objectType>application</objectType>
</objectTypes>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>FORMULA</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
</config>
</widgetToOpen>
</config>
</action>
</actions>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="application-list" xsi:type="ctdbum:RoleDashboardWidgetType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>true</title>
<updateFields>
<field id="serviceNowRitmId">
<hidden>false</hidden>
<config>
<editor>
<editWidget xsi:type="ctdbum:TextInputEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>false</required>
<type>text</type>
</config>
</editWidget>
</editor>
<label />
<lockedInUi>false</lockedInUi>
<mode>READ_WRITE</mode>
<multiValued>false</multiValued>
<validationRule>
<script>import com.memority.toolkit.rule.api.ValidationRuleResult
if (VALUE) {
return ValidationRuleResult.valid()
}else{
return ValidationRuleResult.invalid("Attribute is mandatory")
}
</script>
</validationRule>
</config>
<fieldId>serviceNowRitmId</fieldId>
</field>
</updateFields>
<revokeFields />
<displayProvisioningDetails>true</displayProvisioningDetails>
<scope type="EXPRESSION">
<searchExpression>
<search:Prop op="EQUALS" name="role.type">
<value script="false">application</value>
</search:Prop>
</searchExpression>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>role</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>resource</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>_details</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>false</displayFrozenOperators>
<frozen>ALL</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences>
<objectReference>
<attribute>role</attribute>
<editWidget xsi:type="ctdbum:AdvancedObjectReferenceEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>true</required>
<popupAttributes>
<attribute>roleName</attribute>
<attribute>roleApplication</attribute>
</popupAttributes>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>roleApplication</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>true</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>false</displayFrozenOperators>
<frozen>LABELS</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences>
<objectReference>
<attribute>id</attribute>
<editWidget xsi:type="ctdbum:AdvancedObjectReferenceEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>false</required>
<popupAttributes>
<attribute>roleName</attribute>
</popupAttributes>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>id</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>true</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
<displayPopup>true</displayPopup>
<scope type="EXPRESSION" objectKind="ROLE" xsi:type="ctd:DynamicObjectScopeType">
<objectTypes>
<objectType>application</objectType>
</objectTypes>
</scope>
</config>
</editWidget>
</objectReference>
</objectReferences>
</search>
<displayPopup>true</displayPopup>
</config>
</editWidget>
</objectReference>
</objectReferences>
<fetchLiveStatus>false</fetchLiveStatus>
</search>
<workflowHistoryDisplay>
<displayAssignmentHistory>true</displayAssignmentHistory>
<displayManualProvisioningHistory>true</displayManualProvisioningHistory>
<displayRecertificationHistory>true</displayRecertificationHistory>
</workflowHistoryDisplay>
</config>
</widget>
</widgets>
</column>
</columns>
</section>
<section id="identity-common-role-section-administration">
<layout>SINGLE</layout>
<frame>
<actions>
<action id="identity-common-role-section-administration-assignment" xsi:type="ctdbum:ButtonWidgetType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<hidden>false</hidden>
<config>
<align>RIGHT</align>
<authenticationLevelSufficient>false</authenticationLevelSufficient>
<borderless>false</borderless>
<circle>true</circle>
<color>green-meadow</color>
<icon>fa fa-plus</icon>
<label>true</label>
<linkTarget>SELF</linkTarget>
<outline>true</outline>
<size>SM</size>
<widgetToOpen id="administration-assignment" xsi:type="ctdbum:RoleAssignmentWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>false</title>
<assignment/>
<scope type="EXPRESSION" objectKind="ROLE">
<objectTypes>
<objectType>administration</objectType>
</objectTypes>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>FORMULA</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
</config>
</widgetToOpen>
</config>
</action>
</actions>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="administration-list" xsi:type="ctdbum:RoleDashboardWidgetType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>true</title>
<displayProvisioningDetails>false</displayProvisioningDetails>
<scope type="EXPRESSION">
<searchExpression>
<search:Prop op="EQUALS" name="role.type" xmlns:search="http://www.memority.com/toolkit/search-expression/1_0">
<value script="false">administration</value>
</search:Prop>
</searchExpression>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>role</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>resource</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>_details</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>false</displayFrozenOperators>
<frozen>ALL</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences>
<objectReference>
<attribute>role</attribute>
<editWidget xsi:type="ctdbum:AdvancedObjectReferenceEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>true</required>
<popupAttributes>
<attribute>roleName</attribute>
</popupAttributes>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
<displayPopup>true</displayPopup>
</config>
</editWidget>
</objectReference>
</objectReferences>
<fetchLiveStatus>false</fetchLiveStatus>
</search>
</config>
</widget>
</widgets>
</column>
</columns>
</section>
</sections>
</view>
</views>
</screen>
<authentication>
<authenticationLevelComparison>MINIMUM</authenticationLevelComparison>
</authentication>
<operations>
<operation>
<actions/>
<attributes/>
<checkInheritedAttributes>
<attributes/>
<level>WARN</level>
</checkInheritedAttributes>
<type>UPDATE</type>
</operation>
</operations>
<operationOnSelf>false</operationOnSelf>
</ctdbum:FeatureConfiguration>
<ctdbum:FeatureConfiguration id="identity-snowplugin-self-role"
xmlns:ctdbum="http://www.memority.com/citadel/bum/1_0"
xmlns:ctd="http://www.memority.com/citadel/1_0"
xmlns:search="http://www.memority.com/toolkit/search-expression/1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>identity-snowplugin-self-role</name>
<type>UI_FOR_OBJECT</type>
<scope type="EXPRESSION" objectKind="IDENTITY">
<objectTypes/>
</scope>
<options>
<formLabelOnTop>false</formLabelOnTop>
<initialization/>
<pendingOperationBehaviour>WARN</pendingOperationBehaviour>
<submit>
<reportDisplay>HIDE_ALL</reportDisplay>
</submit>
</options>
<screen>
<views>
<view id="identity-snowplugin-self-role-view">
<icon>fa fa-snowflake-o</icon>
<sections>
<section id="identity-snowplugin-self-role-section-application">
<layout>SINGLE</layout>
<frame>
<actions>
<action id="identity-snowplugin-self-role-section-application-assignment" xsi:type="ctdbum:ButtonWidgetType">
<hidden>false</hidden>
<config>
<align>RIGHT</align>
<authenticationLevelSufficient>false</authenticationLevelSufficient>
<borderless>false</borderless>
<circle>true</circle>
<color>green-meadow</color>
<icon>fa fa-plus</icon>
<label>true</label>
<linkTarget>SELF</linkTarget>
<outline>true</outline>
<size>SM</size>
<widgetToOpen id="application-assignment" xsi:type="ctdbum:RoleAssignmentWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>false</title>
<assignment>
<fields>
<field id="serviceNowRitmId">
<hidden>false</hidden>
<config>
<editor>
<editWidget xsi:type="ctdbum:TextInputEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>true</required>
<type>text</type>
</config>
</editWidget>
</editor>
<label />
<lockedInUi>false</lockedInUi>
<mode>READ_WRITE</mode>
<multiValued>false</multiValued>
</config>
<fieldId>serviceNowRitmId</fieldId>
</field>
</fields>
</assignment>
<scope type="EXPRESSION" objectKind="ROLE">
<searchExpression>
<search:Prop op="EQUALS" name="roleRequestableBySnow">
<value script="false">true</value>
</search:Prop>
</searchExpression>
<objectTypes>
<objectType>application</objectType>
</objectTypes>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>FORMULA</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
</config>
</widgetToOpen>
</config>
</action>
</actions>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="application-list" xsi:type="ctdbum:RoleDashboardWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>true</title>
<displayProvisioningDetails>true</displayProvisioningDetails>
<scope type="EXPRESSION">
<searchExpression>
<search:And>
<search:Prop op="NOT_EQUALS" name="status">
<value script="false">DELETED</value>
</search:Prop>
<search:Prop op="EQUALS" name="role.type">
<value script="false">application</value>
</search:Prop>
</search:And>
</searchExpression>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>role</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>resource</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>_details</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>false</displayFrozenOperators>
<frozen>ALL</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences>
<objectReference>
<attribute>role</attribute>
<editWidget xsi:type="ctdbum:AdvancedObjectReferenceEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>true</required>
<popupAttributes>
<attribute>roleName</attribute>
<attribute>roleApplication</attribute>
</popupAttributes>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>roleApplication</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>true</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences>
<objectReference>
<attribute>roleApplication</attribute>
<editWidget xsi:type="ctdbum:AdvancedObjectReferenceEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>false</required>
<popupAttributes>
<attribute>rsrcName</attribute>
</popupAttributes>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>id</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>true</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>rsrcName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
<displayPopup>true</displayPopup>
<scope type="EXPRESSION" objectKind="RESOURCE" xsi:type="ctd:DynamicObjectScopeType">
<objectTypes>
<objectType>application</objectType>
</objectTypes>
</scope>
</config>
</editWidget>
</objectReference>
</objectReferences>
</search>
<displayPopup>true</displayPopup>
</config>
</editWidget>
</objectReference>
</objectReferences>
<fetchLiveStatus>false</fetchLiveStatus>
</search>
</config>
</widget>
</widgets>
</column>
</columns>
</section>
<section id="identity-snowplugin-self-role-section-administration">
<layout>SINGLE</layout>
<frame>
<actions>
<action id="identity-snowplugin-self-role-section-administration-assignment" xsi:type="ctdbum:ButtonWidgetType">
<hidden>false</hidden>
<config>
<align>RIGHT</align>
<authenticationLevelSufficient>false</authenticationLevelSufficient>
<borderless>false</borderless>
<circle>true</circle>
<color>green-meadow</color>
<icon>fa fa-plus</icon>
<label>true</label>
<linkTarget>SELF</linkTarget>
<outline>true</outline>
<size>SM</size>
<widgetToOpen id="administration-assignment" xsi:type="ctdbum:RoleAssignmentWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>false</title>
<assignment/>
<scope type="EXPRESSION" objectKind="ROLE">
<objectTypes>
<objectType>administration</objectType>
</objectTypes>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>FORMULA</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
</config>
</widgetToOpen>
</config>
</action>
</actions>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="administration-list" xsi:type="ctdbum:RoleDashboardWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<bordered>true</bordered>
<title>true</title>
<displayProvisioningDetails>true</displayProvisioningDetails>
<scope type="EXPRESSION">
<searchExpression>
<search:And>
<search:Prop op="NOT_EQUALS" name="status">
<value script="false">DELETED</value>
</search:Prop>
<search:Prop op="EQUALS" name="role.type">
<value script="false">administration</value>
</search:Prop>
</search:And>
</searchExpression>
</scope>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>role</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>resource</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>excerpt</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>_details</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>status</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>false</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>false</displayFrozenOperators>
<frozen>ALL</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences>
<objectReference>
<attribute>role</attribute>
<editWidget xsi:type="ctdbum:AdvancedObjectReferenceEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>true</required>
<popupAttributes>
<attribute>roleName</attribute>
</popupAttributes>
<search>
<actions/>
<allowExport>false</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>NO</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
</modes>
<objectReferences/>
</search>
<displayPopup>true</displayPopup>
</config>
</editWidget>
</objectReference>
</objectReferences>
<fetchLiveStatus>false</fetchLiveStatus>
</search>
</config>
</widget>
</widgets>
</column>
</columns>
</section>
</sections>
</view>
</views>
</screen>
<authentication>
<authenticationLevelComparison>MINIMUM</authenticationLevelComparison>
</authentication>
<operations>
<operation>
<actions/>
<attributes/>
<checkInheritedAttributes>
<attributes/>
<level>WARN</level>
</checkInheritedAttributes>
<type>UPDATE</type>
</operation>
</operations>
<operationOnSelf>true</operationOnSelf>
</ctdbum:FeatureConfiguration>
<ctdbum:FeatureConfiguration id="role-snowplugin-search"
xmlns:ctdbum="http://www.memority.com/citadel/bum/1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>role-snowplugin-search</name>
<type>SEARCH</type>
<scope type="EXPRESSION" objectKind="ROLE">
<objectTypes/>
</scope>
<options>
<formLabelOnTop>false</formLabelOnTop>
<initialization/>
<pendingOperationBehaviour>WARN</pendingOperationBehaviour>
<submit>
<reportDisplay>DISPLAY_ALL</reportDisplay>
</submit>
</options>
<screen>
<views>
<view id="role-snow-search-view">
<description/>
<icon>fa fa-search</icon>
<sections>
<section id="role-snow-search-section">
<layout>SINGLE</layout>
<columns>
<column>
<widgets>
<widget id="search-widget" xsi:type="ctdbum:SearchWidgetType">
<hidden>false</hidden>
<displayOptions>
<modalSize>LG</modalSize>
</displayOptions>
<config>
<actions>
<action id="view-entry-btn" xsi:type="ctdbum:ButtonWidgetType">
<hidden>false</hidden>
<config>
<authenticationLevelSufficient>false</authenticationLevelSufficient>
<borderless>false</borderless>
<circle>true</circle>
<color>blue</color>
<icon>fa fa-eye</icon>
<label>true</label>
<link>feature://role-snowplugin-read/{dataKey.id}</link>
<linkTarget>SELF</linkTarget>
<outline>true</outline>
<size>XS</size>
</config>
</action>
</actions>
<allowExport>true</allowExport>
<columns>
<column>
<attribute>true</attribute>
<dataKey>id</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>true</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>false</sorted>
<type>general</type>
</column>
<column>
<attribute>true</attribute>
<dataKey>roleName</dataKey>
<dataType>string</dataType>
<dateFormat>DAY_MONTH_YEAR_LONG</dateFormat>
<ellipsis>false</ellipsis>
<hidden>false</hidden>
<sortAs>ALPHA</sortAs>
<sortDirection>ASC</sortDirection>
<sortable>true</sortable>
<sorted>true</sorted>
<type>general</type>
</column>
</columns>
<rowClickActions/>
<additionalSearchAttributes/>
<displayFrozenOperators>true</displayFrozenOperators>
<frozen>LABELS</frozen>
<modes>
<mode>SIMPLE</mode>
<mode>MULTICRITERIA</mode>
<mode>FORMULA</mode>
</modes>
<objectReferences/>
</config>
</widget>
</widgets>
</column>
</columns>
</section>
</sections>
</view>
</views>
</screen>
<authentication>
<authenticationLevelComparison>MINIMUM</authenticationLevelComparison>
</authentication>
<operations>
<operation>
<actions/>
<attributes/>
<checkInheritedAttributes>
<attributes/>
<level>WARN</level>
</checkInheritedAttributes>
<type>READ</type>
</operation>
</operations>
<operationOnSelf>false</operationOnSelf>
</ctdbum:FeatureConfiguration>
<ctdbum:FeatureConfiguration id="role-snowplugin-read"
xmlns:ctdbum="http://www.memority.com/citadel/bum/1_0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>role-snowplugin-read</name>
<type>READ</type>
<scope type="EXPRESSION" objectKind="ROLE">
<objectTypes/>
</scope>
<options>
<formLabelOnTop>false</formLabelOnTop>
<initialization/>
<pendingOperationBehaviour>WARN</pendingOperationBehaviour>
<submit>
<reportDisplay>DISPLAY_ALL</reportDisplay>
</submit>
</options>
<screen>
<views>
<view id="role-snow-read-view">
<icon>fa fa-address-card-o</icon>
<sections>
<section id="role-snow-read-section-role">
<layout>TWO_EQUAL</layout>
<frame>
<actions/>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="roleName" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleName</attributeId>
</widget>
<widget id="description" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleDescription</attributeId>
</widget>
<widget id="roleApplication" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleApplication</attributeId>
</widget>
</widgets>
</column>
<column>
<widgets>
<widget id="enabled" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>enabled</attributeId>
</widget>
<widget id="activationFrom" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>activationFrom</attributeId>
</widget>
<widget id="activationUntil" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>activationUntil</attributeId>
</widget>
</widgets>
</column>
</columns>
</section>
<section id="role-snow-read-section-right">
<layout>SINGLE</layout>
<frame>
<actions/>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="rightBindings" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>rightBindings</attributeId>
</widget>
</widgets>
</column>
</columns>
</section>
<section id="role-snow-read-section-dimension">
<layout>SINGLE</layout>
<frame>
<actions/>
<collapsible>true</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="dimensions" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>dimensions</attributeId>
</widget>
</widgets>
</column>
</columns>
</section>
<section id="role-snow-read-section-assignment">
<layout>SINGLE</layout>
<frame>
<actions/>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>true</title>
</frame>
<columns>
<column>
<widgets>
<widget id="roleSelfService" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleSelfService</attributeId>
</widget>
<widget id="roleRequester" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleRequester</attributeId>
</widget>
<widget id="roleWorkflow" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleWorkflow</attributeId>
</widget>
<widget id="roleMultiAssignment" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleMultiAssignment</attributeId>
</widget>
<widget id="roleAllowedIdentityTypes" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleAllowedIdentityTypes</attributeId>
</widget>
<widget id="roleExclusionAssignments" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>roleExclusionAssignments</attributeId>
</widget>
<widget id="roleAssignmentPolicies" xsi:type="ctdbum:AttributeEditorWidgetType">
<hidden>false</hidden>
<config>
<lockedInUi>false</lockedInUi>
<mode>READ</mode>
<override>false</override>
</config>
<attributeId>assignmentPolicies</attributeId>
</widget>
</widgets>
</column>
</columns>
</section>
</sections>
</view>
</views>
<frame>
<actions/>
<collapsible>false</collapsible>
<display>PORTLET</display>
<initiallyCollapsed>false</initiallyCollapsed>
<title>false</title>
</frame>
</screen>
<authentication>
<authenticationLevelComparison>MINIMUM</authenticationLevelComparison>
</authentication>
<operations>
<operation>
<actions/>
<attributes/>
<checkInheritedAttributes>
<attributes/>
<level>WARN</level>
</checkInheritedAttributes>
<type>READ</type>
</operation>
</operations>
<operationOnSelf>false</operationOnSelf>
</ctdbum:FeatureConfiguration>
Theses features need to be added to the tenant existing features access policy as exisiting role features. There's no need to add them to the menu in order to avoid displaying them.
Settings
Two settings are mandatory:
api.settings.bum.snow.endpointUrl
; Type:STRING
; Exemple:https://ven06706.service-now.com
api.vault.bum.snow.endpointUrl
; Type:CREDENTIAL
(<servicenow_applicative_user_id>,<servicenow_applicative_user_password>)
API account
A technical account is mandatory to communicate with Service Now.
This account needs to be set up in the initial configuration of the plugin in ServiceNow and in the approvers of workflows on the Memority side.
The account needs to have theses permissions:
Access to Snow features
Access to API guard zone with scope (“bum-features”, “idm-identities”)
OAuth2 configuration
The following steps must be taken to create an OAuth client on the Memority side to enable ServiceNow to call the Memority API:
Client Id : <memority_client_id>
Redirect uri : <servicenow_connection_url>
Client Type : Confidential
Client secret : <memority_client_secret>
Authentication Level : 0 (Password)
Subject : choose the attribute : iamUserLogin
Scope : add the scope uid=uid
Service Now initial configuration
Application Dependencies
List all plugins required: “ServiceNow IntegrationHub Starter Pack installer” need to be installed.
ServiceNow users (Requesters, Approvers, and Beneficiaries) are correlated with Memority users. The correlation is done on Memority side with the dedicated attribute “snowCorrelationKey” that should contain the user ID of the ServiceNow user.
Applicative user: a new integration user needs to be created in ServiceNow
Permissions : The following table summarizes the required permissions needed in ServiceNow for each type of users in ServiceNow :
Type of users | Use case | Role |
Employee | Request a role via Memority Service Catalog Item List its applicative roles (by calling Memority) | x_memor_memority.user (new custom role) |
Manager | Request a role via Memority Service Catalog Item List its applicative roles (by calling Memority) Approve or Reject a Memority RITM | x_memor_memority.user (new custom role) approver_user |
Applicative user (used by Memority to call ServiceNow API) | Add comment on a RITM Modify state on a RITM Create a RITM approval record in Memority custom table | x_memor_memority.admin (new custom role) |
External systems connection
The following table lists the variables required to configure the connection between the ServiceNow instance and the Memority instance :
Variable | Example | Description |
<memority_client_id> | snow | Oauth client id (Memority acting as Oauth Provider) |
<memority_client_secret> | *** | Oauth client secret (Memority acting as Oauth Provider) |
<memority_connection_url> | API url of the Memority tenant | |
<memority_access_code_url> | Memority oauth access code url for the tenant | |
<memority_access_token_url> | https://sso.memority.com/sso/v2/oauth2/mytenant/access_token | Memority oauth access token url for the tenant |
<servicenow_redirect_url> | ServiceNow redirect url | |
<memority_applicative_user_id> | my_snow_api | Applicative user created in Memority |
<memority_applicative_user_password> | *** | Password of applicative user created in Memority |
<servicenow_applicative_user_id> | memority | Applicative user created in ServiceNow |
<servicenow_applicative_user_password> | *** | Password of applicative user created in ServiceNow |
<servicenow_connection_url> | ServiceNow instance url |
Configuration
Step to create the applicative user on ServiceNow side (used by Memority to call ServiceNow API) :
Login to ServiceNow with admin user, and create a new user :
User ID : <servicenow_applicative_user_id>
First name : put the same value <servicenow_applicative_user_id>
Check the box “Web service access only”
Set the password to <servicenow_applicative_user_password>
Add the roles x_memor_memority.admin
Steps to configure the connection to Memority
Login to ServiceNow with admin user, and Launch Flow Designer
In the connection tab, click on the button “View Details” of the connection called “Memority SC”
Click on “Edit” or “Configure” to configure the connection:
Connection URL : <memority_connection_url>
OAuth Client ID : <memority_client_id>
OAuth Client Secret : <memority_client_secret>
OAuth Access Code URL : <memority_access_code_url>
OAuth Access Token URL : <memority_access_token_url>
OAuth Redirect URL : <servicenow_redirect_url>
Click on the button “Edit and Get OAuth Token. A Memority authentication popup appears:
If a popup appears and indicates that the user is always connected and ask if you want to disconnect, answer yes (it mays happen if the SSO is configured between ServiceNow and Memority and the user has already a session in Memority).
Enter the identifier of the Memority applicative user: <memority_applicative_user_id>
Click on the button “Connection. Then enter the password of the user : <memority_applicative_user_password>
Click on the button “Log In”, then you should see the following message “OAuth Refresh token is available and will expire at <date> :
Logout from the Memority Session opened with the applicative user <memority_applicative_user_id>, as it will be a problem, if it is still valid in the browser when user will get their personal OAuth token.
Testing the configuration
To test the connection, login as Admin in ServiceNow, open Flow Designer, in tab “Action”, open the action “Get Memority ID” of the application “Memority SC”. Then click on the button “Test”:
Enter the user ID of a ServiceNow user federated with Memority, and click on the button “Run Test”.
Click on the link “View the Action execution details”:
Check that the result is “Success”. The output data “Memority ID” should contain the Memority ID of the user.
How is it used?
Workflow configuration
In role assignment workflow, you need to configure the call to ServiceNow.These calls can be made in different locations depending on the desired actions.
A role assignment field “ROLE_ASSIGNMENT.fields.serviceNowRitmId” is used to keep, during all the workflow context, the ServiceNow request Id.
This field is added in the snow feature request and needs to be added to the roleRequest widget.
<widget id="roleRequestWidget" xsi:type="ctdbum:RoleRequestWidgetType">
<hidden>false</hidden>
<config>
<actions/>
<commentMode>READ_WRITE</commentMode>
<tagsForCreate>
<readOnlyDimensionTags>
<tag>INIT</tag>
</readOnlyDimensionTags>
<readWriteDimensionTags/>
</tagsForCreate>
<tagsForDelete>
<readOnlyDimensionTags>
<tag>INIT</tag>
</readOnlyDimensionTags>
<readWriteDimensionTags/>
</tagsForDelete>
<tagsForUpdate>
<readOnlyDimensionTags>
<tag>INIT</tag>
</readOnlyDimensionTags>
<readWriteDimensionTags/>
</tagsForUpdate>
<validityRangeMode>READ_WRITE</validityRangeMode>
<fields>
<field id="fieldTargetId">
<hidden>false</hidden>
<config>
<editor>
<editWidget xsi:type="ctdbum:TextInputEditWidgetType">
<hidden>false</hidden>
<config>
<conditional>false</conditional>
<required>true</required>
<type>text</type>
</config>
</editWidget>
</editor>
<label />
<lockedInUi>false</lockedInUi>
<mode>READ_WRITE</mode>
<multiValued>false</multiValued>
</config>
<fieldId>serviceNowRitmId</fieldId>
</field>
</fields>
</config>
</widget>
Script Task
In case no approval is required, we need to trigger an empty workflow that only calls ServiceNowServiceNow to sucess and close request.
<scriptTask id="validateSnow" name="validateSnow">
<script><![CDATA[
import com.memority.toolkit.rule.api.ActionOutcome
import _libs_.snow$library.Main
import com.memority.toolkit.rule.api.groovy.transform.Lib
import groovy.transform.Field
@Lib
@Field
final _libs_.snow$library.Main SNOW
if (SNOW.requestSnowCallState(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String, "3", "Applicative role successfully assigned by Memority", "Applicative role successfully assigned by Memority")) {
return ActionOutcome.success()
} else {
return ActionOutcome.failure()
}
]]]]><![CDATA[>
</script>
</scriptTask>
Notification actions
In this case, when creating the validation task on the Memority side, it is necessary to trigger an approval task on the ServiceNow side. This action is carried out during the initialization step. Once the task is approved in ServiceNow, an API call will automatically be made to confirm the approval on the Memority side. This will trigger the Memority approval completion step. Two actions are possible depending on the workflow stage. If there are still approvals pending, it is possible to notify the ServiceNow activity stream. If it is the final step, it is possible to close the request on the ServiceNow side.
<initializationActions>
<action>
<script><![CDATA[
import com.memority.toolkit.rule.api.ActionOutcome
import _libs_.snow$library.Main
import com.memority.toolkit.rule.api.groovy.transform.Lib
import groovy.transform.Field
import java.time.Instant
@Lib
@Field
final _libs_.snow$library.Main SNOW
LOG.trace("Trigger ServiceNow Process - Workflow 1st step - Initialization")
SNOW.requestSnowCallCreateApprovalTask(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String,
ROLE_ASSIGNMENT.currentRoleAssignment.enabledFrom as Instant,
ROLE_ASSIGNMENT.currentRoleAssignment.enabledUntil as Instant,
ROLE_ASSIGNMENT.currentRoleAssignment.dimensions as Map,
OBJECT.manager as String,
WORKFLOW.taskInstanceId as String)
def manager = FIND.identity().withAttributesProjection("commonName").withId(OBJECT.manager)
String comments = "Manager approval requested in ServiceNow - " + manager?.commonName
SNOW.requestSnowCallSendComment(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String, comments)
return ActionOutcome.success()
]]></script>
</action>
</initializationActions>
<completeActions>
<action>
<script><![CDATA[
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import com.memority.toolkit.rule.api.ActionOutcome
import _libs_.snow$library.Main
import com.memority.toolkit.rule.api.groovy.transform.Lib
import groovy.transform.Field
@Lib
@Field
final _libs_.snow$library.Main SNOW
LOG.trace("Trigger ServiceNow Process - Workflow 1st step - Complete")
ZoneId settingZone = ZoneId.of((String) SETTINGS.get("idm.tenant.timeZone"))
LocalDateTime dateWithoutTimeZone = Instant.now().atZone(settingZone).toLocalDateTime()
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
def manager = FIND.identity().withAttributesProjection("commonName").withId(OBJECT.manager)
String comments = "Manager " + manager?.commonName + " has approved the request on " + dateWithoutTimeZone.format(formatter)
SNOW.requestSnowCallSendComment(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String, comments)
return ActionOutcome.success()
]]></script>
</action>
</completeActions>
<completeActions>
<action>
<script><![CDATA[
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import com.memority.toolkit.rule.api.ActionOutcome
import _libs_.snow$library.Main
import com.memority.toolkit.rule.api.groovy.transform.Lib
import groovy.transform.Field
ZoneId settingZone = ZoneId.of((String) SETTINGS.get("idm.tenant.timeZone"))
LocalDateTime dateWithoutTimeZone = Instant.now().atZone(settingZone).toLocalDateTime()
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
LOG.trace("callToCompleteTask - dateWithoutTimeZone {}", dateWithoutTimeZone.format(formatter))
@Lib
@Field
final _libs_.snow$library.Main SNOW
String comments = "Memority validation by " + SUBJECT.firstName + " " + SUBJECT.lastName + " on " + dateWithoutTimeZone.format(formatter)
SNOW.requestSnowCallSendComment(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String, comments)
if (SNOW.requestSnowCallState(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String, "3",
"Applicative role successfully assigned by Memority",
"Applicative role successfully assigned by Memority")) {
return ActionOutcome.success()
} else {
return ActionOutcome.failure()
}
]]></script>
</action>
</completeActions>
<rejectActions>
<action>
<script><![CDATA[
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import com.memority.toolkit.rule.api.ActionOutcome
import _libs_.snow$library.Main
import com.memority.toolkit.rule.api.groovy.transform.Lib
import groovy.transform.Field
ZoneId settingZone = ZoneId.of((String) SETTINGS.get("idm.tenant.timeZone"))
LocalDateTime dateWithoutTimeZone = Instant.now().atZone(settingZone).toLocalDateTime()
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
LOG.trace("callToCompleteTask - dateWithoutTimeZone {}", dateWithoutTimeZone.format(formatter))
@Lib
@Field
final _libs_.snow$library.Main SNOW
if (SNOW.requestSnowCallState(ROLE_ASSIGNMENT.fields.serviceNowRitmId as String, "7",
"Applicative Role request rejected by Memority",
"Memority validation has been refused by application owner on " + dateWithoutTimeZone.format(formatter))) {
return ActionOutcome.success()
} else {
return ActionOutcome.failure()
}
]]></script>
</action>
</rejectActions>