{"revision":"c10276e953456835cdbb1f3a60d58ae1980be353","document":{"id":41233,"path":"platform-security/identity/handling-umapped-fields.md","title":"Handling unmapped fields","bundle":null,"doc_type":null,"release":"australia","body":"\n# Handling unmapped fields\n\nYou can handle unmapped fields in SCIM customization in different ways.\n\nDuring SCIM customization, the fields that are not part of the `sys_user` and `sys_user_group` tables can be mapped by performing the following functions.\n\n## Customize SCIM \\(Create or Update\\)\n\nYou can create or update the SCIM Client.\n\n-   The SCIM admin can add custom scripts in the **onBefore** and **onAfter** scripts for fields that are not mapped in ETL Definition or RTE.\n-   The SCIM admin can override RTE Mappings by adding custom scripts in the **onBefore** and **onAfter** scripts.\n-   You can invoke a scriptable API in the RTE **onBefore** or **onAfter** scripts to access incoming request and perform transformations on other tables, lists, and unmapped attributes.\n-   You can use the **sn\\_auth.SCIM2Util.getScimProviderCustomizationContext\\(\\)** method to provide the SCIM request context that contains the **scimResource** object. The **scimResource** in context represents the following in each operation:\n    -   **POST**: The SCIM resource sent in the request payload.\n    -   **PUT**: The current SCIM resource from database replaced with the SCIM resource sent in thee request payload.\n    -   **PATCH**: The current SCIM resource from the database after performing the patch operations.\n\nThe following is an example of an **onAfter** script.\n\n```\n(function onAfter(source, target, importLog) {\n\n    var ctx = sn_auth.SCIM2Util.getScimProviderCustomizationContext();\n    gs.info(\"scim context ee: \" + JSON.stringify(ctx.scimResource));\n\n    var roles = ctx.scimResource.roles;\n    if(roles) {\n        var removingRolesGR = new GlideRecord(\"sys_user_has_role\");\n        removingRolesGR.addQuery(\"user\", target.sys_user[0].sys_id);\n        removingRolesGR.query();\n        removingRolesGR.deleteMultiple();\n\n    for (var i = 0; i < roles.length; i++) {\n        var addingRolesGR = new GlideRecord(\"sys_user_has_role\");\n        addingRolesGR.setValue(\"user\", target.sys_user[0].sys_id);\n        addingRolesGR.setValue(\"role\", roles[i].value);\n        addingRolesGR.setValue(\"state\", \"active\");\n        addingRolesGR.insert();\n        }\n        }\n        var customUserExtn = new global.SCIMProviderCustomization().getCustomExtensionUrn('User');\n        var salary = ctx.scimResource[customUserExtn].salary;\n        if (salary) {\n            var gr = new GlideRecord(\"u_user_salary\");\n            gr.addQuery(\"user\", target.sys_user[0].sys_id);\n            gr.query();\n            if (gr.next()) {\n                gr.setValue(\"salary\", salary);\n                gs.info(\"scim update: \" + gr.update());\n            } else {\n            gr.setValue(\"salary\", salary);\n            gr.setValue(\"user\", target.sys_user[0].sys_id);\n            gr.insert();\n            }\n           }\n\n})(source, target, importLog);\n```\n\n## Customize SCIM response\n\nFor the GET API calls, any response back to the SCIM client can be customized using the script by extending the **SCIMProviderCustomization** script.\n\nWhile extending the script, the author can override the **customizeUserResponse** and **customizeGroupResponse** methods to modify the responses for User and Group resources.\n\nThe **com.snc.integration.scim2.provider.customization.script.id** property enables the SCIM plugin to use the script that should be used for response customization.\n\nThe following is an example of extending the base script.\n\n```\nvar SCIMCustomizationScript = Class.create();\nSCIMCustomizationScript.prototype = Object.extendsObject(SCIMProviderCustomization, {\n    initialize: function() {\n        SCIMProviderCustomization.prototype.initialize.call(this);\n    },\n    customizeUserResponse: function(context) {\n        try {\n            var rolesGR = new GlideRecord(\"sys_user_has_role\");\n            rolesGR.addQuery(\"user\", context.scimResource.id);\n            rolesGR.query();\n            var i = 0;\n            context.scimResource.roles = [];\n            while (rolesGR.next()) {\n                context.scimResource.roles[i] = {\n                    display: rolesGR.getElement('role.name').getValue(),\n                    value: rolesGR.getElement('role.sys_id').getValue()\n                };\n                i++;\n            }\n            var userGR = new GlideRecord(\"u_user_salary\");\n            userGR.addQuery(\"user\", context.scimResource.id);\n            userGR.query();\n            if (userGR.next()) {\n                var salary = userGR.getValue(\"salary\");\n                if (salary) {\n                    var customExtensionValue = SCIMProviderCustomization.prototype.getCustomExtensionNodeValue.call(this, \"User\", context);\n                    customExtensionValue.salary = salary;\n                    SCIMProviderCustomization.prototype.setCustomExtensionNodeValue.call(this, \"User\", context, customExtensionValue);\n                }\n            }\n        } catch (ex) {\n            gs.error(\"err: \" + ex);\n        }\n        return context;\n    },\n    customizeGroupResponse: function(context) {\n        return context;\n    },\n    type: 'SCIMCustomizationScript'\n});\n```\n\n**Note:**\n\n-   The parameter that the **customizeUserResponse** and **customizeGroupResponse** methods contain is a context object with one attribute called **scimResource**. This attribute has all the attributes of a user or group resource object.\n-   A customized script include can only be created and viewed by the admin.\n-   If a user or group resource is modified, then you must return the context back.\n-   If there are no modification of any attribute in the resource object, then set the **com.snc.integration.scim2.provider.customization.script.id** to empty or return as null.\n-   If certain attributes are persisted through the **onAfter** script, they must be populated with database values in the **scimResource** object inside the customized script. This action is required so that the system can do the following:\n    -   To get the correct **scimResource** object in **onAfter** scripts during the PUT and PATCH operation.\n    -   To include the attributes that persisted through the **onAfter** script in the response back to the client.\n\n## Helper functions\n\nThe following are some of the helper functions for SCIM customization. These functions enable you to fetch or set different types of information.\n\n|Function|Purpose|\n|--------|-------|\n|**SCIMProviderCustomization.prototype.getCustomExtensionUrn.call\\(this, \"User\"\\);**|Fetch the value of custom extension schema.|\n|**SCIMProviderCustomization.prototype.getServiceNowExtensionUrn.call\\(this, \"User\"\\);**|Fetch the value of the ServiceNow extension schema.|\n|**SCIMProviderCustomization.prototype.getCustomExtensionNodeValue.call\\(this, \"User\", context\\);**|Fetch the custom schema node from the response.|\n|**SCIMProviderCustomization.prototype.getServiceNowExtensionNodeValue.call\\(this, \"User\", context\\);**|Fetch the ServiceNow schema node from the response|\n|**SCIMProviderCustomization.prototype.setCustomExtensionNodeValue.call\\(this, \"User\", context, customExtensionValue\\);**|Set the custom schema node in the response.|\n\nThe following is an example of using the helper function:\n\n```\nvar customExtensionUrn = \nSCIMProviderCustomization.prototype.getCustomExtensionUrn.call(this, \"User\"); \nvar customExtensionValue = \nSCIMProviderCustomization.prototype.getCustomExtensionNodeValue.call(this, \"User\", context); \ncustomExtensionValue.age = \"18\";\nSCIMProviderCustomization.prototype.setCustomExtensionNodeValue call(this, \"User\", context, customExtensionValue); \n```\n\n**Note:** RTE supports setting data in tables other than the sys\\_user and sys\\_user\\_group tables.\n\n"}}