From 1a37f9f69836ddc049ff5d160877cb11bea9ebd2 Mon Sep 17 00:00:00 2001 From: MartinStoyanoff <37848972+MartinStoyanoff@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:20:10 +0300 Subject: [PATCH 1/2] Create readme.md --- Script Includes/SCIM Payload Generator/readme.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Script Includes/SCIM Payload Generator/readme.md diff --git a/Script Includes/SCIM Payload Generator/readme.md b/Script Includes/SCIM Payload Generator/readme.md new file mode 100644 index 0000000000..627a619bd5 --- /dev/null +++ b/Script Includes/SCIM Payload Generator/readme.md @@ -0,0 +1,14 @@ +A script include to generate payload for testing SCIM-based integration. + +The script covers as specific case where user is added/removed to user groups based on the values in the 'entitlements' object of the SCIM payload. + +The main function accepts 3 parameters: + +groupsToRemove - will check all groups of which the user is currently member and will randomly remove the membership of groups equal to the number passed to the parameter +groupsToAdd - will check all groups to which the is not currently a member and will randomly create membershis for groups equal to the number passed to the parameter +newGroupsToCreate - will create new groups and add the user to them. Group names are concatenation of a prefix and randomly generated string. +The end result of the function is a JSON object that can be directly passed as a payload while testing via REST API explorer or Postman. + +Usage: var groupsToRemove = 2; var groupsToAdd = 1; var newGroupsToCreate = 3; + +var generator = new GenerateSCIMPayload(); var scimPayload = generator.generateEntitlements(jamesVittoloSysID, groupsToRemove, groupsToAdd, newGroupsToCreate); gs.info(JSON.stringify(scimPayload)); From a3cd3e1928157a497c71d231a320027971fca63f Mon Sep 17 00:00:00 2001 From: MartinStoyanoff <37848972+MartinStoyanoff@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:20:34 +0300 Subject: [PATCH 2/2] Create GenerateSCIMPayload.js --- .../GenerateSCIMPayload.js | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 Script Includes/SCIM Payload Generator/GenerateSCIMPayload.js diff --git a/Script Includes/SCIM Payload Generator/GenerateSCIMPayload.js b/Script Includes/SCIM Payload Generator/GenerateSCIMPayload.js new file mode 100644 index 0000000000..415cd4a56c --- /dev/null +++ b/Script Includes/SCIM Payload Generator/GenerateSCIMPayload.js @@ -0,0 +1,183 @@ +var GenerateSCIMPayload = Class.create(); +GenerateSCIMPayload.prototype = { + initialize: function() { + }, + + // Function to generate a random string for new group names + generateRandomString: function(length) { + var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + var result = ''; + for (var i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * characters.length)); + } + return "test group " + result; + }, + + // Function to retrieve the groups where the user is a member + getUserGroups: function(userSysId) { + var groupNames = []; + var grGroupMember = new GlideRecord('sys_user_grmember'); // Group Member table + grGroupMember.addQuery('user', userSysId); // Get groups of the user + grGroupMember.query(); + + while (grGroupMember.next()) { + var groupName = grGroupMember.group.getDisplayValue(); // Get group name + groupNames.push({ + name: groupName + }); + } + return groupNames; + }, + + // Function to retrieve groups where the user is NOT a member + getGroupsNotMemberOf: function(userSysId) { + var groupNames = []; + var grGroup = new GlideRecord('sys_user_group'); // Group table + + // Subquery to find groups the user is a member of + var subquery = new GlideRecord('sys_user_grmember'); + subquery.addQuery('user', userSysId); + subquery.query(); + + var groupIds = []; + while (subquery.next()) { + groupIds.push(subquery.group.sys_id.toString()); + } + + // Query for groups where the user is NOT a member + grGroup.addQuery('sys_id', 'NOT IN', groupIds); + grGroup.query(); + + while (grGroup.next()) { + groupNames.push({ + name: grGroup.name.toString() // Only store the group name + }); + } + + return groupNames; + }, + + // Function to generate entitlements for current user groups, excluding a set number + generateEntitlementsFromCurrentGroups: function(userSysId, groupsToRemove) { + var currentGroups = this.getUserGroups(userSysId); + var countToKeep = Math.max(0, currentGroups.length - groupsToRemove); // Ensure non-negative value + var keptGroups = currentGroups.slice(0, countToKeep); // Keep the first groups, up to the count + + var entitlements = []; + for (var i = 0; i < keptGroups.length; i++) { + entitlements.push({ + "value": keptGroups[i].name // Add kept group names to entitlements + }); + } + return entitlements; + }, + + // Function to generate entitlements for groups the user will "join" + generateEntitlementsForNewGroups: function(userSysId, groupsToAdd) { + var availableGroups = this.getGroupsNotMemberOf(userSysId); + var entitlements = []; + + for (var i = 0; i < groupsToAdd; i++) { + if (availableGroups.length > 0) { + var randomIndex = Math.floor(Math.random() * availableGroups.length); + var selectedGroup = availableGroups.splice(randomIndex, 1)[0]; + entitlements.push({ + "value": selectedGroup.name // Add selected group names to entitlements + }); + } + } + + return entitlements; + }, + + // Main function to generate entitlements + generateEntitlements: function(userSysId, groupsToRemove, groupsToAdd, newGroupsToCreate) { + // Initialize the object + var userObj = { + "schemas": [ + "urn:ietf:params:scim:schemas:extension:servicenow:2.0:User", + "urn:ietf:params:scim:schemas:core:2.0:User", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" + ], + "id": userSysId, + "meta": { + "resourceType": "User", + "created": "2006-07-11T21:16:15Z", + "lastModified": new Date().toISOString(), // Current date for lastModified + "location": "https://.service-now.com/api/now/scim/Users/" + userSysId //to be updated with your instance name + }, + "userName": "jvittolo", // Replace with actual user name if needed + "name": { + "familyName": "Vittolo", + "givenName": "Jamessss" + }, + "displayName": "Jamessss Vittolo", + "title": "VP, Client Services", + "active": true, + "emails": [ + { + "value": "jvittolo@example.com", + "type": "work" + } + ], + "entitlements": [] + }; + + // Step 1: Generate entitlements for existing groups (excluding some) + var currentGroupEntitlements = this.generateEntitlementsFromCurrentGroups(userSysId, groupsToRemove); + userObj.entitlements = userObj.entitlements.concat(currentGroupEntitlements); + + // Step 2: Generate entitlements for new groups the user will "join" + var newGroupEntitlements = this.generateEntitlementsForNewGroups(userSysId, groupsToAdd); + userObj.entitlements = userObj.entitlements.concat(newGroupEntitlements); + + // Step 3: Create new groups (non-existing) and add to entitlements + for (var j = 0; j < newGroupsToCreate; j++) { + var newGroupName = this.generateRandomString(12); + userObj.entitlements.push({ + "value": newGroupName // Add new group names directly to entitlements + }); + } + + // Return the modified object + return userObj; + }, + + // Function to simulate removal of all group memberships + removeAllGroupMemberships: function(userSysId) { + // Initialize the object with all original properties + var userObj = { + "schemas": [ + "urn:ietf:params:scim:schemas:extension:servicenow:2.0:User", + "urn:ietf:params:scim:schemas:core:2.0:User", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" + ], + "id": userSysId, + "meta": { + "resourceType": "User", + "created": "2006-07-11T21:16:15Z", + "lastModified": new Date().toISOString(), // Current date for lastModified + "location": "https://.service-now.com/api/now/scim/Users/" + userSysId + }, + "userName": "jvittolo", // Replace with actual user name if needed + "name": { + "familyName": "Vittolo", + "givenName": "Jamessss" + }, + "displayName": "Jamessss Vittolo", + "title": "VP, Client Services", + "active": true, + "emails": [ + { + "value": "jvittolo@example.com", + "type": "work" + } + ], + "entitlements": [] // Empty entitlements array + }; + + return userObj; // Return the full object with empty entitlements + }, + + type: 'GenerateSCIMPayload' +};