diff --git a/Images/http_oneloginjit_1.png b/Images/http_oneloginjit_1.png new file mode 100644 index 0000000..31c487b Binary files /dev/null and b/Images/http_oneloginjit_1.png differ diff --git a/Images/http_oneloginjit_10.png b/Images/http_oneloginjit_10.png new file mode 100644 index 0000000..581246d Binary files /dev/null and b/Images/http_oneloginjit_10.png differ diff --git a/Images/http_oneloginjit_11.png b/Images/http_oneloginjit_11.png new file mode 100644 index 0000000..31c487b Binary files /dev/null and b/Images/http_oneloginjit_11.png differ diff --git a/Images/http_oneloginjit_12.png b/Images/http_oneloginjit_12.png new file mode 100644 index 0000000..d9b60d9 Binary files /dev/null and b/Images/http_oneloginjit_12.png differ diff --git a/Images/http_oneloginjit_13.png b/Images/http_oneloginjit_13.png new file mode 100644 index 0000000..95d0730 Binary files /dev/null and b/Images/http_oneloginjit_13.png differ diff --git a/Images/http_oneloginjit_14.png b/Images/http_oneloginjit_14.png new file mode 100644 index 0000000..c6e87a0 Binary files /dev/null and b/Images/http_oneloginjit_14.png differ diff --git a/Images/http_oneloginjit_15.png b/Images/http_oneloginjit_15.png new file mode 100644 index 0000000..c80f87c Binary files /dev/null and b/Images/http_oneloginjit_15.png differ diff --git a/Images/http_oneloginjit_16.png b/Images/http_oneloginjit_16.png new file mode 100644 index 0000000..a5e444b Binary files /dev/null and b/Images/http_oneloginjit_16.png differ diff --git a/Images/http_oneloginjit_17.png b/Images/http_oneloginjit_17.png new file mode 100644 index 0000000..189fe65 Binary files /dev/null and b/Images/http_oneloginjit_17.png differ diff --git a/Images/http_oneloginjit_18.png b/Images/http_oneloginjit_18.png new file mode 100644 index 0000000..a21a4e7 Binary files /dev/null and b/Images/http_oneloginjit_18.png differ diff --git a/Images/http_oneloginjit_19.png b/Images/http_oneloginjit_19.png new file mode 100644 index 0000000..9622f3c Binary files /dev/null and b/Images/http_oneloginjit_19.png differ diff --git a/Images/http_oneloginjit_2.png b/Images/http_oneloginjit_2.png new file mode 100644 index 0000000..d9b60d9 Binary files /dev/null and b/Images/http_oneloginjit_2.png differ diff --git a/Images/http_oneloginjit_20.png b/Images/http_oneloginjit_20.png new file mode 100644 index 0000000..e7dcea9 Binary files /dev/null and b/Images/http_oneloginjit_20.png differ diff --git a/Images/http_oneloginjit_21.png b/Images/http_oneloginjit_21.png new file mode 100644 index 0000000..b36b051 Binary files /dev/null and b/Images/http_oneloginjit_21.png differ diff --git a/Images/http_oneloginjit_22.png b/Images/http_oneloginjit_22.png new file mode 100644 index 0000000..b086393 Binary files /dev/null and b/Images/http_oneloginjit_22.png differ diff --git a/Images/http_oneloginjit_23.png b/Images/http_oneloginjit_23.png new file mode 100644 index 0000000..fd037f8 Binary files /dev/null and b/Images/http_oneloginjit_23.png differ diff --git a/Images/http_oneloginjit_3.png b/Images/http_oneloginjit_3.png new file mode 100644 index 0000000..a21a4e7 Binary files /dev/null and b/Images/http_oneloginjit_3.png differ diff --git a/Images/http_oneloginjit_4.png b/Images/http_oneloginjit_4.png new file mode 100644 index 0000000..fd037f8 Binary files /dev/null and b/Images/http_oneloginjit_4.png differ diff --git a/Images/http_oneloginjit_5.png b/Images/http_oneloginjit_5.png new file mode 100644 index 0000000..17752f2 Binary files /dev/null and b/Images/http_oneloginjit_5.png differ diff --git a/Images/http_oneloginjit_6.png b/Images/http_oneloginjit_6.png new file mode 100644 index 0000000..fd0bbe8 Binary files /dev/null and b/Images/http_oneloginjit_6.png differ diff --git a/Images/http_oneloginjit_7.png b/Images/http_oneloginjit_7.png new file mode 100644 index 0000000..1511222 Binary files /dev/null and b/Images/http_oneloginjit_7.png differ diff --git a/Images/http_oneloginjit_8.png b/Images/http_oneloginjit_8.png new file mode 100644 index 0000000..17752f2 Binary files /dev/null and b/Images/http_oneloginjit_8.png differ diff --git a/Images/http_oneloginjit_9.png b/Images/http_oneloginjit_9.png new file mode 100644 index 0000000..fd0bbe8 Binary files /dev/null and b/Images/http_oneloginjit_9.png differ diff --git a/SampleScripts/HTTP/OneLogin_GRC_JIT_addon.json b/SampleScripts/HTTP/OneLogin_GRC_JIT_addon.json new file mode 100644 index 0000000..87c2042 --- /dev/null +++ b/SampleScripts/HTTP/OneLogin_GRC_JIT_addon.json @@ -0,0 +1,2934 @@ +{ + "Id": "onelogingrdcjitaddon", + "BackEnd": "Scriptable", + "Meta": { + "Author": "Viktor Varga (One Identity)", + "Description": "This Solution Accelerator connector implements activation of OneLogin Accounts and Role elevation. It is to be used in a PIAM/PIdP use-case where a OneLogin Generic REST Connector manages Assets, Accounts, and Entitlements in Safeguard." + }, + "CheckSystem": { + "Parameters": [ + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Address": { + "Type": "String", + "Required": true + } + } + ], + "Do": [ + { + "Function": { + "Name": "ApiAuth", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "AccessTokenResult" + } + }, + { + "Condition": { + "If": "!AccessTokenResult", + "Then": { + "Do": [ + { + "Return": { + "Value": false + } + } + ] + }, + "Else": { + "Do": [ + { + "Function": { + "Name": "Disconnect", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{AccessToken}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "Disconnected" + } + }, { + "Return": { + "Value": true + } + } + ] + } + } + } + ] + }, + "ChangePassword": { + "Parameters": [ + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "NewPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Address": { + "Type": "String", + "Required": true + } + } + ], + "Do": [ + { + "Log": { + "Text": "ChangePassword does not do anything. A dummy password is set on the Account by OneLogin but in practice these Accounts will only have TOTP configured and used. Do not use the ChangePassword task." + } + }, + { + "Return": { + "Value": false + } + } + ] + }, + "EnableAccount": { + "Parameters": [ + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Address": { + "Type": "String", + "Required": true + } + } + ], + "Do": [ + { + "Try": { + "Do": [ + { + "Function": { + "Name": "ApiAuth", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "AccessTokenResult" + } + }, + { + "Condition": { + "If": "!AccessTokenResult", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] Authentication failed" + } + } + ] + } + } + }, { + "Function": { + "Name": "GetUserId", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "GetUserIdResult" + } + }, { + "Condition": { + "If": "GetUserIdResult == null", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] User Id not found" + } + } + ] + } + } + }, { + "Log": { + "Text": "User Id found for user '%{AccountUsername}%': %{GetUserIdResult}%" + } + }, + { + "Function": { + "Name": "ActivateUser", + "Parameters": [ + "%Address%", + "%GetUserIdResult%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "ActivateUserResult" + } + }, { + "Condition": { + "If": "ActivateUserResult == true", + "Then": { + "Do": [ + { + "Function": { + "Name": "Disconnect", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{AccessToken}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "Disconnected" + } + }, { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] Activating the user was not successful" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + "DisableAccount": { + "Parameters": [ + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Address": { + "Type": "String", + "Required": true + } + } + ], + "Do": [ + { + "Try": { + "Do": [ + { + "Function": { + "Name": "ApiAuth", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "AccessTokenResult" + } + }, + { + "Condition": { + "If": "!AccessTokenResult", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] Authentication failed" + } + } + ] + } + } + }, + { + "Function": { + "Name": "GetUserId", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "GetUserIdResult" + } + }, { + "Condition": { + "If": "GetUserIdResult == null", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] User Id not found" + } + } + ] + } + } + }, + { + "Log": { + "Text": "User Id found for user '%{AccountUsername}%': %{GetUserIdResult}%" + } + }, + { + "Function": { + "Name": "DeactivateUser", + "Parameters": [ + "%Address%", + "%GetUserIdResult%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "DeactivateUserResult" + } + }, { + "Condition": { + "If": "DeactivateUserResult == true", + "Then": { + "Do": [ + { + "Function": { + "Name": "Disconnect", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{AccessToken}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "Disconnected" + } + }, { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] Deactivating the user was not successful" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + "ElevateAccount": { + "Parameters": [ + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "PrivilegeGroupMembership": { + "Type": "Array", + "Required": true + } + }, + { + "RetryIntervalSeconds": { + "Type": "integer", + "Description": "The number of seconds to wait between each retries when checking the completion of activating the user or assigning a role. Default value is 5. Note: there is no maximum iteration configured, if hitting a problem on the OneLogin side, the Elevate task will hang in Pending state.", + "Required": false, + "DefaultValue": 5 + } + } + ], + "Do": [ + { + "Try": { + "Do": [ + { + "SetItem": { + "Name": "Global:RetrySeconds", + "Value": "%{RetryIntervalSeconds}%" + } + }, + { + "Function": { + "Name": "ApiAuth", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "AccessTokenResult" + } + }, + { + "Condition": { + "If": "!AccessTokenResult", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] Authentication failed" + } + } + ] + } + } + }, + { + "Function": { + "Name": "AssignRoles", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{PrivilegeGroupMembership}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "AssignRolesResult" + } + }, { + "Condition": { + "If": "AssignRolesResult == true", + "Then": { + "Do": [ + { + "Function": { + "Name": "Disconnect", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{AccessToken}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "Disconnected" + } + }, { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] Assigning roles to the user failed" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + "DemoteAccount": { + "Parameters": [ + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "PrivilegeGroupMembership": { + "Type": "Array", + "Required": true + } + }, + { + "RetryIntervalSeconds": { + "Type": "integer", + "Description": "The number of seconds to wait between each retries when checking the completion of deassigning a role. Default value is 5. Note: there is no maximum iteration configured, if hitting a problem on the OneLogin side, the Demote task will hang in Pending state.", + "Required": false, + "DefaultValue": 5 + } + } + ], + "Do": [ + { + "Try": { + "Do": [ + { + "SetItem": { + "Name": "Global:RetrySeconds", + "Value": "%{RetryIntervalSeconds}%" + } + }, + { + "Function": { + "Name": "ApiAuth", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "AccessTokenResult" + } + }, + { + "Condition": { + "If": "!AccessTokenResult", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] Authentication failed" + } + } + ] + } + } + }, + { + "Function": { + "Name": "DeassignRoles", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{PrivilegeGroupMembership}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "DeassignRolesResult" + } + }, { + "Condition": { + "If": "DeassignRolesResult == true", + "Then": { + "Do": [ + { + "Function": { + "Name": "Disconnect", + "Parameters": [ + "%Address%", + "%FuncUsername%", + "%FuncPassword%", + "%{AccessToken}%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "Disconnected" + } + }, { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] Deassigning roles from the user failed" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + "Functions": [ + { + "Name": "DeassignRoles", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "PrivilegeGroupMembership": { + "Type": "Array", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "Try": { + "Do": [ + { + "Function": { + "Name": "GetUserId", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "UserId" + } + }, { + "Condition": { + "If": "UserId == null", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] User Id not found" + } + } + ] + } + } + }, + { + "Log": { + "Text": "User Id found for user '%{AccountUsername}%': %{UserId}%" + } + },{ + "SetItem": { + "Name": "RoleDeassignmentFailure", + "Value": false + } + }, { + "ForEach": { + "CollectionName": "PrivilegeGroupMembership", + "ElementName": "role", + "Body": { + "Do": [ + { + "Function": { + "Name": "GetRoleId", + "Parameters": [ + "%Address%", + "%role%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "RoleId" + } + }, { + "Condition": { + "If": "RoleId != null", + "Then": { + "Do": [ + { + "Log": { + "Text": "Role Id found for role '%role%': %{RoleId}%" + } + }, + { + "Status": { + "Type": "Changing", + "Percent": 70, + "Message": { + "Name": "DemotingAccount", + "Parameters": [ "%{AccountUsername}%", "%{role}%" ] + } + } + }, + , + { + "Function": { + "Name": "DeleteUserFromRole", + "Parameters": [ + "%Address%", + "%RoleId%", + "%UserId%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%", + "%{AccountUsername}%" + ], + "ResultVariable": "DeleteUserFromRoleResult" + } + }, { + "Condition": { + "If": "DeleteUserFromRoleResult != true", + "Then": { + "Do": [ + { + "Log": { + "Text": "User '%{AccountUsername}%' could not be removed from role '%{role}%', looking up next configured role." + } + },{ + "Status": { + "Type": "Changing", + "Percent": 80, + "Message": { + "Name": "AccountMembershipDemoteFailed", + "Parameters": [ "%{AccountUsername}%", "%{role}%" ] + } + } + }, { + "SetItem": { + "Name": "RoleDeassignmentFailure", + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 80, + "Message": { + "Name": "AccountMembershipDemoted", + "Parameters": [ "%{AccountUsername}%", "%{role}%" ] + } + } + + } + ] + } + } + } + ] + }, + "Else": { + "Do": [ + { + "Log": { + "Text": "Role '%role%' not found, looking up next configured role." + } + }, { + "SetItem": { + "Name": "RoleDeassignmentFailure", + "Value": true + } + } + ] + } + } + } + ] + } + } + }, { + "Condition": { + "If": "RoleDeassignmentFailure == true", + "Then": { + "Do": [ + { + "Log": { + "Text": "At least one of the configured roles could not be removed from the user '%{AccountUsername}%'" + } + } + ] + } + } + }, { + "Return": { + "Value": true + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "AssignRoles", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "PrivilegeGroupMembership": { + "Type": "Array", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "Try": { + "Do": [ + + { + "Function": { + "Name": "GetUserId", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "UserId" + } + }, { + "Condition": { + "If": "UserId == null", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] User Id not found" + } + } + ] + } + } + }, + { + "Log": { + "Text": "User Id found for user '%{AccountUsername}%': %{UserId}%" + } + },{ + "Function": { + "Name": "IsUserActive", + "Parameters": [ + "%Address%", + "%AccountUsername%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "IsUserActiveResult" + } + },{ + "Condition": { + "If": "!IsUserActiveResult", + "Then": { + "Do": [ + { + "Throw": { + "Value": "[Error] User is inactive, roles don't get assigned to avoid subsequent provisioning errors inside OneLogin" + } + } + ] + } + } + }, + { + "Log": { + "Text": "User is active, assigning roles." + } + },{ + "SetItem": { + "Name": "RoleAssignmentFailure", + "Value": false + } + }, { + "ForEach": { + "CollectionName": "PrivilegeGroupMembership", + "ElementName": "role", + "Body": { + "Do": [ + { + "Function": { + "Name": "GetRoleId", + "Parameters": [ + "%Address%", + "%role%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%" + ], + "ResultVariable": "RoleId" + } + }, { + "Condition": { + "If": "RoleId != null", + "Then": { + "Do": [ + { + "Log": { + "Text": "Role Id found for role '%role%': %{RoleId}%" + } + }, + { + "Status": { + "Type": "Changing", + "Percent": 70, + "Message": { + "Name": "ElevatingAccount", + "Parameters": [ "%{AccountUsername}%", "%{role}%" ] + } + } + }, + { + "Function": { + "Name": "AddUserToRole", + "Parameters": [ + "%Address%", + "%RoleId%", + "%UserId%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%", + "%{AccountUsername}%" + ], + "ResultVariable": "AddUserToRoleResult" + } + }, { + "Condition": { + "If": "AddUserToRoleResult != true", + "Then": { + "Do": [ + { + "Log": { + "Text": "User '%{AccountUsername}%' could not be added to role '%{role}%', looking up next configured role." + } + },{ + "Status": { + "Type": "Changing", + "Percent": 80, + "Message": { + "Name": "AccountMembershipElevateFailed", + "Parameters": [ "%{AccountUsername}%", "%{role}%" ] + } + } + }, { + "SetItem": { + "Name": "RoleAssignmentFailure", + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + + { + "Status": { + "Type": "Changing", + "Percent": 80, + "Message": { + "Name": "AccountMembershipElevated", + "Parameters": [ "%{AccountUsername}%", "%{role}%" ] + } + } + } + + ] + } + } + } + ] + }, + "Else": { + "Do": [ + { + "Log": { + "Text": "Role '%role%' not found, looking up next configured role." + } + }, { + "SetItem": { + "Name": "RoleAssignmentFailure", + "Value": true + } + } + ] + } + } + } + ] + } + } + }, { + "Condition": { + "If": "RoleAssignmentFailure == true", + "Then": { + "Do": [ + { + "Log": { + "Text": "At least one of the configured roles could not be assigned to the user '%{AccountUsername}%'" + } + } + ] + } + } + }, { + "Return": { + "Value": true + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "ActivateUser", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "UserId": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "SetItem": { + "Name": "Content", + "Value": "{\"status\": 1}" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, + { + "Try": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 70, + "Message": { + "Name": "EnablingAccount", + "Parameters": [ "%{AccountUsername}%" ] + } + } + }, + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "PUT", + "Url": "api/2/users/%UserId%", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + "ContentType": "application/json", + "ContentObjectName": "Content" + } + } + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "GetUserResponseJson" + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "GetUserResponseJson.state == 1", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] User activation failed" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "DeactivateUser", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "UserId": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "SetItem": { + "Name": "Content", + "Value": "{\"status\": 2}" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, { + "Try": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 70, + "Message": { + "Name": "DisablingAccount", + "Parameters": [ "%{AccountUsername}%" ] + } + } + }, + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "PUT", + "Url": "api/2/users/%UserId%", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + "ContentType": "application/json", + "ContentObjectName": "Content" + } + } + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "GetUserResponseJson" + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "GetUserResponseJson.status == 2", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] User deactivation failed" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "DeleteUserFromRole", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "RoleId": { + "Type": "String", + "Required": true + } + }, + { + "UserId": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Username": { + "Type": "String", + "Required": true + } + } + ], + "Do": [ + { + "SetItem": { + "Name": "Content", + "Value": "[%UserId%]" + } + }, + { + "Log": { + "Text": "List of UserIds to delete from the role: %{Content}%" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, { + "Try": { + "Do": [ + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "DELETE", + "Url": "api/2/roles/%{RoleId}%/users", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + "ContentType": "application/json", + "ContentObjectName": "Content" + } + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "SystemResponse.StatusCode == 204", + "Then": { + "Do": [ + { + "Function": { + "Name": "IsUserInRole", + "Parameters": [ + "%Address%", + "%RoleId%", + "%Username%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%", + "Deassign" + ], + "ResultVariable": "IsUserInRoleResult" + } + },{ + "Condition": { + "If": "IsUserInRoleResult == false", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Return": { + "Value": false + } + } + ] + } + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] %{SystemResponse.StatusCode}%" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "AddUserToRole", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "RoleId": { + "Type": "String", + "Required": true + } + }, + { + "UserId": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Username": { + "Type": "String", + "Required": true + } + } + ], + "Do": [ + { + "SetItem": { + "Name": "Content", + "Value": "[%UserId%]" + } + }, + { + "Log": { + "Text": "List of UserIds to add to the role: %{Content}%" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, { + "Try": { + "Do": [ + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "POST", + "Url": "api/2/roles/%{RoleId}%/users", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + "ContentType": "application/json", + "ContentObjectName": "Content" + } + } + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "GetRoleAssignResponseJson" + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "SystemResponse.StatusCode == 200 && GetRoleAssignResponseJson[0].id == UserId", + "Then": { + "Do": [ + { + "Function": { + "Name": "IsUserInRole", + "Parameters": [ + "%Address%", + "%RoleId%", + "%Username%", + "%AccessToken%", + "%{SkipServerCertValidation}%", + "%{UseSsl}%", + "Assign" + ], + "ResultVariable": "IsUserInRoleResult" + } + },{ + "Condition": { + "If": "IsUserInRoleResult == true", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Return": { + "Value": false + } + } + ] + } + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] %{SystemResponse.StatusCode}%, Response: %{GetRoleAssignResponseJson}%" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "IsUserInRole", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "RoleId": { + "Type": "String", + "Required": true + } + }, + { + "UserName": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "Task": { + "Type": "string", + "Required": true + } + } + ], + "Do": [ + { + "Log": { + "Text": "Checking if role with id: %RoleId% is assigned to user %UserName%" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + },{ + "Try": { + "Do": [ + { + "For": { + "Condition": true, + "Body": { + "Do": [ + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "GET", + "Url": "api/2/roles/%{RoleId}%/users?name=%{Username}%", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%" + } + },{ + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "ListRoleUsersResponseJson" + } + },{ + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + },{ + "Condition": { + "If": "SystemResponse.StatusCode == 200", + "Then": { + "Do": [ + { + "Condition": { + "If": "Task == 'Assign' && ListRoleUsersResponseJson.count == 1", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + } + } + }, { + "Condition": { + "If": "Task == 'Deassign' && ListRoleUsersResponseJson.count == 0", + "Then": { + "Do": [ + { + "Return": { + "Value": false + } + } + ] + } + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] %{SystemResponse.StatusCode}%, Response: %{ListRoleUsersResponseJson}%" + } + } + ] + } + } + }, { + "Status": { + "Type": "Changing", + "Percent": 75, + "Message": { + "Name": "LookingUpGroup", + "Parameters": [ "%{Role}%, whether the role assignment/deassignment completed" ] + } + } + }, { + "Wait": { "Seconds": "%{RetrySeconds}%" } + } + + ] + } + } + } + ], + "Catch": [ + { + "Condition": { + "If": "Task == 'Assign'", + "Then": { + "Do": [ + { + "Return": { + "Value": false + } + } + ] + }, + "Else": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + } + } + } + ] + } + } + ] + }, + { + "Name": "IsUserActive", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, + { + "Try": { + "Do": [ + { + "For": { + "Condition": true, + "Body": { + "Do": [ + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "GET", + "Url": "api/2/users?username=%AccountUsername%", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + } + }, + + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "GetUserIdResponseJson" + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "GetUserIdResponseJson[0].status == 1", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + } + } + },{ + "Status": { + "Type": "Changing", + "Percent": 45, + "Message": { + "Name": "LookingUpUser", + "Parameters": [ "%{AccountUsername}%, which must be active in OneLogin before assigning roles" ] + } + } + }, { + "Wait": { "Seconds": "%{RetrySeconds}%" } + } + + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": null + } + } + ] + } + } + ] + }, + { + "Name": "GetRoleId", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "Role": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, { + "Try": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 50, + "Message": { + "Name": "LookingUpGroup", + "Parameters": [ "%{Role}%" ] + } + } + }, + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "GET", + "Url": "api/2/roles?name=%{Role}%", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + } + } + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "GetRoleIdResponseJson" + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "GetRoleIdResponseJson.count != 0", + "Then": { + "Do": [ + { + "Return": { + "Value": "%{GetRoleIdResponseJson[0].id}%" + } + } + ] + }, + "Else": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 55, + "Message": { + "Name": "GroupNotFound", + "Parameters": [ "%{Role}%" ] + } + } + }, + { + "Throw": { + "Value": "[Error] Role not found: %{Role}%" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": null + } + } + ] + + } + } + ] + }, + { + "Name": "GetUserId", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "AccountUsername": { + "Type": "String", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + ], + "Do": [ + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "Headers": { + "RequestObjectName": "SystemRequest", + "AddHeaders": { + "Authorization": "Bearer %AccessToken%" + } + } + }, + { + "Try": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 30, + "Message": { + "Name": "LookingUpUser", + "Parameters": [ "%{AccountUsername}%" ] + } + } + }, + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "GET", + "Url": "api/2/users?username=%AccountUsername%", + "SubstitutionInUrl": true, + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + } + }, + + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "GetUserIdResponseJson" + } + }, + { + "Log": { + "Text": "%{SystemResponse.StatusCode}%" + } + }, + { + "Condition": { + "If": "GetUserIdResponseJson.count != 0", + "Then": { + "Do": [ + { + "Return": { + "Value": "%{GetUserIdResponseJson[0].id}%" + } + } + ] + }, + "Else": { + "Do": [ + { + "Status": { + "Type": "Changing", + "Percent": 35, + "Message": { + "Name": "AccountNotFoundOnly", + "Parameters": [ "%{AccountUsername}%" ] + } + } + }, + { + "Throw": { + "Value": "[Error] User not found: %AccountUsername%" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": null + } + } + ] + } + } + ] + }, + { + "Name": "ApiAuth", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + } + + ], + "Do": [ + { + "SetItem": { + "Name": "Content", + "Value": "{\"grant_type\":\"client_credentials\"}" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "HttpAuth": { + "RequestObjectName": "SystemRequest", + "Type": "Basic", + "Credentials": { + "Login": "%FuncUsername%", + "Password": "%FuncPassword%" + } + } + }, + { + "Try": { + "Do": [ + { + "Status": { + "Type": "Connecting", + "Percent": 10, + "Message": { + "Name": "AssetConnecting", + "Parameters": [ "%{Address}%" ] + } + } + }, + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "POST", + "Url": "auth/oauth2/v2/token", + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + "ContentType": "application/json", + "ContentObjectName": "Content" + }, + "IsSecret": true + } + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "AuthResponseJson", + "ContainsSecret": true + } + }, + { + "Condition": { + "If": "SystemResponse.StatusCode == 200", + "Then": { + "Do": [ + { + "Status": { + "Type": "Connecting", + "Percent": 15, + "Message": { + "Name": "AssetConnected", + "Parameters": [ "%{Address}%" ] + } + } + },{ + "SetItem": { + "Name": "Global:AccessToken", + "Value": "%{AuthResponseJson.access_token}%", + "IsSecret": true + } + }, + { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Status": { + "Type": "Failure", + "Percent": 90, + "Message": { + "Name": "AssetConnectFailedWithReason", + "Parameters": [ "%{Address}%", "%{AuthResponseJson.message}%" ] + } + } + }, + { + "Throw": { + "Value": "[Error] %{SystemResponse.StatusCode}%" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": false + } + } + ] + } + } + ] + }, + { + "Name": "Disconnect", + "Parameters": [ + { + "Address": { + "Type": "String", + "Required": true + } + }, + { + "FuncUsername": { + "Type": "String", + "Required": true + } + }, + { + "FuncPassword": { + "Type": "Secret", + "Required": true + } + }, + { + "AccessToken": { + "Type": "Secret", + "Required": true + } + }, + { + "SkipServerCertValidation": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + { + "UseSsl": { + "Type": "boolean", + "Required": false, + "DefaultValue": true + } + }, + ], + "Do": [ + { + "SetItem": { + "Name": "Content", + "Value": "{\"access_token\":\"%{AccessToken}%\"}" + } + }, + { + "Condition": { + "If": "UseSsl", + "Then": { + "Do": [ + { + "BaseAddress": { + "Address": "https://%Address%" + } + } + ] + }, + "Else": { + "Do": [ + { + "BaseAddress": { + "Address": "http://%Address%" + } + } + ] + } + } + }, + { + "NewHttpRequest": { + "ObjectName": "SystemRequest" + } + }, + { + "HttpAuth": { + "RequestObjectName": "SystemRequest", + "Type": "Basic", + "Credentials": { + "Login": "%FuncUsername%", + "Password": "%FuncPassword%" + } + } + }, + { + "Try": { + "Do": [ + { + "Request": { + "RequestObjectName": "SystemRequest", + "ResponseObjectName": "SystemResponse", + "Verb": "POST", + "Url": "auth/oauth2/revoke", + "IgnoreServerCertAuthentication": "%SkipServerCertValidation%", + "Content": { + "ContentType": "application/json", + "ContentObjectName": "Content" + } + } + }, + { + "ExtractJsonObject": { + "JsonObjectName": "SystemResponse", + "Name": "AuthResponseJson" + } + }, + { + "Condition": { + "If": "SystemResponse.StatusCode == 200 && AuthResponseJson.status.error == false", + "Then": { + "Do": [ + { + "Return": { + "Value": true + } + } + ] + }, + "Else": { + "Do": [ + { + "Throw": { + "Value": "[Error] %{SystemResponse.StatusCode}%, Message: %{AuthResponseJson.status.message}%" + } + } + ] + } + } + } + ], + "Catch": [ + { + "Return": { + "Value": null + } + } + ] + } + } + ] + } + ] +} diff --git a/SampleScripts/HTTP/README.md b/SampleScripts/HTTP/README.md new file mode 100644 index 0000000..36d252e --- /dev/null +++ b/SampleScripts/HTTP/README.md @@ -0,0 +1,169 @@ +# Guide to SafeguardCustomPlatform - HTTP Scripts + +## Table of Contents +[OneLogin_GRC_JIT_addon](#onelogin_grc_jit_addon) +[Okta_WithDiscoveryAndGroupMembershipRestore](#okta_withdiscoveryandgroupmembershiprestore) + +## OneLogin_GRC_JIT_addon + +This Solution Accelerator addon was created to implement JIT role elevation for OneLogin until it is available out-of-box in Safeguard. + +### How does it work +The OneLogin_GRC_JIT_addon implements Restore/Suspend and Elevate/Demote functions. The ChangePassword function is also defined as it's a must-have for Custom Platform scripts, however it does nothing (only logs that it does nothing). + +Changing the password is: + * Either not necessary as the Account will only store a TOTP code, configured automatically by OneLogin. + * Or if the base privileged Account is created & managed by the out-of-box Starling Connect connector for OneLogin, that will be managing the password. + +The addon will be the Platform Types for additionally created Assets in Safeguard, each separate Asset representing a Role in OneLogin: + +![SafeguardCustomPlatform](../../Images/http_oneloginjit_1.png) + +Each privileged OneLogin User having permission to elevate into that Role needs to have an Account object created within the Asset representing the Role. + +![SafeguardCustomPlatform](../../Images/http_oneloginjit_2.png) + +(Note: the Assets could also represent groups of Roles.) + +In SPP the Account shows up on the Access Request portal only if it has the password set. Hence each of these Accounts need to have a dummy password configured. + +The Users need to have Entitlements / Access Request Policies to the base privileged OneLogin Account as well as for the individual Accounts representing the Roles. This requires creating an Entitlement per User as at the time of writing this reamde (in SPP v8.2) the Accounts of neither the OneLogin platform Asset, nor the custom platform Assets can be added as Linked Accounts. + +![SafeguardCustomPlatform](../../Images/http_oneloginjit_3.png) + +When the User is requesting access to the privileged OneLogin Account, at the same time the desired Roles should also be selected. The privileged OneLogin Account will have the Roles assigned, once the subsequent access requests representing the Roles become available (after Pending Restore state). + +![SafeguardCustomPlatform](../../Images/http_oneloginjit_4.png) + +#### Demo video + +Watch demo video + + +### About enabling/disabling the OneLogin user via a Safeguard Access Request +JIT enable/disable or elevate/demote tasks are implemented on the OneLogin_GRC_JIT_addon Asset/Accounts. + +There are two typical setups: + +1. When the Account objects are managed by OneLogin, all of them stored under a OneLogin_GRC_JIT_addon Asset: + * In this scenario enable the *Suspend account when checked in* function under Password Profile > Change Password policy for the main privileged account. Do not configure JIT groups for this Accounts. + * Configure the JIT group elevation for the Accounts on the Assets representing the Roles. Do not enable the *Suspend account when checked in* function for these Accounts. + * Once the main -adm account is checked out, it gets activated. The Roles get assigned depending on which corresponding Asset is requested along with the main Account. Whilst the main Account is checked out, the User can request further Roles, or check any of them in, demoting that Role in OneLogin. + +2. When the main Account is managed by the out-of-box Starling Connect connector for OneLogin, and only the Assets representing a Role are configured with the OneLogin_GRC_JIT_addon platform type: + * In this case both the *Suspend account when checked in* function and the JIT groups should be configured on each of the Asset/Accounts representing a OneLogin Role. + * Despite the main Account is checked out, it is still inactive in OneLogin. It will only be activated once an Asset/Account representing a Role gets checked out too, as the OneLogin_GRC_JIT_addon is the connector implementing JIT activation and elevation. + * In case the Account is assigned to multiple Roles via requesting multiple Asset/Accounts representing a OneLogin Role, the User should not check in any of the Roles before finishing all activities because checking one of these requests in will not only demote the requested Role, but also deactivate the Account inside OneLogin. + +### Configuration +It can be configured with two different approaches: +* **Accounts are created by OneLogin through its Generic REST Connector.** + * In this case the default Starling Connect connector for OneLogin is not used. Asset and Account objects are created by OneLogin, as well as the Entitlements and the Access Request Policies. + * Every Role which you want to make available for the privileged OneLogin account is mapped to an Asset/Account object in Safeguard, automatically by OneLogin. Corresponding Entitlements and Access Request policies are also created by OneLogin. + * OneLogin is automatically registering the TOTP for the privileged OneLogin account, as well as vaulting it in SPP (the TOTP seed is never exposed, users are technically forced to use the vaulted credential). +* **The base Account is created via the Discovery feature of the Starling Connect connector for OneLogin or in any other way, like via AD (in case the accounts are synchronized into OneLogin from AD).** + * In this case the Asset/Account objects representing the Role/User pairs must be created manually, or via 3rd party automation, so as the Entitlements and Access Request Policies. + * The TOTP seed for the base privileged OneLogin Account must be vaulted manually, or via 3rd party automation. + +#### Configuration: Accounts are created by OneLogin through its Generic REST Connector + + 1. Create the API Credential in OneLogin with Manage All permissions. This will be used as the service account for the Assets in Safeguard. + 2. Upload the custom platform script to SPP. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_5.png) + + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_6.png) + + + + 3. Configure the OneLogin REST Connector for Safeguard and let it do the heavy-lifting Safeguard: Assets, Accounts, Entitlements, Access Request Policies, etc. Search the **One Identity Safeguard (OneLogin Account Onboarding)** and **One Identity Safeguard (OneLogin-Virtual AssetAccounts for JIT elevation)** connectors in the OneLogin Application Catalog. + + + + +With this, the User is now able to raise Access Requests in Safeguard which enables the Account in OneLogin and assigns the requested Roles. + +#### Configuration: The base Account is created via the Discovery feature of the Starling Connect connector for OneLogin, or from Active Directory + +1. Onboard the OneLogin Accounts to SPP in the preferred way, for example using the out-of-box Starling Connect connector for OneLogin. This is going to be the main Account object holding the actual secrets of the privileged OneLogin Account. Feel free to manage these Accounts as needed. The Accounts may also originate from AD so that we can configure RDP Apps. In case the status and password of the OneLogin account is in sync with AD, then you can also manage the corresponding AD accounts in SPP. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_7.png) + + +2. Create the API Credential in OneLogin with Manage All permissions. This will be used as the service account for the Assets in Safeguard. + +3. Upload the custom platform script to SPP. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_8.png) + + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_9.png) + +4. Create an Asset for each OneLogin Role, or combination of Roles, that the User has permission to elevate into. The platform type is the OneLogin_GRC_JIT_addon. + + As the Roles look like in OneLogin: + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_10.png) + + + As the corresponding Assets look like in Safeguard: + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_11.png) + + +5. Create an Account on each of the these Assets with the same name as the original OneLogin Account. For example as shown on one of the Assets representing a OneLogin Role: + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_12.png) + + + Make sure that a dummy password is set on each of these Accounts otherwise these won't show up when raising an Access Request (note: the OneLogin_GRC_JIT_addon does not change the password of the Account, even if the Task is successfully completed). + + The Password Profile of these Accounts should do nothing with the password. No Check / No Change. + +6. Configure the corresponding Role name in the JIT configuration of these Accounts. For example as shown on one of the Assets representing a OneLogin Role: + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_13.png) + +7. If the base OneLogin Account is managed through the originating AD Account, then create an Entitlement for password or pession (RDP App) access with the Users' Linked Accounts. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_14.png) + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_15.png) + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_16.png) + +Don't forget creating the virtual asset to connect to: + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_17.png) + +Otherwise the Access Request Policy will be created in the per-user Entitlement together with the access to the virtual JIT Assets. + +8. Create an Entitlement per each User. This is required as at the time of writing this readme (in SPP v8.2) the Accounts of a Custom Platfom Asset can't be configured as Linked Accounts. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_18.png) + +9. Create a Dynamic Account Group for all the Role-specific Accounts of the User. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_19.png) + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_20.png) + + +10. Create a password Access Request Policy into the Entitlement. In the Scope of this Access Request Policy, add the Dynamic Account Group of the User. + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_21.png) + + ![SafeguardCustomPlatform](../../Images/http_oneloginjit_22.png) + + +With this, the User is now able to raise Access Requests in Safeguard which enables the Account in OneLogin and assigns the requested Roles. + +![SafeguardCustomPlatform](../../Images/http_oneloginjit_23.png) + + + +## Okta_WithDiscoveryAndGroupMembershipRestore +This script had been implemented before the JIT Elevation functionality was available in Safeguard. Hence the configuration is cumbersome and does not work as JIT is confgured. + +The script should be reworked a bit to reflect the out-of-box JIT configuration approach. diff --git a/SampleScripts/SafeguardCustomPlatform_TestTool.ps1 b/SampleScripts/SafeguardCustomPlatform_TestTool.ps1 new file mode 100644 index 0000000..4befce7 --- /dev/null +++ b/SampleScripts/SafeguardCustomPlatform_TestTool.ps1 @@ -0,0 +1,59 @@ +# This tiny script uploads the CustomPlatform connector script to SPP which is useful for testing. +# It requires the Custom Platform created earlier with a base script. +# It currently supports: Restore|Elevate|Demote|Suspend + +# Base parameters +$appliance = "" +$username = "" +$provider = "" + +# Script Upload parameters +$customPlatformScriptPath = "" +$customPlatformName = "" + + +# Test parameters +$uploadScript = $true +$accountid = +$restore = $true +$elevate = $false +$demote = $false +$suspend = $true + +if (-not($AccessToken)) { + $AccessToken = Connect-Safeguard -Insecure -Appliance $appliance -Username $username -IdentityProvider $provider -NoSessionVariable +} + +if ($uploadScript) { + + $customPlatform = Get-SafeguardPlatform -AccessToken $AccessToken -Appliance $appliance -Fields "id" -Insecure -Platform $customPlatformName + + $script = Get-Content $customPlatformScriptPath + $bytesScript = [System.Text.Encoding]::UTF8.GetBytes($script) + $base64Script = [Convert]::ToBase64String($bytesScript) + + echo "Uploading script to SPP..." + + $scriptupdate = Invoke-SafeguardMethod -Method Put -RelativeUrl $("Platforms/" + $customPlatform.Id + "/Script") -Service Core -AccessToken $AccessToken -Appliance $appliance -Body $base64Script + } + +if ($restore) { + $tasklog = Invoke-SafeguardMethod -Method Post -RelativeUrl $("AssetAccounts/" + $accountid + "/RestoreAccount?extendedLogging=true") -Service Core -AccessToken $AccessToken -Appliance $appliance + write-host "Restore task log id: " $tasklog.id + LogTaskLog $tasklog.id +} + +if ($elevate) { + $tasklog = Invoke-SafeguardMethod -Method Post -RelativeUrl $("AssetAccounts/" + $accountid + "/ElevateAccount?extendedLogging=true") -Service Core -AccessToken $AccessToken -Appliance $appliance + write-host "Elevate task log id: " $tasklog.id +} + +if ($demote) { + $tasklog = Invoke-SafeguardMethod -Method Post -RelativeUrl $("AssetAccounts/" + $accountid + "/DemoteAccount?extendedLogging=true") -Service Core -AccessToken $AccessToken -Appliance $appliance + write-host "Demote task log id: " $tasklog.id +} + +if ($suspend) { + $tasklog = Invoke-SafeguardMethod -Method Post -RelativeUrl $("AssetAccounts/" + $accountid + "/SuspendAccount?extendedLogging=true") -Service Core -AccessToken $AccessToken -Appliance $appliance + write-host "Suspend task log id: " $tasklog.id +} diff --git a/Videos/http_oneloginjit_1.mp4 b/Videos/http_oneloginjit_1.mp4 new file mode 100644 index 0000000..a049221 Binary files /dev/null and b/Videos/http_oneloginjit_1.mp4 differ