From b6e9ca7217003866e59c6b735e5fffb8ba015097 Mon Sep 17 00:00:00 2001 From: Garima Garg <211866541+ggarima01@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:25:10 -0700 Subject: [PATCH] Update Standard Logic App workflow templates (June 2026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Updates the Standard Logic App workflow templates and orchestrator parameters. ### Changed files | File | Change | |------|--------| | StandardLogicApp/GroupTests_Workflow.json | Updated | | StandardLogicApp/Orchestrator_Parameters.json | Updated | | StandardLogicApp/Orchestrator_Workflow.json | Updated | | StandardLogicApp/SCIMTests_Workflow.json | Updated | | StandardLogicApp/UserTests_Workflow.json | Updated | | StandardLogicApp/VERSION | Bumped 5.0 → 6.0 | ### VERSION bump Workflow JSON files changed → automatic VERSION bump from **5.0** to **6.0**. ### Notes - Initialization_Workflow.json was byte-identical to upstream and skipped. - CRLF normalized to LF for GroupTests and UserTests workflow files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../StandardLogicApp/GroupTests_Workflow.json | 8505 +++++++++-------- .../Orchestrator_Parameters.json | 53 +- .../Orchestrator_Workflow.json | 12 +- .../StandardLogicApp/SCIMTests_Workflow.json | 539 +- .../StandardLogicApp/UserTests_Workflow.json | 271 +- .../StandardLogicApp/VERSION | 2 +- 6 files changed, 5489 insertions(+), 3893 deletions(-) diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json index 14803d69..7c01b1ac 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json @@ -1,3953 +1,4796 @@ { - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "triggers": { - "manual": { - "type": "Request", - "kind": "Http", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "triggers": { + "manual": { + "type": "Request", + "kind": "Http", + "inputs": { + "schema": { + "type": "object", + "properties": { + "initializationData": { + "type": "object", + "properties": { + "syncJobId": { + "type": "string" + }, + "testUserNames": { + "type": "object" + }, + "testGroupNames": { + "type": "object" + }, + "appRoles": { + "type": "object" + }, + "userAppRole": { + "type": "array" + }, + "schema": { + "type": "object" + } + } + }, + "EnabledTests": { + "type": "string" + }, + "parentRunId": { + "type": "string" + } + } + } + } + } + }, + "actions": { + "Response_Immediate": { + "runAfter": { + "Initialize_All_Group_Test_Variables": [ + "Succeeded" + ] + }, + "type": "Response", + "kind": "Http", + "inputs": { + "statusCode": 202, + "body": { + "workflowRunId": "@workflow().run.name", + "workflowName": "@workflow().name", + "status": "Accepted", + "message": "GroupTests workflow started. Tests are running asynchronously." + } + } + }, + "Initialize_All_Group_Test_Variables": { + "runAfter": {}, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "CreateGroupFailedActionName", + "type": "string", + "value": "" + }, + { + "name": "CreateGroupFailedActionResponse", + "type": "Object", + "value": {} + }, + { + "name": "CreateGroupScopeExecutionStatus", + "type": "string", + "value": "InProgress" + }, + { + "name": "CreateGroupTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "provisioningLogsResult": "", + "scimCheckResult": "", + "errorDetails": { + "provisioningLogs": "", + "scimCheck": "" + } + } + }, + { + "name": "UpdateGroupFailedActionName", + "type": "string", + "value": "" + }, + { + "name": "UpdateGroupFailedActionResponse", + "type": "Object", + "value": {} + }, + { + "name": "UpdateGroupScopeExecutionStatus", + "type": "string", + "value": "InProgress" + }, + { + "name": "UpdateGroupTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "provisioningLogsResult": "", + "scimCheckResult": "", + "errorDetails": { + "provisioningLogs": "", + "scimCheck": "" + } + } + }, + { + "name": "DeleteGroupFailedActionName", + "type": "string", + "value": "" + }, + { + "name": "DeleteGroupFailedActionResponse", + "type": "Object", + "value": {} + }, + { + "name": "DeleteGroupScopeExecutionStatus", + "type": "string", + "value": "InProgress" + }, + { + "name": "DeleteGroupTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "provisioningLogsResult": "", + "scimCheckResult": "", + "errorDetails": { + "provisioningLogs": "", + "scimCheck": "" + } + } + }, + { + "name": "AddMemberFailedActionName", + "type": "string", + "value": "" + }, + { + "name": "AddMemberFailedActionResponse", + "type": "Object", + "value": {} + }, + { + "name": "AddMemberScopeExecutionStatus", + "type": "string", + "value": "InProgress" + }, + { + "name": "AddMemberTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "provisioningLogsResult": "", + "scimCheckResult": "", + "errorDetails": { + "provisioningLogs": "", + "scimCheck": "" + } + } + }, + { + "name": "RemoveMemberFailedActionName", + "type": "string", + "value": "" + }, + { + "name": "RemoveMemberFailedActionResponse", + "type": "Object", + "value": {} + }, + { + "name": "RemoveMemberScopeExecutionStatus", + "type": "string", + "value": "InProgress" + }, + { + "name": "RemoveMemberTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "provisioningLogsResult": "", + "scimCheckResult": "", + "errorDetails": { + "provisioningLogs": "", + "scimCheck": "" + } + } + } + ] + } + }, + "Initialize_PODGroupTestOutputs": { + "runAfter": { + "Initialize_All_Group_Test_Variables": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "PODGroupTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "errorDetails": {} + } + } + ] + } + }, + "Initialize_RestoreGroupTestVariables": { + "runAfter": { + "Initialize_PODGroupTestOutputs": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "restoreEntraGroupId", + "type": "string", + "value": "" + }, + { + "name": "restoreGroupAppRoleAssignmentId", + "type": "string", + "value": "" + }, + { + "name": "RestoreGroupTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "summary": null, + "detailedResults": [], + "errorDetails": { + "summary": null + } + } + } + ] + } + }, + "Initialize_RestoreGroupFailedActionName": { + "runAfter": { + "Initialize_RestoreGroupTestVariables": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "RestoreGroupFailedActionName", + "type": "string", + "value": "" + } + ] + } + }, + "Initialize_RestoreGroupFailedActionResponse": { + "runAfter": { + "Initialize_RestoreGroupFailedActionName": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "RestoreGroupFailedActionResponse", + "type": "Object", + "value": {} + } + ] + } + }, + "Initialize_RestoreGroupScopeExecutionStatus": { + "runAfter": { + "Initialize_RestoreGroupFailedActionResponse": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "RestoreGroupScopeExecutionStatus", + "type": "string", + "value": "InProgress" + } + ] + } + }, + "GroupTests_Scope": { + "actions": { + "Create_Group_Test": { + "actions": { + "Create_Group_Test_Actions": { + "actions": { + "Create_Group_Initial_Verify_Group_Exists": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['createGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Create_Group_Create_Group_Graph": { + "runAfter": { + "Create_Group_Initial_Verify_Group_Exists": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['createGroup']}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{triggerBody()?['initializationData']?['testGroupNames']?['createGroupNickname']}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Create_Group_Assign_Group_To_App": { + "runAfter": { + "Delay_After_Create_Group": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('Create_Group_Create_Group_Graph')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "DoUntil_Poll_Create_Group": { + "actions": { + "Create_Group_Query_Create_Group": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['createGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delay_Create_Group_15s": { + "runAfter": { + "Create_Group_Query_Create_Group": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Create_Group_Assign_Group_To_App": [ + "Succeeded" + ] + }, + "expression": "@greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "DoUntil_Poll_Group_Provisioning_Logs": { + "actions": { + "Verify_Group_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Create_Group_Create_Group_Graph')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Delay_Group_Provisioning_Logs_15s": { + "runAfter": { + "Verify_Group_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "DoUntil_Poll_Create_Group": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "expression": "@greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0)", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + }, + "Delay_After_Create_Group": { + "runAfter": { + "Create_Group_Create_Group_Graph": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 1, + "unit": "Minute" + } + } + } + }, + "type": "Scope" + }, + "Capture_Failed_Group_Action_Details": { + "actions": { + "Get_Failed_Group_Actions": { + "type": "Compose", + "inputs": "@result('Create_Group_Test_Actions')" + }, + "Filter_Failed_Group_Actions": { + "runAfter": { + "Get_Failed_Group_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_Group_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_Failed_Group_Action_Name": { + "runAfter": { + "Filter_Failed_Group_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "CreateGroupFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_Group_Actions')), 0), first(body('Filter_Failed_Group_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_Failed_Group_Action_Response": { + "runAfter": { + "Set_Failed_Group_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "CreateGroupFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_Group_Actions')), 0), coalesce(first(body('Filter_Failed_Group_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_Create_Group_Test_Status_Failed": { + "runAfter": { + "Set_Failed_Group_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "CreateGroupScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Create_Group_Test_Actions": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_Create_Group_Test_Status_Success": { + "runAfter": { + "Create_Group_Test_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", "inputs": { - "schema": { - "type": "object", - "properties": { - "initializationData": { - "type": "object", - "properties": { - "syncJobId": { - "type": "string" - }, - "testUserNames": { - "type": "object" - }, - "testGroupNames": { - "type": "object" - }, - "appRoles": { - "type": "object" - }, - "userAppRole": { - "type": "array" - }, - "schema": { - "type": "object" - } + "name": "CreateGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Create_Group_Test_Analyze_Provisioning_Results": { + "runAfter": { + "Create_Group_Test_Actions": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_Failed_Group_Action_Details": [ + "Succeeded", + "Skipped" + ], + "Set_Create_Group_Test_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", + "provisioningResult": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Verify_Group_Provisioning_Logs: ', coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Verify_Group_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('CreateGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('CreateGroupFailedActionResponse'))", + "overallResult": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0), false), 'success', 'Create_Group_Query_Create_Group: Group not found on SCIM server after provisioning'), concat('Failed Action: ', variables('CreateGroupFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after provisioning. SCIM query returned ', string(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]')))), ' resources (expected >= 1). totalResults: ', string(coalesce(body('Create_Group_Query_Create_Group')?['totalResults'], 'N/A')))), concat('Scope execution failed. Failed action: ', variables('CreateGroupFailedActionName')))" + } + }, + "Set_CreateGroup_Output_Variables": { + "actions": { + "Set_CreateGroupTestOutputs": { + "type": "SetVariable", + "inputs": { + "name": "CreateGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Create_Group_Test_Analyze_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } + } + } + }, + "runAfter": { + "Create_Group_Test_Analyze_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + }, + "Delete_Created_Group": { + "runAfter": { + "Set_CreateGroup_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Create_Group_Create_Group_Graph')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + } + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] + }, + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Create_Group_Test" + ] + } + ] + } + ] + }, + "type": "If" + }, + "Update_Group_Test": { + "actions": { + "Update_Group_Test_Actions": { + "actions": { + "Update_Group_Verify_Creation_And_Provisioning": { + "actions": { + "Update_Group_Initial_Verify_Group_Exists": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Update_Group_Create_Group_Graph": { + "runAfter": { + "Update_Group_Initial_Verify_Group_Exists": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['updateGroup']}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{triggerBody()?['initializationData']?['testGroupNames']?['updateGroupNickname']}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Update_Group_Assign_To_App": { + "runAfter": { + "Delay_After_Update_Group_Create": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('Update_Group_Create_Group_Graph')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Update_Group_DoUntil_Wait_For_Creation": { + "actions": { + "Update_Group_Check_Group_Create": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Update_Group_Delay_Creation_15s": { + "runAfter": { + "Update_Group_Check_Group_Create": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Update_Group_Assign_To_App": [ + "Succeeded" + ] + }, + "expression": "@greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Update_Group_DoUntil_Poll_Create_Provisioning": { + "actions": { + "Update_Group_Verify_Create_Provisioning": { + "type": "Http", + "inputs": { + "uri": "@concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Update_Group_Create_Group_Graph')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Update_Group_Delay_Create_Provisioning_15s": { + "runAfter": { + "Update_Group_Verify_Create_Provisioning": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Update_Group_DoUntil_Wait_For_Creation": [ + "Succeeded" + ] + }, + "expression": "@greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0)", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + }, + "Delay_After_Update_Group_Create": { + "runAfter": { + "Update_Group_Create_Group_Graph": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 1, + "unit": "Minute" + } + } + } + }, + "type": "Scope" + }, + "Capture_Update_Group_CreatePhase_Failed": { + "actions": { + "Get_Failed_CreatePhase_Group_Actions": { + "type": "Compose", + "inputs": "@result('Update_Group_Verify_Creation_And_Provisioning')" + }, + "Filter_Failed_CreatePhase_Group_Actions": { + "runAfter": { + "Get_Failed_CreatePhase_Group_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_CreatePhase_Group_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_UpdateGroup_CreatePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_CreatePhase_Group_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_CreatePhase_Group_Actions')), 0), first(body('Filter_Failed_CreatePhase_Group_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_UpdateGroup_CreatePhase_Failed_Action_Response": { + "runAfter": { + "Set_UpdateGroup_CreatePhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_CreatePhase_Group_Actions')), 0), coalesce(first(body('Filter_Failed_CreatePhase_Group_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_UpdateGroup_CreatePhase_Status_Failed": { + "runAfter": { + "Set_UpdateGroup_CreatePhase_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Update_Group_Verify_Creation_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_UpdateGroup_CreatePhase_Status_Success": { + "runAfter": { + "Update_Group_Verify_Creation_And_Provisioning": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Update_Group_Analyze_Create_Provisioning": { + "runAfter": { + "Update_Group_Verify_Creation_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_Update_Group_CreatePhase_Failed": [ + "Succeeded", + "Skipped" + ], + "Set_UpdateGroup_CreatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", + "provisioningResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Update_Group_Verify_Create_Provisioning: ', coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Update_Group_Verify_Create_Provisioning: NO_LOGS_FOUND'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), equals(toLower(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('UpdateGroupFailedActionResponse'))", + "overallResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0), false), 'success', 'Update_Group_Check_Group_Create: Group not found on SCIM server after provisioning'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after provisioning. SCIM query returned ', string(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]')))), ' resources (expected >= 1). totalResults: ', string(coalesce(body('Update_Group_Check_Group_Create')?['totalResults'], 'N/A')))), concat('Scope execution failed. Failed action: ', variables('UpdateGroupFailedActionName')))" + } + }, + "Set_UpdateGroup_CreatePhase_Output_Variables": { + "actions": { + "Set_UpdateGroupTestOutputs_CreatePhase": { + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Update_Group_Analyze_Create_Provisioning')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } + } + } + }, + "runAfter": { + "Update_Group_Analyze_Create_Provisioning": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + }, + "Update_Group_Check_Create_Phase_Status": { + "actions": { + "Update_Group_Verify_Update_And_Provisioning": { + "actions": { + "Update_Group_Query_Group_By_Id": { + "type": "Http", + "inputs": { + "uri": "@concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '%22')", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Update_Group_Update_Group_Attributes": { + "runAfter": { + "Update_Group_Query_Group_By_Id": [ + "Succeeded", + "Failed" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Update_Group_Create_Group_Graph')?['id']}", + "method": "PATCH", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{concat(triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '-Modified')}", + "description": "Updated Test Group Description" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Update_Group_DoUntil_Wait_For_Updates": { + "actions": { + "Update_Group_Query_Group_By_Id_After_Attributes_Update": { + "type": "Http", + "inputs": { + "uri": "@concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', concat(triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '-Modified'), '%22')", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Update_Group_Delay_Update_15s": { + "runAfter": { + "Update_Group_Query_Group_By_Id_After_Attributes_Update": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Update_Group_Update_Group_Attributes": [ + "Succeeded" + ] + }, + "expression": "@and(greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0), contains(string(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')), '-Modified'))", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Update_Group_DoUntil_Poll_Update_Provisioning": { + "actions": { + "Update_Group_Verify_Update_Provisioning": { + "type": "Http", + "inputs": { + "uri": "@concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Update_Group_Create_Group_Graph')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27&$top=1&$orderby=activityDateTime%20desc')", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Update_Group_Delay_Update_Provisioning_15s": { + "runAfter": { + "Update_Group_Verify_Update_Provisioning": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Update_Group_DoUntil_Wait_For_Updates": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "expression": "@greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0)", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + } + }, + "type": "Scope" + }, + "Capture_Update_Group_UpdatePhase_Failed": { + "actions": { + "Get_Failed_UpdatePhase_Group_Actions": { + "type": "Compose", + "inputs": "@result('Update_Group_Verify_Update_And_Provisioning')" + }, + "Filter_Failed_UpdatePhase_Group_Actions": { + "runAfter": { + "Get_Failed_UpdatePhase_Group_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_UpdatePhase_Group_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_UpdateGroup_UpdatePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_UpdatePhase_Group_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_UpdatePhase_Group_Actions')), 0), first(body('Filter_Failed_UpdatePhase_Group_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_UpdateGroup_UpdatePhase_Failed_Action_Response": { + "runAfter": { + "Set_UpdateGroup_UpdatePhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_UpdatePhase_Group_Actions')), 0), coalesce(first(body('Filter_Failed_UpdatePhase_Group_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_UpdateGroup_UpdatePhase_Status_Failed": { + "runAfter": { + "Set_UpdateGroup_UpdatePhase_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Update_Group_Verify_Update_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_UpdateGroup_UpdatePhase_Status_Success": { + "runAfter": { + "Update_Group_Verify_Update_And_Provisioning": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Update_Group_Analyze_Update_Provisioning": { + "runAfter": { + "Update_Group_Verify_Update_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_Update_Group_UpdatePhase_Failed": [ + "Succeeded", + "Skipped" + ], + "Set_UpdateGroup_UpdatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", + "provisioningResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Update_Group_Verify_Update_Provisioning: ', coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Update_Group_Verify_Update_Provisioning: NO_LOGS_FOUND'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), equals(toLower(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('UpdateGroupFailedActionResponse'))", + "overallResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0), 'success', 'Update_Group_Query_Group_By_Id_After_Attributes_Update: Group not found on SCIM server after update'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0), null, 'SCIM verification failed: Group not found on SCIM server after update provisioning'), concat('Scope execution failed. Failed action: ', variables('UpdateGroupFailedActionName')))" + } + }, + "Set_UpdateGroup_UpdatePhase_Output_Variables": { + "actions": { + "Set_UpdateGroupTestOutputs_UpdatePhase": { + "type": "SetVariable", + "inputs": { + "name": "UpdateGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Update Phase] ', coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], '')), concat('FAILED - [Update Phase] Provisioning: ', coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Update_Group_Analyze_Update_Provisioning')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } + } + } + }, + "runAfter": { + "Update_Group_Analyze_Update_Provisioning": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + } + }, + "runAfter": { + "Set_UpdateGroup_CreatePhase_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@toLower(variables('UpdateGroupTestOutputs')['overallResult'])", + "passed" + ] + } + ] + }, + "type": "If" + }, + "Update_Group_Cleanup_Delete": { + "runAfter": { + "Update_Group_Check_Create_Phase_Status": [ + "Succeeded", + "Failed", + "TimedOut", + "Skipped" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Update_Group_Create_Group_Graph')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + } + }, + "type": "Scope" + } + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] + }, + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Update_Group_Test" + ] + } + ] + } + ] + }, + "type": "If" + }, + "Delete_Group_Test": { + "actions": { + "Delete_Group_Test_Actions": { + "actions": { + "Delete_Group_Verify_Creation_And_Provisioning": { + "actions": { + "Delete_Step1_Check_Group_Exists": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delete_Step2_Create_Group": { + "runAfter": { + "Delete_Step1_Check_Group_Exists": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup']}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{replace(triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '-', '')}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Delete_Group_Assign_App_Role": { + "runAfter": { + "Delay_After_Delete_Group_Create": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", + "method": "POST", + "body": { + "principalId": "@{body('Delete_Step2_Create_Group')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Delete_DoUntil_Wait_For_Group_Creation": { + "actions": { + "Delete_Step3_Fetch_Group_By_Filter": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delete_Group_Delay_Creation_15s": { + "runAfter": { + "Delete_Step3_Fetch_Group_By_Filter": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Delete_Group_Assign_App_Role": [ + "Succeeded" + ] + }, + "expression": "@greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Delete_Group_DoUntil_Poll_Create_Provisioning_Logs": { + "actions": { + "Delete_Group_Verify_Create_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Delete_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Delete_Group_Delay_Create_Provisioning_Logs_15s": { + "runAfter": { + "Delete_Group_Verify_Create_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Delete_DoUntil_Wait_For_Group_Creation": [ + "Succeeded" + ] + }, + "expression": "@greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0)", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + }, + "Delay_After_Delete_Group_Create": { + "runAfter": { + "Delete_Step2_Create_Group": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 1, + "unit": "Minute" + } + } + } + }, + "type": "Scope" + }, + "Capture_DeleteGroup_CreatePhase_Failed_Actions": { + "actions": { + "Get_Failed_DeleteGroup_CreatePhase_Actions": { + "type": "Compose", + "inputs": "@result('Delete_Group_Verify_Creation_And_Provisioning')" + }, + "Filter_Failed_DeleteGroup_CreatePhase_Actions": { + "runAfter": { + "Get_Failed_DeleteGroup_CreatePhase_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_DeleteGroup_CreatePhase_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_DeleteGroup_CreatePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_DeleteGroup_CreatePhase_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_DeleteGroup_CreatePhase_Actions')), 0), first(body('Filter_Failed_DeleteGroup_CreatePhase_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_DeleteGroup_CreatePhase_Failed_Action_Response": { + "runAfter": { + "Set_DeleteGroup_CreatePhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_DeleteGroup_CreatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_DeleteGroup_CreatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_DeleteGroup_CreatePhase_Status_Failed": { + "runAfter": { + "Set_DeleteGroup_CreatePhase_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Delete_Group_Verify_Creation_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_DeleteGroup_CreatePhase_Status_Success": { + "runAfter": { + "Delete_Group_Verify_Creation_And_Provisioning": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Delete_Group_Analyze_Create_Provisioning_Results": { + "runAfter": { + "Delete_Group_Verify_Creation_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_DeleteGroup_CreatePhase_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "Set_DeleteGroup_CreatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", + "provisioningResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Delete_Group_Verify_Create_Provisioning_Logs: ', coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Delete_Group_Verify_Create_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('DeleteGroupFailedActionResponse'))", + "overallResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0), false), 'success', 'Delete_Step3_Fetch_Group_By_Filter: Group not found on SCIM server after provisioning'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after provisioning. SCIM query returned ', string(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]')))), ' resources (expected >= 1). totalResults: ', string(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['totalResults'], 'N/A')))), concat('Scope execution failed. Failed action: ', variables('DeleteGroupFailedActionName')))" + } + }, + "Set_DeleteGroup_CreatePhase_Output_Variables": { + "actions": { + "Set_DeleteGroupTestOutputs_CreatePhase": { + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } + } + } + }, + "runAfter": { + "Delete_Group_Analyze_Create_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + }, + "Delete_Group_Check_Create_Phase_Status": { + "actions": { + "Delete_Group_Verify_Delete_And_Provisioning": { + "actions": { + "Delete_Step4_Query_Group_By_Id": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delete_Step5_Delete_Group_By_Id": { + "runAfter": { + "Delete_Step4_Query_Group_By_Id": [ + "Succeeded", + "Failed" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Delete_Step2_Create_Group')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Delete_DoUntil_Wait_For_Group_Deletion": { + "actions": { + "Delete_Step6_Check_Group_Exists_Final": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delete_Group_Delay_Final_15s": { + "runAfter": { + "Delete_Step6_Check_Group_Exists_Final": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Delete_Step5_Delete_Group_By_Id": [ + "Succeeded" + ] + }, + "expression": "@equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Delete_Group_DoUntil_Poll_Delete_Provisioning_Logs": { + "actions": { + "Delete_Group_Verify_Delete_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Delete_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Delete%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Delete_Group_Delay_Delete_Provisioning_Logs_15s": { + "runAfter": { + "Delete_Group_Verify_Delete_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } } + } + }, + "runAfter": { + "Delete_DoUntil_Wait_For_Group_Deletion": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "expression": "@greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0)", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + } + }, + "type": "Scope" + }, + "Capture_DeleteGroup_DeletePhase_Failed_Actions": { + "actions": { + "Get_Failed_DeleteGroup_DeletePhase_Actions": { + "type": "Compose", + "inputs": "@result('Delete_Group_Verify_Delete_And_Provisioning')" + }, + "Filter_Failed_DeleteGroup_DeletePhase_Actions": { + "runAfter": { + "Get_Failed_DeleteGroup_DeletePhase_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_DeleteGroup_DeletePhase_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_DeleteGroup_DeletePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_DeleteGroup_DeletePhase_Actions": [ + "Succeeded" + ] }, - "EnabledTests": { - "type": "string" + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_DeleteGroup_DeletePhase_Actions')), 0), first(body('Filter_Failed_DeleteGroup_DeletePhase_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_DeleteGroup_DeletePhase_Failed_Action_Response": { + "runAfter": { + "Set_DeleteGroup_DeletePhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_DeleteGroup_DeletePhase_Actions')), 0), coalesce(first(body('Filter_Failed_DeleteGroup_DeletePhase_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_DeleteGroup_DeletePhase_Status_Failed": { + "runAfter": { + "Set_DeleteGroup_DeletePhase_Failed_Action_Response": [ + "Succeeded" + ] }, - "parentRunId": { - "type": "string" + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Delete_Group_Verify_Delete_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_DeleteGroup_DeletePhase_Status_Success": { + "runAfter": { + "Delete_Group_Verify_Delete_And_Provisioning": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Delete_Group_Analyze_Delete_Provisioning_Results": { + "runAfter": { + "Delete_Group_Verify_Delete_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_DeleteGroup_DeletePhase_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "Set_DeleteGroup_DeletePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", + "provisioningResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', if(equals(toLower(coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'skipped'), 'Delete provisioning was skipped by the engine. Group deprovisioning cannot be skipped - the connector objectMapping flowTypes must include Delete', concat('Delete provisioning log status: ', coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN')))), 'Delete_Group_Verify_Delete_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('DeleteGroupFailedActionResponse'))", + "overallResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0), 'success', 'Delete_Step6_Check_Group_Exists_Final: Group still exists on SCIM server after deletion'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0), null, concat('SCIM verification failed: Group still exists on SCIM server after deletion. Resources count: ', string(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('DeleteGroupFailedActionName')))" + } + }, + "Set_DeleteGroup_Output_Variables": { + "actions": { + "Set_DeleteGroupTestOutputs_DeletePhase": { + "type": "SetVariable", + "inputs": { + "name": "DeleteGroupTestOutputs", + "value": { + "result": "@if(and(contains(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Delete Phase] ', coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Delete Phase] Provisioning: ', coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } } + } + }, + "runAfter": { + "Delete_Group_Analyze_Delete_Provisioning_Results": [ + "Succeeded" + ] + }, + "type": "Scope" + } + }, + "runAfter": { + "Set_DeleteGroup_CreatePhase_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@toLower(variables('DeleteGroupTestOutputs')['overallResult'])", + "passed" + ] } + ] + }, + "type": "If" + } + }, + "type": "Scope" + } + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] + }, + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Delete_Group_Test" + ] } + ] } - } - }, - "actions": { - "Response_Immediate": { - "runAfter": { - "Initialize_All_Group_Test_Variables": [ + ] + }, + "type": "If" + }, + "Group_Update_Add_Member_Test": { + "actions": { + "Group_Update_Add_Member_Test_Actions": { + "actions": { + "Add_Member_Verify_Creation_And_Provisioning": { + "actions": { + "Add_DoUntil_Wait_For_Initial_Sync": { + "actions": { + "Add_Step4_Check_Group_And_User": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Add_Step4_Check_User": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Users?filter=userName%20eq%20%22', coalesce(triggerBody()?['initializationData']?['testUserNames']?['memberUser1'], ''), '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Add_Delay_Initial_15s": { + "runAfter": { + "Add_Step4_Check_Group_And_User": [ + "Succeeded", + "Failed" + ], + "Add_Step4_Check_User": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Add_Assign_Group_To_App": [ + "Succeeded" + ] + }, + "expression": "@and(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0))", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Add_Member_DoUntil_Poll_Group_Create_Provisioning_Logs": { + "actions": { + "Add_Member_Verify_Group_Create_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Add_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Member_Delay_Group_Create_Provisioning_Logs_15s": { + "runAfter": { + "Add_Member_Verify_Group_Create_Provisioning_Logs": [ + "Succeeded", + "Failed" + ], + "Add_Member_Verify_User_Create_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + }, + "Add_Member_Verify_User_Create_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Add_Step3_Create_Member_User')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + } + }, + "runAfter": { + "Add_DoUntil_Wait_For_Initial_Sync": [ + "Succeeded" + ] + }, + "expression": "@and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0))", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + }, + "Add_Assign_Group_To_App": { + "runAfter": { + "Delay_Before_Add_Group_AppRole": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('Add_Step2_Create_Group')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Assign_User_To_App": { + "runAfter": { + "Add_Step3_Create_Member_User": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{body('Add_Step3_Create_Member_User')?['id']}/appRoleAssignments", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('Add_Step3_Create_Member_User')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Step3_Create_Member_User": { + "runAfter": { + "Add_Step2_Create_Group": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "accountEnabled": true, + "displayName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser1']}", + "mailNickname": "@{replace(first(split(triggerBody()?['initializationData']?['testUserNames']?['memberUser1'],'@')),'.','')}", + "userPrincipalName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser1']}", + "givenName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName']), concat('Given', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName'])}", + "surname": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname']), concat('Sur', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname'])}", + "jobTitle": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle']), concat('Title', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle'])}", + "department": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department']), concat('Dept', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department'])}", + "companyName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName']), concat('Company', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName'])}", + "businessPhones": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['businessPhones'], json(concat('[\"+ 1-555-', substring(guid(),0,4), '\"]')))", + "mobilePhone": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone'])}", + "officeLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation']), concat('Office', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation'])}", + "preferredLanguage": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage']), 'en-US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage'])}", + "employeeId": "@{substring(guid(), 0, 8)}", + "employeeType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType']), 'Employee', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType'])}", + "streetAddress": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress']), concat('Street', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress'])}", + "city": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city']), concat('City', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city'])}", + "state": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state']), 'WA', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state'])}", + "country": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country'])}", + "postalCode": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode'])}", + "usageLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation'])}", + "mail": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser1Mail']}", + "otherMails": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['otherMails'], json(concat('[\"', substring(guid(),0,8), '@example.com\"]')))", + "faxNumber": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber'])}", + "userType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType']), 'Member', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType'])}", + "employeeOrgData": "@if(or(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'])), json(concat('{\"division\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), concat('Div', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), '\",\"costCenter\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), '\"}')), json(concat('{\"division\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division'], '\",\"costCenter\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'], '\"}')))", + "passwordProfile": { + "forceChangePasswordNextSignIn": "@{coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['forceChangePasswordNextSignIn'], true)}", + "password": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password']), concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password'])}" + } + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Step2_Create_Group": { + "runAfter": { + "Add_Step1_Check_Group_Exists": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['memberGroup']}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{replace(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-', '')}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Step1_Check_Group_Exists": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delay_Before_Add_Group_AppRole": { + "runAfter": { + "Add_Assign_User_To_App": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 1, + "unit": "Minute" + } + } + } + }, + "type": "Scope" + }, + "Add_Member_Analyze_Group_Create_Provisioning_Results": { + "runAfter": { + "Add_Member_Verify_Creation_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_AddMember_CreatePhase_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "Set_AddMember_CreatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningStatus": "@concat('Group: ', if(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'), ', User: ', if(greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'))", + "provisioningResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), concat('Group: ', if(equals(toLower(coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Add_Member_Verify_Group_Create_Provisioning_Logs: ', coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), ', User: ', if(equals(toLower(coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Add_Member_Verify_User_Create_Provisioning_Logs: ', coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN')))), 'NO_LOGS_FOUND'), concat('Failed Action: ', variables('AddMemberFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(or(and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), and(greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure'))), json(concat('{\"group\":', string(coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), ',\"user\":', string(coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), '}')), null), variables('AddMemberFailedActionResponse'))", + "overallResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), and(equals(toLower(coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), equals(toLower(coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'))), and(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0))), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0), false)), 'success', concat('SCIM check: Group found=', string(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0)), ', User found=', string(greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0)))), concat('Failed Action: ', variables('AddMemberFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0), false)), null, concat('SCIM verification failed: Group resources=', string(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]')))), ', User resources=', string(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('AddMemberFailedActionName')))" + } + }, + "Add_Member_Check_Create_Phase_Status": { + "actions": { + "Add_Member_Verify_Update_And_Provisioning": { + "actions": { + "Add_Step5_Add_User_To_Group": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Add_Step2_Create_Group')?['id']}/members/$ref", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "@@odata.id": "https://graph.microsoft.com/v1.0/users/@{body('Add_Step3_Create_Member_User')?['id']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_DoUntil_Wait_For_Member_Addition": { + "actions": { + "Add_Step6_Query_Group_With_Members": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Add_Delay_Member_15s": { + "runAfter": { + "Add_Step6_Query_Group_With_Members": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Add_Step5_Add_User_To_Group": [ + "Succeeded" + ] + }, + "expression": "@and(greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0), and(greater(length(coalesce(first(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]')))?['members'], json('[]'))), 0), contains(string(coalesce(first(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]')))?['members'], json('[]'))), coalesce(first(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]')))?['id'], ''))))", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Add_Step7_Query_Group_By_Id": { + "runAfter": { + "Add_DoUntil_Wait_For_Member_Addition": [ + "Succeeded", + "TimedOut", + "Failed" + ] + }, + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Add_Member_DoUntil_Poll_Add_Member_Provisioning_Logs": { + "actions": { + "Add_Member_Verify_Add_Member_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Add_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27%20and%20modifiedProperties/any(p:%20p/displayName%20eq%20%27members%27)&$orderby=activityDateTime%20desc&$top=1')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Member_Delay_Add_Member_Provisioning_Logs_15s": { + "runAfter": { + "Add_Member_Verify_Add_Member_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Add_Step7_Query_Group_By_Id": [ + "Succeeded", + "Failed" + ] + }, + "expression": "@and(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), and(empty(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['oldValue']), not(empty(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['newValue']))))", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + } + }, + "type": "Scope" + }, + "Capture_AddMember_AddMemberPhase_Failed_Actions": { + "actions": { + "Get_Failed_AddMember_UpdatePhase_Actions": { + "type": "Compose", + "inputs": "@result('Add_Member_Verify_Update_And_Provisioning')" + }, + "Filter_Failed_AddMember_UpdatePhase_Actions": { + "runAfter": { + "Get_Failed_AddMember_UpdatePhase_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_AddMember_UpdatePhase_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_AddMember_UpdatePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_AddMember_UpdatePhase_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_AddMember_UpdatePhase_Actions')), 0), first(body('Filter_Failed_AddMember_UpdatePhase_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_AddMember_UpdatePhase_Failed_Action_Response": { + "runAfter": { + "Set_AddMember_UpdatePhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_AddMember_UpdatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_AddMember_UpdatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_AddMember_UpdatePhase_Status_Failed": { + "runAfter": { + "Set_AddMember_UpdatePhase_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Add_Member_Verify_Update_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_AddMember_UpdatePhase_Status_Success": { + "runAfter": { + "Add_Member_Verify_Update_And_Provisioning": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Add_Member_Analyze_Add_Member_Provisioning_Results": { + "runAfter": { + "Add_Member_Verify_Update_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_AddMember_AddMemberPhase_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "Set_AddMember_UpdatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", + "provisioningResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Add_Member_Verify_Add_Member_Provisioning_Logs: ', coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Add_Member_Verify_Add_Member_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('AddMemberFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('AddMemberFailedActionResponse'))", + "overallResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0), false), 'success', 'Add_Step6_Query_Group_With_Members: Member not found in group on SCIM server after add member'), concat('Failed Action: ', variables('AddMemberFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Member not found in group after add member operation. Group resources=', string(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('AddMemberFailedActionName')))" + } + }, + "Set_AddMember_UpdatePhase_Output_Variables": { + "actions": { + "Set_AddMemberTestOutputs_UpdatePhase": { + "type": "SetVariable", + "inputs": { + "name": "AddMemberTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Add Member Phase] ', coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Add Member Phase] Provisioning: ', coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } + } + } + }, + "runAfter": { + "Add_Member_Analyze_Add_Member_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + } + }, + "runAfter": { + "Set_AddMember_CreatePhase_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@toLower(variables('AddMemberTestOutputs')['overallResult'])", + "passed" + ] + } + ] + }, + "type": "If" + }, + "Add_Cleanup_Delete_User": { + "runAfter": { + "Add_Member_Check_Create_Phase_Status": [ + "Succeeded", + "Failed", + "Skipped", + "TimedOut" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{body('Add_Step3_Create_Member_User')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Add_Cleanup_Delete_Group": { + "runAfter": { + "Add_Cleanup_Delete_User": [ + "Succeeded", + "Failed", + "Skipped", + "TimedOut" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Add_Step2_Create_Group')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Capture_AddMember_CreatePhase_Failed_Actions": { + "actions": { + "Get_Failed_AddMember_CreatePhase_Actions": { + "type": "Compose", + "inputs": "@result('Add_Member_Verify_Creation_And_Provisioning')" + }, + "Filter_Failed_AddMember_CreatePhase_Actions": { + "runAfter": { + "Get_Failed_AddMember_CreatePhase_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_AddMember_CreatePhase_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "Set_AddMember_CreatePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_AddMember_CreatePhase_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberFailedActionName", + "value": "@{if(greater(length(body('Filter_Failed_AddMember_CreatePhase_Actions')), 0), first(body('Filter_Failed_AddMember_CreatePhase_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "Set_AddMember_CreatePhase_Failed_Action_Response": { + "runAfter": { + "Set_AddMember_CreatePhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_AddMember_CreatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_AddMember_CreatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_AddMember_CreatePhase_Status_Failed": { + "runAfter": { + "Set_AddMember_CreatePhase_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Add_Member_Verify_Creation_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_AddMember_CreatePhase_Status_Success": { + "runAfter": { + "Add_Member_Verify_Creation_And_Provisioning": [ "Succeeded" - ] + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AddMemberScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Set_AddMember_CreatePhase_Output_Variables": { + "actions": { + "Set_AddMemberTestOutputs_CreatePhase": { + "type": "SetVariable", + "inputs": { + "name": "AddMemberTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningErrorDetails'], concat('Provisioning result: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], 'UNKNOWN'))))", + "scimCheck": "@if(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" + } + } + } + } + }, + "runAfter": { + "Add_Member_Analyze_Group_Create_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + } }, - "type": "Response", - "kind": "Http", - "inputs": { - "statusCode": 202, - "body": { - "workflowRunId": "@workflow().run.name", - "workflowName": "@workflow().name", - "status": "Accepted", - "message": "GroupTests workflow started. Tests are running asynchronously." + "type": "Scope" + } + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] + }, + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Group_Update_Add_Member_Test" + ] } + ] } + ] }, - "Initialize_All_Group_Test_Variables": { - "runAfter": {}, - "type": "InitializeVariable", - "inputs": { - "variables": [ - { - "name": "CreateGroupFailedActionName", - "type": "string", - "value": "" + "type": "If" + }, + "Group_Update_Remove_Member_Test": { + "actions": { + "Group_Update_Remove_Member_Test_Actions": { + "actions": { + "Remove_Member_Verify_Creation_And_Provisioning": { + "actions": { + "Remove_DoUntil_Wait_For_Initial_Member_Addition": { + "actions": { + "Remove_Step4a_Check_Group_With_Member": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Remove_Step4b_Check_User": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Users?filter=userName%20eq%20%22', coalesce(triggerBody()?['initializationData']?['testUserNames']?['memberUser2'], ''), '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Remove_Delay_Initial_15s": { + "runAfter": { + "Remove_Step4a_Check_Group_With_Member": [ + "Succeeded", + "Failed" + ], + "Remove_Step4b_Check_User": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } }, - { - "name": "CreateGroupFailedActionResponse", - "type": "Object", - "value": {} + "runAfter": { + "Remove_Step4_Add_User_To_Group": [ + "Succeeded" + ] }, - { - "name": "CreateGroupScopeExecutionStatus", - "type": "string", - "value": "InProgress" + "expression": "@and(and(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0)), and(not(empty(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))))), contains(string(body('Remove_Step4a_Check_Group_With_Member')), coalesce(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]')))?['id'], ''))))", + "limit": { + "count": 200, + "timeout": "PT60M" }, - { - "name": "CreateGroupTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "provisioningLogsResult": "", - "scimCheckResult": "", - "errorDetails": { - "provisioningLogs": "", - "scimCheck": "" + "type": "Until" + }, + "Remove_Member_DoUntil_Poll_Group_Create_Provisioning_Logs": { + "actions": { + "Remove_Member_Verify_Group_Create_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Remove_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27%20and%20modifiedProperties/any(p:%20p/displayName%20eq%20%27members%27)&$top=1&$orderby=activityDateTime%20desc')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Member_Verify_User_Create_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Remove_Step3_Create_Member_User')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Member_Delay_Group_Create_Provisioning_Logs_15s": { + "runAfter": { + "Remove_Member_Verify_Group_Create_Provisioning_Logs": [ + "Succeeded", + "Failed" + ], + "Remove_Member_Verify_User_Create_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Remove_DoUntil_Wait_For_Initial_Member_Addition": [ + "Succeeded" + ] + }, + "expression": "@and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), and(not(empty(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['newValue'])), empty(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['oldValue'])))", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + }, + "Remove_Step4_Add_User_To_Group": { + "runAfter": { + "Remove_Assign_Group_To_App": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Remove_Step2_Create_Group')?['id']}/members/$ref", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "@@odata.id": "https://graph.microsoft.com/v1.0/users/@{body('Remove_Step3_Create_Member_User')?['id']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Assign_Group_To_App": { + "runAfter": { + "Delay_Before_Remove_Group_AppRole": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('Remove_Step2_Create_Group')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Assign_User_To_App": { + "runAfter": { + "Remove_Step3_Create_Member_User": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{body('Remove_Step3_Create_Member_User')?['id']}/appRoleAssignments", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('Remove_Step3_Create_Member_User')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Step3_Create_Member_User": { + "runAfter": { + "Remove_Step2_Create_Group": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "accountEnabled": true, + "displayName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser2']}", + "mailNickname": "@{replace(first(split(triggerBody()?['initializationData']?['testUserNames']?['memberUser2'],'@')),'.','')}", + "userPrincipalName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser2']}", + "givenName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName']), concat('Given', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName'])}", + "surname": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname']), concat('Sur', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname'])}", + "jobTitle": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle']), concat('Title', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle'])}", + "department": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department']), concat('Dept', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department'])}", + "companyName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName']), concat('Company', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName'])}", + "businessPhones": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['businessPhones'], json(concat('[\"+ 1-555-', substring(guid(),0,4), '\"]')))", + "mobilePhone": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone'])}", + "officeLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation']), concat('Office', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation'])}", + "preferredLanguage": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage']), 'en-US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage'])}", + "employeeId": "@{substring(guid(), 0, 8)}", + "employeeType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType']), 'Employee', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType'])}", + "streetAddress": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress']), concat('Street', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress'])}", + "city": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city']), concat('City', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city'])}", + "state": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state']), 'WA', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state'])}", + "country": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country'])}", + "postalCode": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode'])}", + "usageLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation'])}", + "mail": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser2Mail']}", + "otherMails": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['otherMails'], json(concat('[\"', substring(guid(),0,8), '@example.com\"]')))", + "faxNumber": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber'])}", + "userType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType']), 'Member', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType'])}", + "employeeOrgData": "@if(or(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'])), json(concat('{\"division\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), concat('Div', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), '\",\"costCenter\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), '\"}')), json(concat('{\"division\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division'], '\",\"costCenter\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'], '\"}')))", + "passwordProfile": { + "forceChangePasswordNextSignIn": "@{coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['forceChangePasswordNextSignIn'], true)}", + "password": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password']), concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password'])}" + } + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Step2_Create_Group": { + "runAfter": { + "Remove_Step1_Check_Group_Exists": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{concat(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove')}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{replace(concat(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], 'Remove'), '-', '')}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Step1_Check_Group_Exists": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Delay_Before_Remove_Group_AppRole": { + "runAfter": { + "Remove_Assign_User_To_App": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 1, + "unit": "Minute" + } + } + } + }, + "type": "Scope" + }, + "Remove_Member_Analyze_Group_Create_Provisioning_Results": { + "runAfter": { + "Remove_Member_Verify_Creation_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_RemoveMember_CreatePhase_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "Set_RemoveMember_CreatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningStatus": "@concat('Group: ', if(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'), ', User: ', if(greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'))", + "provisioningResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), concat('Group: ', if(equals(toLower(coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Remove_Member_Verify_Group_Create_Provisioning_Logs: ', coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), ', User: ', if(equals(toLower(coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Remove_Member_Verify_User_Create_Provisioning_Logs: ', coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN')))), 'NO_LOGS_FOUND'), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(or(and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), and(greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure'))), json(concat('{\"group\":', string(coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), ',\"user\":', string(coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), '}')), null), variables('RemoveMemberFailedActionResponse'))", + "overallResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), and(equals(toLower(coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), equals(toLower(coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'))), and(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0))), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0), false)), 'success', concat('SCIM check: Group found=', string(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0)), ', User found=', string(greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0)))), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0), false)), null, concat('SCIM verification failed: Group resources=', string(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]')))), ', User resources=', string(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('RemoveMemberFailedActionName')))" + } + }, + "Remove_Member_Check_Create_Phase_Status": { + "actions": { + "Remove_Member_Verify_Update_And_Provisioning": { + "actions": { + "Remove_Step5_Remove_User_From_Group": { + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Remove_Step2_Create_Group')?['id']}/members/@{body('Remove_Step3_Create_Member_User')?['id']}/$ref", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_DoUntil_Wait_For_Member_Removal": { + "actions": { + "Remove_Step6_Query_Group_After_Remove": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "Remove_Delay_Final_15s": { + "runAfter": { + "Remove_Step6_Query_Group_After_Remove": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } } + } + }, + "runAfter": { + "Remove_Step5_Remove_User_From_Group": [ + "Succeeded" + ] + }, + "expression": "@and(greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0), and(not(empty(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))))), not(contains(string(body('Remove_Step6_Query_Group_After_Remove')), coalesce(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]')))?['id'], '')))))", + "limit": { + "count": 200, + "timeout": "PT60M" + }, + "type": "Until" + }, + "Remove_Step7_Query_Group_By_Id": { + "runAfter": { + "Remove_DoUntil_Wait_For_Member_Removal": [ + "Succeeded", + "TimedOut", + "Failed" + ] + }, + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', concat(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove'), '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } } - }, - { - "name": "UpdateGroupFailedActionName", - "type": "string", - "value": "" - }, - { - "name": "UpdateGroupFailedActionResponse", - "type": "Object", - "value": {} - }, - { - "name": "UpdateGroupScopeExecutionStatus", - "type": "string", - "value": "InProgress" - }, - { - "name": "UpdateGroupTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "provisioningLogsResult": "", - "scimCheckResult": "", - "errorDetails": { - "provisioningLogs": "", - "scimCheck": "" + }, + "Remove_Member_DoUntil_Poll_Remove_Member_Provisioning_Logs": { + "actions": { + "Remove_Member_Verify_Remove_Member_Provisioning_Logs": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Remove_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27%20and%20modifiedProperties/any(p:%20p/displayName%20eq%20%27members%27)&$orderby=activityDateTime%20desc&$top=1')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } } + }, + "Remove_Member_Delay_Remove_Member_Provisioning_Logs_15s": { + "runAfter": { + "Remove_Member_Verify_Remove_Member_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } + } + } + }, + "runAfter": { + "Remove_Step7_Query_Group_By_Id": [ + "Succeeded", + "Failed" + ] + }, + "expression": "@and(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), and(not(empty(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['oldValue'])), empty(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['newValue'])))", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "type": "Until" + } + }, + "type": "Scope" + }, + "Capture_RemoveMember_RemoveMemberPhase_Failed_Actions": { + "actions": { + "Get_Failed_RemoveMember_RemoveMemberPhase_Actions": { + "type": "Compose", + "inputs": "@result('Remove_Member_Verify_Update_And_Provisioning')" + }, + "Filter_Failed_RemoveMember_RemoveMemberPhase_Actions": { + "runAfter": { + "Get_Failed_RemoveMember_RemoveMemberPhase_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_RemoveMember_RemoveMemberPhase_Actions')", + "where": "@or(equals(item()?['status'], 'Failed'), equals(item()?['status'], 'TimedOut'))" + } + }, + "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_RemoveMember_RemoveMemberPhase_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberFailedActionName", + "value": "@{coalesce(first(body('Filter_Failed_RemoveMember_RemoveMemberPhase_Actions'))?['name'], 'Unknown')}" + } + }, + "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Response": { + "runAfter": { + "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_RemoveMember_RemoveMemberPhase_Actions')), 0), coalesce(first(body('Filter_Failed_RemoveMember_RemoveMemberPhase_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_RemoveMember_RemoveMemberPhase_Status_Failed": { + "runAfter": { + "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberScopeExecutionStatus", + "value": "Failed" } + } }, - { - "name": "DeleteGroupFailedActionName", - "type": "string", - "value": "" + "runAfter": { + "Remove_Member_Verify_Update_And_Provisioning": [ + "Failed" + ] }, - { - "name": "DeleteGroupFailedActionResponse", - "type": "Object", - "value": {} + "type": "Scope" + }, + "Set_RemoveMember_UpdatePhase_Status_Success": { + "runAfter": { + "Remove_Member_Verify_Update_And_Provisioning": [ + "Succeeded" + ] }, - { - "name": "DeleteGroupScopeExecutionStatus", - "type": "string", - "value": "InProgress" + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Remove_Member_Analyze_Remove_Member_Provisioning_Results": { + "runAfter": { + "Remove_Member_Verify_Update_And_Provisioning": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "Capture_RemoveMember_RemoveMemberPhase_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "Set_RemoveMember_UpdatePhase_Status_Success": [ + "Succeeded", + "Skipped" + ] }, - { - "name": "DeleteGroupTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "provisioningLogsResult": "", - "scimCheckResult": "", + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0)", + "provisioningStatus": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Failed'), 'FAILED', if(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND'))", + "provisioningResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Remove_Member_Verify_Remove_Member_Provisioning_Logs: ', coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Remove_Member_Verify_Remove_Member_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('RemoveMemberFailedActionResponse'))", + "overallResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", + "scimCheckResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0), false), 'success', 'Remove_Step6_Query_Group_After_Remove: Group not found on SCIM server after member removal'), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after member removal. Group resources=', string(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('RemoveMemberFailedActionName')))" + } + }, + "Set_RemoveMember_UpdatePhase_Output_Variables": { + "actions": { + "Set_RemoveMemberTestOutputs_UpdatePhase": { + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Remove Member Phase] ', coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Remove Member Phase] Provisioning: ', coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", "errorDetails": { - "provisioningLogs": "", - "scimCheck": "" + "provisioningLogs": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", + "scimCheck": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" } + } } + } }, - { - "name": "AddMemberFailedActionName", - "type": "string", - "value": "" - }, - { - "name": "AddMemberFailedActionResponse", - "type": "Object", - "value": {} - }, - { - "name": "AddMemberScopeExecutionStatus", - "type": "string", - "value": "InProgress" + "runAfter": { + "Remove_Member_Analyze_Remove_Member_Provisioning_Results": [ + "Succeeded", + "Failed" + ] }, + "type": "Scope" + } + }, + "runAfter": { + "Set_RemoveMemberCreatePhase_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ { - "name": "AddMemberTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "provisioningLogsResult": "", - "scimCheckResult": "", - "errorDetails": { - "provisioningLogs": "", - "scimCheck": "" - } - } + "equals": [ + "@toLower(variables('RemoveMemberTestOutputs')['overallResult'])", + "passed" + ] + } + ] + }, + "type": "If" + }, + "Remove_Cleanup_Delete_User": { + "runAfter": { + "Remove_Member_Check_Create_Phase_Status": [ + "Succeeded", + "Failed", + "Skipped", + "TimedOut" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/users/@{body('Remove_Step3_Create_Member_User')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Remove_Cleanup_Delete_Group": { + "runAfter": { + "Remove_Cleanup_Delete_User": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "type": "Http", + "inputs": { + "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Remove_Step2_Create_Group')?['id']}", + "method": "DELETE", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "Capture_RemoveMember_CreatePhase_Failed_Actions": { + "actions": { + "Get_Failed_RemoveMember_CreatePhase_Actions": { + "type": "Compose", + "inputs": "@result('Remove_Member_Verify_Creation_And_Provisioning')" + }, + "Filter_Failed_RemoveMember_CreatePhase_Actions": { + "runAfter": { + "Get_Failed_RemoveMember_CreatePhase_Actions": [ + "Succeeded" + ] }, - { - "name": "RemoveMemberFailedActionName", - "type": "string", - "value": "" + "type": "Query", + "inputs": { + "from": "@outputs('Get_Failed_RemoveMember_CreatePhase_Actions')", + "where": "@or(equals(item()?['status'], 'Failed'), equals(item()?['status'], 'TimedOut'))" + } + }, + "Set_RemoveMember_CreatePhase_Failed_Action_Name": { + "runAfter": { + "Filter_Failed_RemoveMember_CreatePhase_Actions": [ + "Succeeded" + ] }, - { - "name": "RemoveMemberFailedActionResponse", - "type": "Object", - "value": {} + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberFailedActionName", + "value": "@{coalesce(first(body('Filter_Failed_RemoveMember_CreatePhase_Actions'))?['name'], 'Unknown')}" + } + }, + "Set_RemoveMember_CreatePhase_Failed_Action_Response": { + "runAfter": { + "Set_RemoveMember_CreatePhase_Failed_Action_Name": [ + "Succeeded" + ] }, - { - "name": "RemoveMemberScopeExecutionStatus", - "type": "string", - "value": "InProgress" + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberFailedActionResponse", + "value": "@if(greater(length(body('Filter_Failed_RemoveMember_CreatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_RemoveMember_CreatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "Set_RemoveMember_CreatePhase_Status_Failed": { + "runAfter": { + "Set_RemoveMember_CreatePhase_Failed_Action_Response": [ + "Succeeded" + ] }, - { - "name": "RemoveMemberTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "provisioningLogsResult": "", - "scimCheckResult": "", - "errorDetails": { - "provisioningLogs": "", - "scimCheck": "" - } + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "Remove_Member_Verify_Creation_And_Provisioning": [ + "Failed" + ] + }, + "type": "Scope" + }, + "Set_RemoveMember_CreatePhase_Status_Success": { + "runAfter": { + "Remove_Member_Verify_Creation_And_Provisioning": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberScopeExecutionStatus", + "value": "Succeeded" + } + }, + "Set_RemoveMemberCreatePhase_Output_Variables": { + "actions": { + "Set_RemoveMemberTestOutputs_CreatePhase": { + "type": "SetVariable", + "inputs": { + "name": "RemoveMemberTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningErrorDetails'], concat('Provisioning result: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], 'UNKNOWN'))))", + "scimCheck": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" } + } } - ] + } + }, + "runAfter": { + "Remove_Member_Analyze_Group_Create_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + } + }, + "type": "Scope" + } + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] + }, + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Group_Update_Remove_Member_Test" + ] + } + ] } + ] }, - "Initialize_PODGroupTestOutputs": { + "type": "If" + }, + "POD_Group_Test": { + "actions": { + "POD_Group_Test_Actions": { + "type": "Scope", + "actions": { + "POD_Create_Graph_Group": { + "type": "Http", + "inputs": { + "method": "POST", + "uri": "https://graph.microsoft.com/v1.0/groups", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{concat('PODTestGroup_', substring(guid(), 0, 8))}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{concat('podgrp', substring(guid(), 0, 8))}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "POD_SCIM_Pre_Check_Group": { + "runAfter": { + "POD_Create_Graph_Group": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', body('POD_Create_Graph_Group')?['displayName'], '%22')}", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "POD_Group_Delay_After_Create": { + "runAfter": { + "POD_SCIM_Pre_Check_Group": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } + } + }, + "POD_Group_Assign_AppRole": { + "runAfter": { + "POD_Group_Delay_After_Create": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "POST", + "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', body('POD_Create_Graph_Group')?['id'], '/appRoleAssignments')}", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{body('POD_Create_Graph_Group')?['id']}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "POD_Group_Delay_After_AppRole": { + "runAfter": { + "POD_Group_Assign_AppRole": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 60, + "unit": "Second" + } + } + }, + "POD_Group_Get_Sync_Rules": { + "runAfter": { + "POD_Group_Delay_After_AppRole": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/synchronization/jobs/', triggerBody()?['initializationData']?['syncJobId'], '/schema')}", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "POD_Group_Provision_On_Demand": { + "runAfter": { + "POD_Group_Get_Sync_Rules": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "POST", + "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/synchronization/jobs/', triggerBody()?['initializationData']?['syncJobId'], '/provisionOnDemand')}", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "parameters": [ + { + "ruleId": "@{first(body('POD_Group_Get_Sync_Rules')?['synchronizationRules'])?['id']}", + "subjects": [ + { + "objectId": "@{body('POD_Create_Graph_Group')?['id']}", + "objectTypeName": "Group" + } + ] + } + ] + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "POD_Group_Delay_After_Provision": { + "runAfter": { + "POD_Group_Provision_On_Demand": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 2, + "unit": "Minute" + } + } + }, + "POD_SCIM_Get_Group": { + "runAfter": { + "POD_Group_Delay_After_Provision": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', body('POD_Create_Graph_Group')?['displayName'], '%22')}", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "POD_Group_Until_Provisioning_Logs": { + "runAfter": { + "POD_SCIM_Get_Group": [ + "Succeeded", + "Failed" + ] + }, + "type": "Until", + "expression": "@greater(length(coalesce(body('POD_Group_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)", + "limit": { + "count": 30, + "timeout": "PT15M" + }, + "actions": { + "POD_Group_Verify_Provisioning_Logs": { + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('POD_Create_Graph_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27create%27')}", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "POD_Group_Delay_Log_Poll": { + "runAfter": { + "POD_Group_Verify_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } + } + } + } + } + } + }, + "POD_Group_Analyze_Results": { "runAfter": { - "Initialize_All_Group_Test_Variables": ["Succeeded"] + "POD_Group_Test_Actions": [ + "Succeeded", + "Failed", + "TimedOut" + ] }, - "type": "InitializeVariable", + "type": "Compose", "inputs": { - "variables": [ - { - "name": "PODGroupTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "errorDetails": {} - } - } - ] + "testName": "POD_Group_Test", + "timestamp": "@utcNow()", + "graphGroupId": "@coalesce(body('POD_Create_Graph_Group')?['id'], '')", + "graphGroupName": "@coalesce(body('POD_Create_Graph_Group')?['displayName'], '')", + "appRoleAssigned": "@equals(outputs('POD_Group_Assign_AppRole')?['statusCode'], 201)", + "podStatusCode": "@coalesce(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 0)", + "podSucceeded": "@equals(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 200)", + "scimGetStatusCode": "@coalesce(outputs('POD_SCIM_Get_Group')?['statusCode'], 0)", + "scimGroupFound": "@greater(length(coalesce(body('POD_SCIM_Get_Group')?['Resources'], json('[]'))), 0)", + "scimGroupId": "@coalesce(first(body('POD_SCIM_Get_Group')?['Resources'])?['id'], '')", + "provisioningLogFound": "@greater(length(coalesce(body('POD_Group_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)", + "provisioningLogStatus": "@coalesce(first(body('POD_Group_Verify_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'notFound')", + "overallResult": "@if(and(equals(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 200), greater(length(coalesce(body('POD_SCIM_Get_Group')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('POD_Group_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)), 'PASSED', 'FAILED')" } - }, - "Initialize_RestoreGroupTestVariables": { + }, + "Set_PODGroupTestOutputs": { "runAfter": { - "Initialize_PODGroupTestOutputs": ["Succeeded"] + "POD_Group_Analyze_Results": [ + "Succeeded" + ] }, - "type": "InitializeVariable", + "type": "SetVariable", "inputs": { - "variables": [ - { - "name": "restoreEntraGroupId", - "type": "string", - "value": "" + "name": "PODGroupTestOutputs", + "value": { + "overallResult": "@coalesce(outputs('POD_Group_Analyze_Results')?['overallResult'], 'FAILED')", + "result": "@if(equals(coalesce(outputs('POD_Group_Analyze_Results')?['overallResult'], 'FAILED'), 'PASSED'), 'success', if(equals(coalesce(outputs('POD_Group_Analyze_Results')?['appRoleAssigned'], false), false), 'FAILED - Action: POD_Group_Assign_AppRole - app role assignment failed', if(not(equals(coalesce(outputs('POD_Group_Analyze_Results')?['podStatusCode'], 0), 200)), concat('FAILED - Action: POD_Group_Provision_On_Demand - HTTP ', string(coalesce(outputs('POD_Group_Analyze_Results')?['podStatusCode'], 0))), if(equals(coalesce(outputs('POD_Group_Analyze_Results')?['scimGroupFound'], false), false), 'FAILED - Action: POD_SCIM_Get_Group - group not found on SCIM endpoint', 'FAILED - Action: POD_Group_Verify_Provisioning_Logs - provisioning log not found'))))", + "summary": "@outputs('POD_Group_Analyze_Results')", + "errorDetails": { + "podResponse": "@if(not(equals(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 200)), string(coalesce(body('POD_Group_Provision_On_Demand'), 'no response')), null)" + } + } + } + }, + "POD_Group_Cleanup_SCIM_Delete": { + "runAfter": { + "Set_PODGroupTestOutputs": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "type": "Http", + "inputs": { + "method": "DELETE", + "uri": "@{concat(parameters('scimEndpoint'), '/Groups/', coalesce(first(body('POD_SCIM_Get_Group')?['Resources'])?['id'], 'not-found'))}", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "POD_Group_Cleanup_Remove_AppRole": { + "runAfter": { + "POD_Group_Cleanup_SCIM_Delete": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "type": "Http", + "inputs": { + "method": "DELETE", + "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', coalesce(body('POD_Create_Graph_Group')?['id'], 'not-found'), '/appRoleAssignments/', coalesce(body('POD_Group_Assign_AppRole')?['id'], 'not-found'))}", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "POD_Group_Cleanup_Graph_Delete": { + "runAfter": { + "POD_Group_Cleanup_Remove_AppRole": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "type": "Http", + "inputs": { + "method": "DELETE", + "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', coalesce(body('POD_Create_Graph_Group')?['id'], 'not-found'))}", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + } + }, + "runAfter": {}, + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] + }, + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "POD_Group_Test" + ] + } + ] + } + ] + }, + "type": "If" + }, + "Restore_Group_Test": { + "runAfter": {}, + "actions": { + "RestoreGroupTest_Actions": { + "type": "Scope", + "actions": { + "RestoreGroupTest_Phase1_Create_And_Assign": { + "type": "Scope", + "actions": { + "RestoreGroupTest_SCIM_Pre_Check": { + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(coalesce(triggerBody()?['initializationData']?['testGroupNames']?['restoreGroup'], '')), '%22')}", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "RestoreGroupTest_Create_Entra_Group": { + "runAfter": { + "RestoreGroupTest_SCIM_Pre_Check": [ + "Succeeded", + "Failed" + ] }, - { - "name": "restoreGroupAppRoleAssignmentId", - "type": "string", - "value": "" + "type": "Http", + "inputs": { + "method": "POST", + "uri": "https://graph.microsoft.com/v1.0/groups", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "displayName": "@{coalesce(triggerBody()?['initializationData']?['testGroupNames']?['restoreGroup'], concat('RestoreGrp-', substring(guid(),0,8)))}", + "description": "@{parameters('defaultGroupProperties')['description']}", + "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", + "mailNickname": "@{concat('restoregrp', substring(guid(),0,8))}", + "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", + "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", + "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", + "visibility": "@{parameters('defaultGroupProperties')['visibility']}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "RestoreGroupTest_Set_EntraGroupId": { + "runAfter": { + "RestoreGroupTest_Create_Entra_Group": [ + "Succeeded" + ] }, - { - "name": "RestoreGroupTestOutputs", - "type": "Object", - "value": { - "overallResult": "SKIPPED", - "result": "SKIPPED", - "summary": null, - "detailedResults": [], - "errorDetails": { "summary": null } + "type": "SetVariable", + "inputs": { + "name": "restoreEntraGroupId", + "value": "@{body('RestoreGroupTest_Create_Entra_Group')?['id']}" + } + }, + "RestoreGroupTest_Delay_Before_AppRole": { + "runAfter": { + "RestoreGroupTest_Set_EntraGroupId": [ + "Succeeded" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } + } + }, + "RestoreGroupTest_Assign_AppRole": { + "runAfter": { + "RestoreGroupTest_Delay_Before_AppRole": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "POST", + "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'), '/appRoleAssignments')}", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{variables('restoreEntraGroupId')}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "RestoreGroupTest_Set_AppRoleAssignmentId": { + "runAfter": { + "RestoreGroupTest_Assign_AppRole": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "restoreGroupAppRoleAssignmentId", + "value": "@{body('RestoreGroupTest_Assign_AppRole')?['id']}" + } + }, + "RestoreGroupTest_DoUntil_Verify_SCIM_Create": { + "runAfter": { + "RestoreGroupTest_Set_AppRoleAssignmentId": [ + "Succeeded" + ] + }, + "type": "Until", + "expression": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Created')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT50M" + }, + "actions": { + "RestoreGroupTest_SCIM_Check_Created": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(body('RestoreGroupTest_Create_Entra_Group')?['displayName']), '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "RestoreGroupTest_Delay_Create_15s": { + "runAfter": { + "RestoreGroupTest_SCIM_Check_Created": [ + "Succeeded", + "Failed" + ] + }, + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } } + } } - ] - } - }, - "GroupTests_Scope": { - "actions": { - "Create_Group_Test": { + }, + "RestoreGroupTest_DoUntil_Verify_Create_ProvisioningLog": { + "runAfter": { + "RestoreGroupTest_DoUntil_Verify_SCIM_Create": [ + "Succeeded", + "Failed" + ] + }, + "type": "Until", + "expression": "@greater(length(coalesce(body('RestoreGroupTest_Get_Create_Log')?['value'], json('[]'))), 0)", + "limit": { + "count": 20, + "timeout": "PT10M" + }, "actions": { - "Create_Group_Test_Actions": { - "actions": { - "Create_Group_Initial_Verify_Group_Exists": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['createGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Create_Group_Create_Group_Graph": { - "runAfter": { - "Create_Group_Initial_Verify_Group_Exists": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['createGroup']}", - "description": "@{parameters('defaultGroupProperties')['description']}", - "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", -"mailNickname": "@{triggerBody()?['initializationData']?['testGroupNames']?['createGroupNickname']}", - "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", - "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", - "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", - "visibility": "@{parameters('defaultGroupProperties')['visibility']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Create_Group_Assign_Group_To_App": { - "runAfter": { - "Delay_After_Create_Group": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "principalId": "@{body('Create_Group_Create_Group_Graph')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "DoUntil_Poll_Create_Group": { - "actions": { - "Create_Group_Query_Create_Group": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['createGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delay_Create_Group_15s": { - "runAfter": { - "Create_Group_Query_Create_Group": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Create_Group_Assign_Group_To_App": [ - "Succeeded" - ] - }, - "expression": "@greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0)", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "DoUntil_Poll_Group_Provisioning_Logs": { - "actions": { - "Verify_Group_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Create_Group_Create_Group_Graph')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Delay_Group_Provisioning_Logs_15s": { - "runAfter": { - "Verify_Group_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "DoUntil_Poll_Create_Group": [ - "Succeeded", - "Failed", - "TimedOut" - ] - }, - "expression": "@greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0)", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - }, - "Delay_After_Create_Group": { - "runAfter": { - "Create_Group_Create_Group_Graph": [ - "Succeeded" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 1, - "unit": "Minute" - } - } - } - }, - "type": "Scope" + "RestoreGroupTest_Get_Create_Log": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', variables('restoreEntraGroupId'), '%27%20and%20provisioningAction%20eq%20%27Create%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "RestoreGroupTest_Wait_Create_Log_30s": { + "runAfter": { + "RestoreGroupTest_Get_Create_Log": [ + "Succeeded", + "Failed" + ] }, - "Capture_Failed_Group_Action_Details": { - "actions": { - "Get_Failed_Group_Actions": { - "type": "Compose", - "inputs": "@result('Create_Group_Test_Actions')" - }, - "Filter_Failed_Group_Actions": { - "runAfter": { - "Get_Failed_Group_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_Group_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_Failed_Group_Action_Name": { - "runAfter": { - "Filter_Failed_Group_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "CreateGroupFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_Group_Actions')), 0), first(body('Filter_Failed_Group_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_Failed_Group_Action_Response": { - "runAfter": { - "Set_Failed_Group_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "CreateGroupFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_Group_Actions')), 0), coalesce(first(body('Filter_Failed_Group_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_Create_Group_Test_Status_Failed": { - "runAfter": { - "Set_Failed_Group_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "CreateGroupScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Create_Group_Test_Actions": [ - "Failed" - ] - }, - "type": "Scope" + "type": "Wait", + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } + } + } + } + } + } + }, + "RestoreGroupTest_Capture_Phase1_Failed_Actions": { + "actions": { + "RestoreGroupTest_Get_Phase1_Failed_Actions": { + "type": "Compose", + "inputs": "@result('RestoreGroupTest_Phase1_Create_And_Assign')" + }, + "RestoreGroupTest_Filter_Phase1_Failed_Actions": { + "runAfter": { + "RestoreGroupTest_Get_Phase1_Failed_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('RestoreGroupTest_Get_Phase1_Failed_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "RestoreGroupTest_Set_Phase1_Failed_Action_Name": { + "runAfter": { + "RestoreGroupTest_Filter_Phase1_Failed_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupFailedActionName", + "value": "@{if(greater(length(body('RestoreGroupTest_Filter_Phase1_Failed_Actions')), 0), first(body('RestoreGroupTest_Filter_Phase1_Failed_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "RestoreGroupTest_Set_Phase1_Failed_Action_Response": { + "runAfter": { + "RestoreGroupTest_Set_Phase1_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupFailedActionResponse", + "value": "@if(greater(length(body('RestoreGroupTest_Filter_Phase1_Failed_Actions')), 0), coalesce(first(body('RestoreGroupTest_Filter_Phase1_Failed_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "RestoreGroupTest_Set_Phase1_Status_Failed": { + "runAfter": { + "RestoreGroupTest_Set_Phase1_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupScopeExecutionStatus", + "value": "Failed" + } + } + }, + "runAfter": { + "RestoreGroupTest_Phase1_Create_And_Assign": [ + "Failed" + ] + }, + "type": "Scope" + }, + "RestoreGroupTest_Set_Phase1_Status_Success": { + "runAfter": { + "RestoreGroupTest_Phase1_Create_And_Assign": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "RestoreGroupTest_Analyze_Phase1_Provisioning_Results": { + "runAfter": { + "RestoreGroupTest_Phase1_Create_And_Assign": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "RestoreGroupTest_Capture_Phase1_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "RestoreGroupTest_Set_Phase1_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('RestoreGroupTest_Get_Create_Log')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('RestoreGroupTest_Get_Create_Log')?['value'], json('[]'))), 0)", + "scimGroupCreated": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Created')?['Resources'], json('[]'))), 0)", + "provisioningResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('RestoreGroupTest_Get_Create_Log')?['value'], json('[]'))), 0), 'success', 'RestoreGroupTest_Get_Create_Log: NO_LOGS_FOUND'), concat('Failed Action: ', variables('RestoreGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), null, variables('RestoreGroupFailedActionResponse'))", + "overallResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Created')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('RestoreGroupTest_Get_Create_Log')?['value'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')" + } + }, + "RestoreGroupTest_Set_Phase1_Output_Variables": { + "actions": { + "RestoreGroupTest_Set_RestoreGroupTestOutputs_Phase1": { + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['scimGroupCreated'], false), true)), 'success', if(startsWith(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['scimGroupCreated'], false), true), 'success', 'Group not found on SCIM server'))))", + "overallResult": "@outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], ''), 'success'), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['scimGroupCreated'], false), true), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningErrorDetails'], concat('Provisioning result: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['provisioningResult'], 'UNKNOWN'))))", + "scimCheck": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase1_Provisioning_Results')?['scimGroupCreated'], false), true), null, 'Group not found on SCIM server after provisioning')" + } + } + } + } + }, + "runAfter": { + "RestoreGroupTest_Analyze_Phase1_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + }, + "RestoreGroupTest_Check_Phase1_Status": { + "actions": { + "RestoreGroupTest_Phase2_Unassign": { + "runAfter": {}, + "type": "Scope", + "actions": { + "RestoreGroupTest_Unassign_AppRole": { + "type": "Http", + "inputs": { + "method": "DELETE", + "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/appRoleAssignedTo/', variables('restoreGroupAppRoleAssignmentId'))}", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "RestoreGroupTest_DoUntil_Verify_SCIM_Gone": { + "runAfter": { + "RestoreGroupTest_Unassign_AppRole": [ + "Succeeded" + ] }, - "Set_Create_Group_Test_Status_Success": { - "runAfter": { - "Create_Group_Test_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", + "type": "Until", + "expression": "@equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT50M" + }, + "actions": { + "RestoreGroupTest_SCIM_Check_Gone": { + "type": "Http", "inputs": { - "name": "CreateGroupScopeExecutionStatus", - "value": "Succeeded" + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(body('RestoreGroupTest_Create_Entra_Group')?['displayName']), '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } } - }, - "Create_Group_Test_Analyze_Provisioning_Results": { + }, + "RestoreGroupTest_Delay_Gone_15s": { "runAfter": { - "Create_Group_Test_Actions": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_Failed_Group_Action_Details": [ - "Succeeded", - "Skipped" - ], - "Set_Create_Group_Test_Status_Success": [ - "Succeeded", - "Skipped" - ] + "RestoreGroupTest_SCIM_Check_Gone": [ + "Succeeded", + "Failed" + ] }, - "type": "Compose", + "type": "Wait", "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", - "provisioningResult": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Verify_Group_Provisioning_Logs: ', coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Verify_Group_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('CreateGroupFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('CreateGroupFailedActionResponse'))", - "overallResult": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Verify_Group_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Verify_Group_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0), false), 'success', 'Create_Group_Query_Create_Group: Group not found on SCIM server after provisioning'), concat('Failed Action: ', variables('CreateGroupFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('CreateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after provisioning. SCIM query returned ', string(length(coalesce(body('Create_Group_Query_Create_Group')?['Resources'], json('[]')))), ' resources (expected >= 1). totalResults: ', string(coalesce(body('Create_Group_Query_Create_Group')?['totalResults'], 'N/A')))), concat('Scope execution failed. Failed action: ', variables('CreateGroupFailedActionName')))" + "interval": { + "count": 15, + "unit": "Second" + } } + } + } + }, + "RestoreGroupTest_DoUntil_Verify_Delete_ProvisioningLog": { + "runAfter": { + "RestoreGroupTest_DoUntil_Verify_SCIM_Gone": [ + "Succeeded", + "Failed", + "TimedOut" + ] }, - "Set_CreateGroup_Output_Variables": { - "actions": { - "Set_CreateGroupTestOutputs": { - "type": "SetVariable", - "inputs": { - "name": "CreateGroupTestOutputs", - "value": { - "result": "@if(and(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Create_Group_Test_Analyze_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Create_Group_Test_Analyze_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Create_Group_Test_Analyze_Provisioning_Results": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - }, - "Delete_Created_Group": { - "runAfter": { - "Set_CreateGroup_Output_Variables": [ - "Succeeded", - "Failed", - "Skipped" - ] - }, + "type": "Until", + "expression": "@greater(length(coalesce(body('RestoreGroupTest_Get_Delete_Log')?['value'], json('[]'))), 0)", + "limit": { + "count": 150, + "timeout": "PT40M" + }, + "actions": { + "RestoreGroupTest_Get_Delete_Log": { "type": "Http", "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Create_Group_Create_Group_Graph')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', variables('restoreEntraGroupId'), '%27%20and%20provisioningAction%20eq%20%27Delete%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } } - } - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] + }, + "RestoreGroupTest_Wait_Delete_Log_15s": { + "runAfter": { + "RestoreGroupTest_Get_Delete_Log": [ + "Succeeded", + "Failed" + ] }, - { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Create_Group_Test" - ] - } - ] + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } } - ] - }, - "type": "If" - }, - "Update_Group_Test": { + } + } + } + } + }, + "RestoreGroupTest_Capture_Phase2_Failed_Actions": { "actions": { - "Update_Group_Test_Actions": { - "actions": { - "Update_Group_Verify_Creation_And_Provisioning": { - "actions": { - "Update_Group_Initial_Verify_Group_Exists": { - "type": "Http", - "inputs": { -"uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Update_Group_Create_Group_Graph": { - "runAfter": { - "Update_Group_Initial_Verify_Group_Exists": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { -"displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['updateGroup']}", - "description": "@{parameters('defaultGroupProperties')['description']}", - "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", -"mailNickname": "@{triggerBody()?['initializationData']?['testGroupNames']?['updateGroupNickname']}", - "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", - "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", - "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", - "visibility": "@{parameters('defaultGroupProperties')['visibility']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Update_Group_Assign_To_App": { - "runAfter": { - "Delay_After_Update_Group_Create": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "principalId": "@{body('Update_Group_Create_Group_Graph')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Update_Group_DoUntil_Wait_For_Creation": { - "actions": { - "Update_Group_Check_Group_Create": { - "type": "Http", - "inputs": { -"uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Update_Group_Delay_Creation_15s": { - "runAfter": { - "Update_Group_Check_Group_Create": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Update_Group_Assign_To_App": [ - "Succeeded" - ] - }, - "expression": "@greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0)", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Update_Group_DoUntil_Poll_Create_Provisioning": { - "actions": { - "Update_Group_Verify_Create_Provisioning": { - "type": "Http", - "inputs": { - "uri": "@concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Update_Group_Create_Group_Graph')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Update_Group_Delay_Create_Provisioning_15s": { - "runAfter": { - "Update_Group_Verify_Create_Provisioning": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Update_Group_DoUntil_Wait_For_Creation": [ - "Succeeded" - ] - }, - "expression": "@greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0)", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - }, - "Delay_After_Update_Group_Create": { - "runAfter": { - "Update_Group_Create_Group_Graph": [ - "Succeeded" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 1, - "unit": "Minute" - } - } - } - }, - "type": "Scope" - }, - "Capture_Update_Group_CreatePhase_Failed": { - "actions": { - "Get_Failed_CreatePhase_Group_Actions": { - "type": "Compose", - "inputs": "@result('Update_Group_Verify_Creation_And_Provisioning')" - }, - "Filter_Failed_CreatePhase_Group_Actions": { - "runAfter": { - "Get_Failed_CreatePhase_Group_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_CreatePhase_Group_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_UpdateGroup_CreatePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_CreatePhase_Group_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_CreatePhase_Group_Actions')), 0), first(body('Filter_Failed_CreatePhase_Group_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_UpdateGroup_CreatePhase_Failed_Action_Response": { - "runAfter": { - "Set_UpdateGroup_CreatePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_CreatePhase_Group_Actions')), 0), coalesce(first(body('Filter_Failed_CreatePhase_Group_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_UpdateGroup_CreatePhase_Status_Failed": { - "runAfter": { - "Set_UpdateGroup_CreatePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Update_Group_Verify_Creation_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_UpdateGroup_CreatePhase_Status_Success": { - "runAfter": { - "Update_Group_Verify_Creation_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Update_Group_Analyze_Create_Provisioning": { - "runAfter": { - "Update_Group_Verify_Creation_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_Update_Group_CreatePhase_Failed": [ - "Succeeded", - "Skipped" - ], - "Set_UpdateGroup_CreatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", - "provisioningResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Update_Group_Verify_Create_Provisioning: ', coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Update_Group_Verify_Create_Provisioning: NO_LOGS_FOUND'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), equals(toLower(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('UpdateGroupFailedActionResponse'))", - "overallResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Update_Group_Verify_Create_Provisioning')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Update_Group_Verify_Create_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0), false), 'success', 'Update_Group_Check_Group_Create: Group not found on SCIM server after provisioning'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after provisioning. SCIM query returned ', string(length(coalesce(body('Update_Group_Check_Group_Create')?['Resources'], json('[]')))), ' resources (expected >= 1). totalResults: ', string(coalesce(body('Update_Group_Check_Group_Create')?['totalResults'], 'N/A')))), concat('Scope execution failed. Failed action: ', variables('UpdateGroupFailedActionName')))" - } - }, - "Set_UpdateGroup_CreatePhase_Output_Variables": { - "actions": { - "Set_UpdateGroupTestOutputs_CreatePhase": { - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupTestOutputs", - "value": { - "result": "@if(and(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Update_Group_Analyze_Create_Provisioning')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Create_Provisioning')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Update_Group_Analyze_Create_Provisioning": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - }, - "Update_Group_Check_Create_Phase_Status": { - "actions": { - "Update_Group_Verify_Update_And_Provisioning": { - "actions": { - "Update_Group_Query_Group_By_Id": { - "type": "Http", - "inputs": { -"uri": "@concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '%22')", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Update_Group_Update_Group_Attributes": { - "runAfter": { - "Update_Group_Query_Group_By_Id": [ - "Succeeded", - "Failed" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Update_Group_Create_Group_Graph')?['id']}", - "method": "PATCH", - "headers": { - "Content-Type": "application/json" - }, - "body": { -"displayName": "@{concat(triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '-Modified')}", - "description": "Updated Test Group Description" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Update_Group_DoUntil_Wait_For_Updates": { - "actions": { - "Update_Group_Query_Group_By_Id_After_Attributes_Update": { - "type": "Http", - "inputs": { -"uri": "@concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', concat(triggerBody()?['initializationData']?['testGroupNames']?['updateGroup'], '-Modified'), '%22')", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Update_Group_Delay_Update_15s": { - "runAfter": { - "Update_Group_Query_Group_By_Id_After_Attributes_Update": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Update_Group_Update_Group_Attributes": [ - "Succeeded" - ] - }, - "expression": "@and(greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0), contains(string(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')), '-Modified'))", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Update_Group_DoUntil_Poll_Update_Provisioning": { - "actions": { - "Update_Group_Verify_Update_Provisioning": { - "type": "Http", - "inputs": { - "uri": "@concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Update_Group_Create_Group_Graph')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27&$top=1&$orderby=activityDateTime%20desc')", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Update_Group_Delay_Update_Provisioning_15s": { - "runAfter": { - "Update_Group_Verify_Update_Provisioning": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Update_Group_DoUntil_Wait_For_Updates": [ - "Succeeded", - "Failed", - "TimedOut" - ] - }, - "expression": "@greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0)", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - } - }, - "type": "Scope" - }, - "Capture_Update_Group_UpdatePhase_Failed": { - "actions": { - "Get_Failed_UpdatePhase_Group_Actions": { - "type": "Compose", - "inputs": "@result('Update_Group_Verify_Update_And_Provisioning')" - }, - "Filter_Failed_UpdatePhase_Group_Actions": { - "runAfter": { - "Get_Failed_UpdatePhase_Group_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_UpdatePhase_Group_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_UpdateGroup_UpdatePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_UpdatePhase_Group_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_UpdatePhase_Group_Actions')), 0), first(body('Filter_Failed_UpdatePhase_Group_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_UpdateGroup_UpdatePhase_Failed_Action_Response": { - "runAfter": { - "Set_UpdateGroup_UpdatePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_UpdatePhase_Group_Actions')), 0), coalesce(first(body('Filter_Failed_UpdatePhase_Group_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_UpdateGroup_UpdatePhase_Status_Failed": { - "runAfter": { - "Set_UpdateGroup_UpdatePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Update_Group_Verify_Update_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_UpdateGroup_UpdatePhase_Status_Success": { - "runAfter": { - "Update_Group_Verify_Update_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Update_Group_Analyze_Update_Provisioning": { - "runAfter": { - "Update_Group_Verify_Update_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_Update_Group_UpdatePhase_Failed": [ - "Succeeded", - "Skipped" - ], - "Set_UpdateGroup_UpdatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", - "provisioningResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Update_Group_Verify_Update_Provisioning: ', coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Update_Group_Verify_Update_Provisioning: NO_LOGS_FOUND'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), equals(toLower(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('UpdateGroupFailedActionResponse'))", - "overallResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Update_Group_Verify_Update_Provisioning')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Update_Group_Verify_Update_Provisioning')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0), 'success', 'Update_Group_Query_Group_By_Id_After_Attributes_Update: Group not found on SCIM server after update'), concat('Failed Action: ', variables('UpdateGroupFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('UpdateGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Update_Group_Query_Group_By_Id_After_Attributes_Update')?['Resources'], json('[]'))), 0), null, 'SCIM verification failed: Group not found on SCIM server after update provisioning'), concat('Scope execution failed. Failed action: ', variables('UpdateGroupFailedActionName')))" - } - }, - "Set_UpdateGroup_UpdatePhase_Output_Variables": { - "actions": { - "Set_UpdateGroupTestOutputs_UpdatePhase": { - "type": "SetVariable", - "inputs": { - "name": "UpdateGroupTestOutputs", - "value": { - "result": "@if(and(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Update Phase] ', coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], '')), concat('FAILED - [Update Phase] Provisioning: ', coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Update_Group_Analyze_Update_Provisioning')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Update_Group_Analyze_Update_Provisioning')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Update_Group_Analyze_Update_Provisioning": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - } - }, - "runAfter": { - "Set_UpdateGroup_CreatePhase_Output_Variables": [ - "Succeeded", - "Failed", - "Skipped" - ] - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@toLower(variables('UpdateGroupTestOutputs')['overallResult'])", - "passed" - ] - } - ] - }, - "type": "If" - }, - "Update_Group_Cleanup_Delete": { - "runAfter": { - "Update_Group_Check_Create_Phase_Status": [ - "Succeeded", - "Failed", - "TimedOut", - "Skipped" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Update_Group_Create_Group_Graph')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - } - }, - "type": "Scope" + "RestoreGroupTest_Get_Phase2_Failed_Actions": { + "type": "Compose", + "inputs": "@result('RestoreGroupTest_Phase2_Unassign')" + }, + "RestoreGroupTest_Filter_Phase2_Failed_Actions": { + "runAfter": { + "RestoreGroupTest_Get_Phase2_Failed_Actions": [ + "Succeeded" + ] + }, + "type": "Query", + "inputs": { + "from": "@outputs('RestoreGroupTest_Get_Phase2_Failed_Actions')", + "where": "@equals(item()?['status'], 'Failed')" + } + }, + "RestoreGroupTest_Set_Phase2_Failed_Action_Name": { + "runAfter": { + "RestoreGroupTest_Filter_Phase2_Failed_Actions": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupFailedActionName", + "value": "@{if(greater(length(body('RestoreGroupTest_Filter_Phase2_Failed_Actions')), 0), first(body('RestoreGroupTest_Filter_Phase2_Failed_Actions'))?['name'], 'Unknown_Action')}" + } + }, + "RestoreGroupTest_Set_Phase2_Failed_Action_Response": { + "runAfter": { + "RestoreGroupTest_Set_Phase2_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupFailedActionResponse", + "value": "@if(greater(length(body('RestoreGroupTest_Filter_Phase2_Failed_Actions')), 0), coalesce(first(body('RestoreGroupTest_Filter_Phase2_Failed_Actions'))?['outputs'], json('{}')), json('{}'))" + } + }, + "RestoreGroupTest_Set_Phase2_Status_Failed": { + "runAfter": { + "RestoreGroupTest_Set_Phase2_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupScopeExecutionStatus", + "value": "Failed" } + } }, - "else": { - "actions": {} + "runAfter": { + "RestoreGroupTest_Phase2_Unassign": [ + "Failed" + ] }, - "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] - }, - { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Update_Group_Test" - ] - } - ] - } - ] + "type": "Scope" + }, + "RestoreGroupTest_Set_Phase2_Status_Success": { + "runAfter": { + "RestoreGroupTest_Phase2_Unassign": [ + "Succeeded" + ] }, - "type": "If" - }, - "Delete_Group_Test": { + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "RestoreGroupTest_Analyze_Phase2_Provisioning_Results": { + "runAfter": { + "RestoreGroupTest_Phase2_Unassign": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "RestoreGroupTest_Capture_Phase2_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "RestoreGroupTest_Set_Phase2_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('RestoreGroupTest_Get_Delete_Log')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('RestoreGroupTest_Get_Delete_Log')?['value'], json('[]'))), 0)", + "scimGroupGone": "@equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[]'))), 0)", + "provisioningResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('RestoreGroupTest_Get_Delete_Log')?['value'], json('[]'))), 0), 'success', 'RestoreGroupTest_Get_Delete_Log: NO_LOGS_FOUND'), concat('Failed Action: ', variables('RestoreGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), null, variables('RestoreGroupFailedActionResponse'))", + "scimCheckResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[]'))), 0), 'success', 'RestoreGroupTest: Group still present on SCIM server after unassign'), concat('Failed Action: ', variables('RestoreGroupFailedActionName')))", + "overallResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('RestoreGroupTest_Get_Delete_Log')?['value'], json('[]'))), 0), equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')" + } + }, + "RestoreGroupTest_Set_Phase2_Output_Variables": { "actions": { - "Delete_Group_Test_Actions": { - "actions": { - "Delete_Group_Verify_Creation_And_Provisioning": { - "actions": { - "Delete_Step1_Check_Group_Exists": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delete_Step2_Create_Group": { - "runAfter": { - "Delete_Step1_Check_Group_Exists": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup']}", - "description": "@{parameters('defaultGroupProperties')['description']}", - "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", - "mailNickname": "@{replace(triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '-', '')}", - "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", - "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", - "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", - "visibility": "@{parameters('defaultGroupProperties')['visibility']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Delete_Group_Assign_App_Role": { - "runAfter": { - "Delay_After_Delete_Group_Create": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", - "method": "POST", - "body": { - "principalId": "@{body('Delete_Step2_Create_Group')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Delete_DoUntil_Wait_For_Group_Creation": { - "actions": { - "Delete_Step3_Fetch_Group_By_Filter": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delete_Group_Delay_Creation_15s": { - "runAfter": { - "Delete_Step3_Fetch_Group_By_Filter": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Delete_Group_Assign_App_Role": [ - "Succeeded" - ] - }, - "expression": "@greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0)", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Delete_Group_DoUntil_Poll_Create_Provisioning_Logs": { - "actions": { - "Delete_Group_Verify_Create_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Delete_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Delete_Group_Delay_Create_Provisioning_Logs_15s": { - "runAfter": { - "Delete_Group_Verify_Create_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Delete_DoUntil_Wait_For_Group_Creation": [ - "Succeeded" - ] - }, - "expression": "@greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0)", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - }, - "Delay_After_Delete_Group_Create": { - "runAfter": { - "Delete_Step2_Create_Group": [ - "Succeeded" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 1, - "unit": "Minute" - } - } - } - }, - "type": "Scope" - }, - "Capture_DeleteGroup_CreatePhase_Failed_Actions": { - "actions": { - "Get_Failed_DeleteGroup_CreatePhase_Actions": { - "type": "Compose", - "inputs": "@result('Delete_Group_Verify_Creation_And_Provisioning')" - }, - "Filter_Failed_DeleteGroup_CreatePhase_Actions": { - "runAfter": { - "Get_Failed_DeleteGroup_CreatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_DeleteGroup_CreatePhase_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_DeleteGroup_CreatePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_DeleteGroup_CreatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_DeleteGroup_CreatePhase_Actions')), 0), first(body('Filter_Failed_DeleteGroup_CreatePhase_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_DeleteGroup_CreatePhase_Failed_Action_Response": { - "runAfter": { - "Set_DeleteGroup_CreatePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_DeleteGroup_CreatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_DeleteGroup_CreatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_DeleteGroup_CreatePhase_Status_Failed": { - "runAfter": { - "Set_DeleteGroup_CreatePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Delete_Group_Verify_Creation_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_DeleteGroup_CreatePhase_Status_Success": { - "runAfter": { - "Delete_Group_Verify_Creation_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Delete_Group_Analyze_Create_Provisioning_Results": { - "runAfter": { - "Delete_Group_Verify_Creation_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_DeleteGroup_CreatePhase_Failed_Actions": [ - "Succeeded", - "Skipped" - ], - "Set_DeleteGroup_CreatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", - "provisioningResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Delete_Group_Verify_Create_Provisioning_Logs: ', coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Delete_Group_Verify_Create_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('DeleteGroupFailedActionResponse'))", - "overallResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Delete_Group_Verify_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0), false), 'success', 'Delete_Step3_Fetch_Group_By_Filter: Group not found on SCIM server after provisioning'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after provisioning. SCIM query returned ', string(length(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['Resources'], json('[]')))), ' resources (expected >= 1). totalResults: ', string(coalesce(body('Delete_Step3_Fetch_Group_By_Filter')?['totalResults'], 'N/A')))), concat('Scope execution failed. Failed action: ', variables('DeleteGroupFailedActionName')))" - } - }, - "Set_DeleteGroup_CreatePhase_Output_Variables": { - "actions": { - "Set_DeleteGroupTestOutputs_CreatePhase": { - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupTestOutputs", - "value": { - "result": "@if(and(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Create_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Delete_Group_Analyze_Create_Provisioning_Results": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - }, - "Delete_Group_Check_Create_Phase_Status": { - "actions": { - "Delete_Group_Verify_Delete_And_Provisioning": { - "actions": { - "Delete_Step4_Query_Group_By_Id": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delete_Step5_Delete_Group_By_Id": { - "runAfter": { - "Delete_Step4_Query_Group_By_Id": [ - "Succeeded", - "Failed" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Delete_Step2_Create_Group')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Delete_DoUntil_Wait_For_Group_Deletion": { - "actions": { - "Delete_Step6_Check_Group_Exists_Final": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['deleteGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delete_Group_Delay_Final_15s": { - "runAfter": { - "Delete_Step6_Check_Group_Exists_Final": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Delete_Step5_Delete_Group_By_Id": [ - "Succeeded" - ] - }, - "expression": "@equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0)", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Delete_Group_DoUntil_Poll_Delete_Provisioning_Logs": { - "actions": { - "Delete_Group_Verify_Delete_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Delete_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Delete%27')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Delete_Group_Delay_Delete_Provisioning_Logs_15s": { - "runAfter": { - "Delete_Group_Verify_Delete_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Delete_DoUntil_Wait_For_Group_Deletion": [ - "Succeeded", - "Failed", - "TimedOut" - ] - }, - "expression": "@greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0)", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - } - }, - "type": "Scope" - }, - "Capture_DeleteGroup_DeletePhase_Failed_Actions": { - "actions": { - "Get_Failed_DeleteGroup_DeletePhase_Actions": { - "type": "Compose", - "inputs": "@result('Delete_Group_Verify_Delete_And_Provisioning')" - }, - "Filter_Failed_DeleteGroup_DeletePhase_Actions": { - "runAfter": { - "Get_Failed_DeleteGroup_DeletePhase_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_DeleteGroup_DeletePhase_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_DeleteGroup_DeletePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_DeleteGroup_DeletePhase_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_DeleteGroup_DeletePhase_Actions')), 0), first(body('Filter_Failed_DeleteGroup_DeletePhase_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_DeleteGroup_DeletePhase_Failed_Action_Response": { - "runAfter": { - "Set_DeleteGroup_DeletePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_DeleteGroup_DeletePhase_Actions')), 0), coalesce(first(body('Filter_Failed_DeleteGroup_DeletePhase_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_DeleteGroup_DeletePhase_Status_Failed": { - "runAfter": { - "Set_DeleteGroup_DeletePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Delete_Group_Verify_Delete_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_DeleteGroup_DeletePhase_Status_Success": { - "runAfter": { - "Delete_Group_Verify_Delete_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Delete_Group_Analyze_Delete_Provisioning_Results": { - "runAfter": { - "Delete_Group_Verify_Delete_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_DeleteGroup_DeletePhase_Failed_Actions": [ - "Succeeded", - "Skipped" - ], - "Set_DeleteGroup_DeletePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", - "provisioningResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', if(equals(toLower(coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'skipped'), 'Delete provisioning was skipped by the engine. Group deprovisioning cannot be skipped - the connector objectMapping flowTypes must include Delete', concat('Delete provisioning log status: ', coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN')))), 'Delete_Group_Verify_Delete_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('DeleteGroupFailedActionResponse'))", - "overallResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Delete_Group_Verify_Delete_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0), 'success', 'Delete_Step6_Check_Group_Exists_Final: Group still exists on SCIM server after deletion'), concat('Failed Action: ', variables('DeleteGroupFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('DeleteGroupScopeExecutionStatus'), 'Succeeded'), if(equals(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]'))), 0), null, concat('SCIM verification failed: Group still exists on SCIM server after deletion. Resources count: ', string(length(coalesce(body('Delete_Step6_Check_Group_Exists_Final')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('DeleteGroupFailedActionName')))" - } - }, - "Set_DeleteGroup_Output_Variables": { - "actions": { - "Set_DeleteGroupTestOutputs_DeletePhase": { - "type": "SetVariable", - "inputs": { - "name": "DeleteGroupTestOutputs", - "value": { - "result": "@if(and(contains(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Delete Phase] ', coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Delete Phase] Provisioning: ', coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Delete_Group_Analyze_Delete_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Delete_Group_Analyze_Delete_Provisioning_Results": [ - "Succeeded" - ] - }, - "type": "Scope" - } - }, - "runAfter": { - "Set_DeleteGroup_CreatePhase_Output_Variables": [ - "Succeeded", - "Failed", - "Skipped" - ] - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@toLower(variables('DeleteGroupTestOutputs')['overallResult'])", - "passed" - ] - } - ] - }, - "type": "If" - } - }, - "type": "Scope" + "RestoreGroupTest_Set_RestoreGroupTestOutputs_Phase2": { + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Unassign Phase] ', coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Unassign Phase] Provisioning: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningResult'], ''), 'success'), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed'))", + "scimCheck": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase2_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, 'Group still present on SCIM server after unassign')" + } + } } + } }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] - }, - { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Delete_Group_Test" - ] - } - ] - } - ] + "runAfter": { + "RestoreGroupTest_Analyze_Phase2_Provisioning_Results": [ + "Succeeded", + "Failed" + ] }, - "type": "If" - }, - "Group_Update_Add_Member_Test": { + "type": "Scope" + }, + "RestoreGroupTest_Check_Phase2_Status": { "actions": { - "Group_Update_Add_Member_Test_Actions": { - "actions": { - "Add_Member_Verify_Creation_And_Provisioning": { - "actions": { - "Add_DoUntil_Wait_For_Initial_Sync": { - "actions": { - "Add_Step4_Check_Group_And_User": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Add_Step4_Check_User": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Users?filter=userName%20eq%20%22', coalesce(triggerBody()?['initializationData']?['testUserNames']?['memberUser1'], ''), '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Add_Delay_Initial_15s": { - "runAfter": { - "Add_Step4_Check_Group_And_User": [ - "Succeeded", - "Failed" - ], - "Add_Step4_Check_User": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Add_Assign_Group_To_App": [ - "Succeeded" - ] - }, - "expression": "@and(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0))", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Add_Member_DoUntil_Poll_Group_Create_Provisioning_Logs": { - "actions": { - "Add_Member_Verify_Group_Create_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Add_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Member_Delay_Group_Create_Provisioning_Logs_15s": { - "runAfter": { - "Add_Member_Verify_Group_Create_Provisioning_Logs": [ - "Succeeded", - "Failed" - ], - "Add_Member_Verify_User_Create_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - }, - "Add_Member_Verify_User_Create_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Add_Step3_Create_Member_User')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - } - }, - "runAfter": { - "Add_DoUntil_Wait_For_Initial_Sync": [ - "Succeeded" - ] - }, - "expression": "@and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0))", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - }, - "Add_Assign_Group_To_App": { - "runAfter": { - "Delay_Before_Add_Group_AppRole": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "principalId": "@{body('Add_Step2_Create_Group')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Assign_User_To_App": { - "runAfter": { - "Add_Step3_Create_Member_User": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/users/@{body('Add_Step3_Create_Member_User')?['id']}/appRoleAssignments", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "principalId": "@{body('Add_Step3_Create_Member_User')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Step3_Create_Member_User": { - "runAfter": { - "Add_Step2_Create_Group": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/users", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "accountEnabled": true, - "displayName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser1']}", - "mailNickname": "@{replace(first(split(triggerBody()?['initializationData']?['testUserNames']?['memberUser1'],'@')),'.','')}", - "userPrincipalName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser1']}", - "mail": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser1Mail']}", - "givenName": "MemberUser1", - "surname": "Test", - "passwordProfile": { - "forceChangePasswordNextSignIn": true, - "password": "@{concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8))}" - } - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Step2_Create_Group": { - "runAfter": { - "Add_Step1_Check_Group_Exists": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "displayName": "@{triggerBody()?['initializationData']?['testGroupNames']?['memberGroup']}", - "description": "@{parameters('defaultGroupProperties')['description']}", - "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", - "mailNickname": "@{replace(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-', '')}", - "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", - "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", - "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", - "visibility": "@{parameters('defaultGroupProperties')['visibility']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Step1_Check_Group_Exists": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delay_Before_Add_Group_AppRole": { - "runAfter": { - "Add_Assign_User_To_App": [ - "Succeeded" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 1, - "unit": "Minute" - } - } - } - }, - "type": "Scope" - }, - "Add_Member_Analyze_Group_Create_Provisioning_Results": { - "runAfter": { - "Add_Member_Verify_Creation_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_AddMember_CreatePhase_Failed_Actions": [ - "Succeeded", - "Skipped" - ], - "Set_AddMember_CreatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningStatus": "@concat('Group: ', if(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'), ', User: ', if(greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'))", - "provisioningResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), concat('Group: ', if(equals(toLower(coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Add_Member_Verify_Group_Create_Provisioning_Logs: ', coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), ', User: ', if(equals(toLower(coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Add_Member_Verify_User_Create_Provisioning_Logs: ', coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN')))), 'NO_LOGS_FOUND'), concat('Failed Action: ', variables('AddMemberFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(or(and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), and(greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure'))), json(concat('{\"group\":', string(coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), ',\"user\":', string(coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), '}')), null), variables('AddMemberFailedActionResponse'))", - "overallResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(and(greater(length(coalesce(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), and(equals(toLower(coalesce(first(body('Add_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), equals(toLower(coalesce(first(body('Add_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'))), and(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0))), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0), false)), 'success', concat('SCIM check: Group found=', string(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0)), ', User found=', string(greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0)))), concat('Failed Action: ', variables('AddMemberFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]'))), 0), false)), null, concat('SCIM verification failed: Group resources=', string(length(coalesce(body('Add_Step4_Check_Group_And_User')?['Resources'], json('[]')))), ', User resources=', string(length(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('AddMemberFailedActionName')))" - } - }, - "Add_Member_Check_Create_Phase_Status": { - "actions": { - "Add_Member_Verify_Update_And_Provisioning": { - "actions": { - "Add_Step5_Add_User_To_Group": { - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Add_Step2_Create_Group')?['id']}/members/$ref", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "@@odata.id": "https://graph.microsoft.com/v1.0/users/@{body('Add_Step3_Create_Member_User')?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_DoUntil_Wait_For_Member_Addition": { - "actions": { - "Add_Step6_Query_Group_With_Members": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Add_Delay_Member_15s": { - "runAfter": { - "Add_Step6_Query_Group_With_Members": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Add_Step5_Add_User_To_Group": [ - "Succeeded" - ] - }, - "expression": "@and(greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0), and(greater(length(coalesce(first(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]')))?['members'], json('[]'))), 0), contains(string(coalesce(first(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]')))?['members'], json('[]'))), coalesce(first(coalesce(body('Add_Step4_Check_User')?['Resources'], json('[]')))?['id'], ''))))", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Add_Step7_Query_Group_By_Id": { - "runAfter": { - "Add_DoUntil_Wait_For_Member_Addition": [ - "Succeeded", - "TimedOut", - "Failed" - ] - }, - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Add_Member_DoUntil_Poll_Add_Member_Provisioning_Logs": { - "actions": { - "Add_Member_Verify_Add_Member_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Add_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27%20and%20modifiedProperties/any(p:%20p/displayName%20eq%20%27members%27)&$orderby=activityDateTime%20desc&$top=1')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Member_Delay_Add_Member_Provisioning_Logs_15s": { - "runAfter": { - "Add_Member_Verify_Add_Member_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Add_Step7_Query_Group_By_Id": [ - "Succeeded", - "Failed" - ] - }, - "expression": "@and(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), and(empty(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['oldValue']), not(empty(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['newValue']))))", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - } - }, - "type": "Scope" - }, - "Capture_AddMember_AddMemberPhase_Failed_Actions": { - "actions": { - "Get_Failed_AddMember_UpdatePhase_Actions": { - "type": "Compose", - "inputs": "@result('Add_Member_Verify_Update_And_Provisioning')" - }, - "Filter_Failed_AddMember_UpdatePhase_Actions": { - "runAfter": { - "Get_Failed_AddMember_UpdatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_AddMember_UpdatePhase_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_AddMember_UpdatePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_AddMember_UpdatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_AddMember_UpdatePhase_Actions')), 0), first(body('Filter_Failed_AddMember_UpdatePhase_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_AddMember_UpdatePhase_Failed_Action_Response": { - "runAfter": { - "Set_AddMember_UpdatePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_AddMember_UpdatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_AddMember_UpdatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_AddMember_UpdatePhase_Status_Failed": { - "runAfter": { - "Set_AddMember_UpdatePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Add_Member_Verify_Update_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_AddMember_UpdatePhase_Status_Success": { - "runAfter": { - "Add_Member_Verify_Update_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Add_Member_Analyze_Add_Member_Provisioning_Results": { - "runAfter": { - "Add_Member_Verify_Update_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_AddMember_AddMemberPhase_Failed_Actions": [ - "Succeeded", - "Skipped" - ], - "Set_AddMember_UpdatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND')", - "provisioningResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Add_Member_Verify_Add_Member_Provisioning_Logs: ', coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Add_Member_Verify_Add_Member_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('AddMemberFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('AddMemberFailedActionResponse'))", - "overallResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Add_Member_Verify_Add_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0), false), 'success', 'Add_Step6_Query_Group_With_Members: Member not found in group on SCIM server after add member'), concat('Failed Action: ', variables('AddMemberFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('AddMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Member not found in group after add member operation. Group resources=', string(length(coalesce(body('Add_Step6_Query_Group_With_Members')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('AddMemberFailedActionName')))" - } - }, - "Set_AddMember_UpdatePhase_Output_Variables": { - "actions": { - "Set_AddMemberTestOutputs_UpdatePhase": { - "type": "SetVariable", - "inputs": { - "name": "AddMemberTestOutputs", - "value": { - "result": "@if(and(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Add Member Phase] ', coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Add Member Phase] Provisioning: ', coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Add_Member_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Add_Member_Analyze_Add_Member_Provisioning_Results": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - } - }, - "runAfter": { - "Set_AddMember_CreatePhase_Output_Variables": [ - "Succeeded", - "Failed", - "Skipped" - ] - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@toLower(variables('AddMemberTestOutputs')['overallResult'])", - "passed" - ] - } - ] - }, - "type": "If" - }, - "Add_Cleanup_Delete_User": { - "runAfter": { - "Add_Member_Check_Create_Phase_Status": [ - "Succeeded", - "Failed", - "Skipped", - "TimedOut" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/users/@{body('Add_Step3_Create_Member_User')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Add_Cleanup_Delete_Group": { - "runAfter": { - "Add_Cleanup_Delete_User": [ - "Succeeded", - "Failed", - "Skipped", - "TimedOut" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Add_Step2_Create_Group')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Capture_AddMember_CreatePhase_Failed_Actions": { - "actions": { - "Get_Failed_AddMember_CreatePhase_Actions": { - "type": "Compose", - "inputs": "@result('Add_Member_Verify_Creation_And_Provisioning')" - }, - "Filter_Failed_AddMember_CreatePhase_Actions": { - "runAfter": { - "Get_Failed_AddMember_CreatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_AddMember_CreatePhase_Actions')", - "where": "@equals(item()?['status'], 'Failed')" - } - }, - "Set_AddMember_CreatePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_AddMember_CreatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberFailedActionName", - "value": "@{if(greater(length(body('Filter_Failed_AddMember_CreatePhase_Actions')), 0), first(body('Filter_Failed_AddMember_CreatePhase_Actions'))?['name'], 'Unknown_Action')}" - } - }, - "Set_AddMember_CreatePhase_Failed_Action_Response": { - "runAfter": { - "Set_AddMember_CreatePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_AddMember_CreatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_AddMember_CreatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_AddMember_CreatePhase_Status_Failed": { - "runAfter": { - "Set_AddMember_CreatePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Add_Member_Verify_Creation_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_AddMember_CreatePhase_Status_Success": { - "runAfter": { - "Add_Member_Verify_Creation_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "AddMemberScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Set_AddMember_CreatePhase_Output_Variables": { - "actions": { - "Set_AddMemberTestOutputs_CreatePhase": { - "type": "SetVariable", - "inputs": { - "name": "AddMemberTestOutputs", - "value": { - "result": "@if(and(not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'UNKNOWN')), equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success')), if(and(not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'MISSING')), not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed'))), 'success', if(startsWith(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], '')))), if(startsWith(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'UNKNOWN')), and(not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'MISSING')), not(contains(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed')))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Add_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Add_Member_Analyze_Group_Create_Provisioning_Results": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - } + "RestoreGroupTest_Phase3_Reassign": { + "runAfter": {}, + "type": "Scope", + "actions": { + "RestoreGroupTest_Reassign_AppRole": { + "type": "Http", + "inputs": { + "method": "POST", + "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'), '/appRoleAssignments')}", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "principalId": "@{variables('restoreEntraGroupId')}", + "resourceId": "@{parameters('servicePrincipalId')}", + "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "RestoreGroupTest_DoUntil_Verify_SCIM_Restored": { + "runAfter": { + "RestoreGroupTest_Reassign_AppRole": [ + "Succeeded" + ] }, - "type": "Scope" - } - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] + "type": "Until", + "expression": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0)", + "limit": { + "count": 200, + "timeout": "PT50M" }, - { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Group_Update_Add_Member_Test" - ] - } - ] - } - ] - }, - "type": "If" - }, - "Group_Update_Remove_Member_Test": { - "actions": { - "Group_Update_Remove_Member_Test_Actions": { "actions": { - "Remove_Member_Verify_Creation_And_Provisioning": { - "actions": { - "Remove_DoUntil_Wait_For_Initial_Member_Addition": { - "actions": { - "Remove_Step4a_Check_Group_With_Member": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Remove_Step4b_Check_User": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Users?filter=userName%20eq%20%22', coalesce(triggerBody()?['initializationData']?['testUserNames']?['memberUser2'], ''), '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Remove_Delay_Initial_15s": { - "runAfter": { - "Remove_Step4a_Check_Group_With_Member": [ - "Succeeded", - "Failed" - ], - "Remove_Step4b_Check_User": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Remove_Step4_Add_User_To_Group": [ - "Succeeded" - ] - }, - "expression": "@and(and(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0)), and(not(empty(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))))), contains(string(body('Remove_Step4a_Check_Group_With_Member')), coalesce(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]')))?['id'], ''))))", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Remove_Member_DoUntil_Poll_Group_Create_Provisioning_Logs": { - "actions": { - "Remove_Member_Verify_Group_Create_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Remove_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27%20and%20modifiedProperties/any(p:%20p/displayName%20eq%20%27members%27)&$top=1&$orderby=activityDateTime%20desc')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Member_Verify_User_Create_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Remove_Step3_Create_Member_User')?['id'], '%27%20and%20provisioningAction%20eq%20%27Create%27')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Member_Delay_Group_Create_Provisioning_Logs_15s": { - "runAfter": { - "Remove_Member_Verify_Group_Create_Provisioning_Logs": [ - "Succeeded", - "Failed" - ], - "Remove_Member_Verify_User_Create_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Remove_DoUntil_Wait_For_Initial_Member_Addition": [ - "Succeeded" - ] - }, - "expression": "@and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), and(not(empty(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['newValue'])), empty(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['oldValue'])))", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - }, - "Remove_Step4_Add_User_To_Group": { - "runAfter": { - "Remove_Assign_Group_To_App": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Remove_Step2_Create_Group')?['id']}/members/$ref", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "@@odata.id": "https://graph.microsoft.com/v1.0/users/@{body('Remove_Step3_Create_Member_User')?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Assign_Group_To_App": { - "runAfter": { - "Delay_Before_Remove_Group_AppRole": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/servicePrincipals/@{parameters('servicePrincipalId')}/appRoleAssignedTo", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "principalId": "@{body('Remove_Step2_Create_Group')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Assign_User_To_App": { - "runAfter": { - "Remove_Step3_Create_Member_User": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/users/@{body('Remove_Step3_Create_Member_User')?['id']}/appRoleAssignments", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "principalId": "@{body('Remove_Step3_Create_Member_User')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Step3_Create_Member_User": { - "runAfter": { - "Remove_Step2_Create_Group": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/users", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "accountEnabled": true, - "displayName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser2']}", - "mailNickname": "@{replace(first(split(triggerBody()?['initializationData']?['testUserNames']?['memberUser2'],'@')),'.','')}", - "userPrincipalName": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser2']}", - "mail": "@{triggerBody()?['initializationData']?['testUserNames']?['memberUser2Mail']}", - "givenName": "MemberUser2", - "surname": "Test", - "passwordProfile": { - "forceChangePasswordNextSignIn": true, - "password": "@{concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8))}" - } - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Step2_Create_Group": { - "runAfter": { - "Remove_Step1_Check_Group_Exists": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups", - "method": "POST", - "headers": { - "Content-Type": "application/json" - }, - "body": { - "displayName": "@{concat(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove')}", - "description": "@{parameters('defaultGroupProperties')['description']}", - "mailEnabled": "@parameters('defaultGroupProperties')['mailEnabled']", - "mailNickname": "@{replace(concat(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], 'Remove'), '-', '')}", - "securityEnabled": "@parameters('defaultGroupProperties')['securityEnabled']", - "groupTypes": "@parameters('defaultGroupProperties')['groupTypes']", - "isAssignableToRole": "@parameters('defaultGroupProperties')['isAssignableToRole']", - "visibility": "@{parameters('defaultGroupProperties')['visibility']}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Step1_Check_Group_Exists": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Delay_Before_Remove_Group_AppRole": { - "runAfter": { - "Remove_Assign_User_To_App": [ - "Succeeded" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 1, - "unit": "Minute" - } - } - } - }, - "type": "Scope" - }, - "Remove_Member_Analyze_Group_Create_Provisioning_Results": { - "runAfter": { - "Remove_Member_Verify_Creation_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_RemoveMember_CreatePhase_Failed_Actions": [ - "Succeeded", - "Skipped" - ], - "Set_RemoveMember_CreatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningStatus": "@concat('Group: ', if(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'), ', User: ', if(greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS'))", - "provisioningResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), concat('Group: ', if(equals(toLower(coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Remove_Member_Verify_Group_Create_Provisioning_Logs: ', coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), ', User: ', if(equals(toLower(coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Remove_Member_Verify_User_Create_Provisioning_Logs: ', coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN')))), 'NO_LOGS_FOUND'), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(or(and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), and(greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure'))), json(concat('{\"group\":', string(coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), ',\"user\":', string(coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null)), '}')), null), variables('RemoveMemberFailedActionResponse'))", - "overallResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(and(greater(length(coalesce(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'], json('[]'))), 0), greater(length(coalesce(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'], json('[]'))), 0)), and(equals(toLower(coalesce(first(body('Remove_Member_Verify_Group_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), equals(toLower(coalesce(first(body('Remove_Member_Verify_User_Create_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'))), and(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0))), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0), false)), 'success', concat('SCIM check: Group found=', string(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0)), ', User found=', string(greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0)))), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(coalesce(greater(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]'))), 0), false), coalesce(greater(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))), 0), false)), null, concat('SCIM verification failed: Group resources=', string(length(coalesce(body('Remove_Step4a_Check_Group_With_Member')?['Resources'], json('[]')))), ', User resources=', string(length(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('RemoveMemberFailedActionName')))" - } - }, - "Remove_Member_Check_Create_Phase_Status": { - "actions": { - "Remove_Member_Verify_Update_And_Provisioning": { - "actions": { - "Remove_Step5_Remove_User_From_Group": { - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Remove_Step2_Create_Group')?['id']}/members/@{body('Remove_Step3_Create_Member_User')?['id']}/$ref", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_DoUntil_Wait_For_Member_Removal": { - "actions": { - "Remove_Step6_Query_Group_After_Remove": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Remove_Delay_Final_15s": { - "runAfter": { - "Remove_Step6_Query_Group_After_Remove": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Remove_Step5_Remove_User_From_Group": [ - "Succeeded" - ] - }, - "expression": "@and(greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0), and(not(empty(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]'))))), not(contains(string(body('Remove_Step6_Query_Group_After_Remove')), coalesce(first(coalesce(body('Remove_Step4b_Check_User')?['Resources'], json('[]')))?['id'], '')))))", - "limit": { - "count": 200, - "timeout": "PT60M" - }, - "type": "Until" - }, - "Remove_Step7_Query_Group_By_Id": { - "runAfter": { - "Remove_DoUntil_Wait_For_Member_Removal": [ - "Succeeded", - "TimedOut", - "Failed" - ] - }, - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', concat(triggerBody()?['initializationData']?['testGroupNames']?['memberGroup'], '-Remove'), '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "Remove_Member_DoUntil_Poll_Remove_Member_Provisioning_Logs": { - "actions": { - "Remove_Member_Verify_Remove_Member_Provisioning_Logs": { - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('Remove_Step2_Create_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27Update%27%20and%20modifiedProperties/any(p:%20p/displayName%20eq%20%27members%27)&$orderby=activityDateTime%20desc&$top=1')}", - "method": "GET", - "headers": { - "Accept": "application/json" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Member_Delay_Remove_Member_Provisioning_Logs_15s": { - "runAfter": { - "Remove_Member_Verify_Remove_Member_Provisioning_Logs": [ - "Succeeded", - "Failed" - ] - }, - "type": "Wait", - "inputs": { - "interval": { - "count": 15, - "unit": "Second" - } - } - } - }, - "runAfter": { - "Remove_Step7_Query_Group_By_Id": [ - "Succeeded", - "Failed" - ] - }, - "expression": "@and(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), and(not(empty(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['oldValue'])), empty(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['modifiedProperties'][0]?['newValue'])))", - "limit": { - "count": 150, - "timeout": "PT40M" - }, - "type": "Until" - } - }, - "type": "Scope" - }, - "Capture_RemoveMember_RemoveMemberPhase_Failed_Actions": { - "actions": { - "Get_Failed_RemoveMember_RemoveMemberPhase_Actions": { - "type": "Compose", - "inputs": "@result('Remove_Member_Verify_Update_And_Provisioning')" - }, - "Filter_Failed_RemoveMember_RemoveMemberPhase_Actions": { - "runAfter": { - "Get_Failed_RemoveMember_RemoveMemberPhase_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_RemoveMember_RemoveMemberPhase_Actions')", - "where": "@or(equals(item()?['status'], 'Failed'), equals(item()?['status'], 'TimedOut'))" - } - }, - "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_RemoveMember_RemoveMemberPhase_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberFailedActionName", - "value": "@{coalesce(first(body('Filter_Failed_RemoveMember_RemoveMemberPhase_Actions'))?['name'], 'Unknown')}" - } - }, - "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Response": { - "runAfter": { - "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_RemoveMember_RemoveMemberPhase_Actions')), 0), coalesce(first(body('Filter_Failed_RemoveMember_RemoveMemberPhase_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_RemoveMember_RemoveMemberPhase_Status_Failed": { - "runAfter": { - "Set_RemoveMember_RemoveMemberPhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Remove_Member_Verify_Update_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_RemoveMember_UpdatePhase_Status_Success": { - "runAfter": { - "Remove_Member_Verify_Update_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberScopeExecutionStatus", - "value": "Succeeded" - } - }, - "Remove_Member_Analyze_Remove_Member_Provisioning_Results": { - "runAfter": { - "Remove_Member_Verify_Update_And_Provisioning": [ - "Succeeded", - "Failed", - "TimedOut" - ], - "Capture_RemoveMember_RemoveMemberPhase_Failed_Actions": [ - "Succeeded", - "Skipped" - ], - "Set_RemoveMember_UpdatePhase_Status_Success": [ - "Succeeded", - "Skipped" - ] - }, - "type": "Compose", - "inputs": { - "provisioningLogsCount": "@length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]')))", - "hasProvisioningLogs": "@greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0)", - "provisioningStatus": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Failed'), 'FAILED', if(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'), 'NO_LOGS_FOUND'))", - "provisioningResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), if(equals(toLower(coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success'), 'success', concat('Remove_Member_Verify_Remove_Member_Provisioning_Logs: ', coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'UNKNOWN'))), 'Remove_Member_Verify_Remove_Member_Provisioning_Logs: NO_LOGS_FOUND'), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", - "provisioningErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('RemoveMemberFailedActionResponse'))", - "overallResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(and(and(greater(length(coalesce(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('Remove_Member_Verify_Remove_Member_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')", - "scimCheckResult": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0), false), 'success', 'Remove_Step6_Query_Group_After_Remove: Group not found on SCIM server after member removal'), concat('Failed Action: ', variables('RemoveMemberFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('RemoveMemberScopeExecutionStatus'), 'Succeeded'), if(coalesce(greater(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]'))), 0), false), null, concat('SCIM verification failed: Group not found on SCIM server after member removal. Group resources=', string(length(coalesce(body('Remove_Step6_Query_Group_After_Remove')?['Resources'], json('[]')))))), concat('Scope execution failed. Failed action: ', variables('RemoveMemberFailedActionName')))" - } - }, - "Set_RemoveMember_UpdatePhase_Output_Variables": { - "actions": { - "Set_RemoveMemberTestOutputs_UpdatePhase": { - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberTestOutputs", - "value": { - "result": "@if(and(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Remove Member Phase] ', coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Remove Member Phase] Provisioning: ', coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(contains(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Remove_Member_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Remove_Member_Analyze_Remove_Member_Provisioning_Results": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" - } - }, - "runAfter": { - "Set_RemoveMemberCreatePhase_Output_Variables": [ - "Succeeded", - "Failed", - "Skipped" - ] - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@toLower(variables('RemoveMemberTestOutputs')['overallResult'])", - "passed" - ] - } - ] - }, - "type": "If" - }, - "Remove_Cleanup_Delete_User": { - "runAfter": { - "Remove_Member_Check_Create_Phase_Status": [ - "Succeeded", - "Failed", - "Skipped", - "TimedOut" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/users/@{body('Remove_Step3_Create_Member_User')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Remove_Cleanup_Delete_Group": { - "runAfter": { - "Remove_Cleanup_Delete_User": [ - "Succeeded", - "Failed", - "Skipped" - ] - }, - "type": "Http", - "inputs": { - "uri": "https://graph.microsoft.com/v1.0/groups/@{body('Remove_Step2_Create_Group')?['id']}", - "method": "DELETE", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "Capture_RemoveMember_CreatePhase_Failed_Actions": { - "actions": { - "Get_Failed_RemoveMember_CreatePhase_Actions": { - "type": "Compose", - "inputs": "@result('Remove_Member_Verify_Creation_And_Provisioning')" - }, - "Filter_Failed_RemoveMember_CreatePhase_Actions": { - "runAfter": { - "Get_Failed_RemoveMember_CreatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "Query", - "inputs": { - "from": "@outputs('Get_Failed_RemoveMember_CreatePhase_Actions')", - "where": "@or(equals(item()?['status'], 'Failed'), equals(item()?['status'], 'TimedOut'))" - } - }, - "Set_RemoveMember_CreatePhase_Failed_Action_Name": { - "runAfter": { - "Filter_Failed_RemoveMember_CreatePhase_Actions": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberFailedActionName", - "value": "@{coalesce(first(body('Filter_Failed_RemoveMember_CreatePhase_Actions'))?['name'], 'Unknown')}" - } - }, - "Set_RemoveMember_CreatePhase_Failed_Action_Response": { - "runAfter": { - "Set_RemoveMember_CreatePhase_Failed_Action_Name": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberFailedActionResponse", - "value": "@if(greater(length(body('Filter_Failed_RemoveMember_CreatePhase_Actions')), 0), coalesce(first(body('Filter_Failed_RemoveMember_CreatePhase_Actions'))?['outputs'], json('{}')), json('{}'))" - } - }, - "Set_RemoveMember_CreatePhase_Status_Failed": { - "runAfter": { - "Set_RemoveMember_CreatePhase_Failed_Action_Response": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberScopeExecutionStatus", - "value": "Failed" - } - } - }, - "runAfter": { - "Remove_Member_Verify_Creation_And_Provisioning": [ - "Failed" - ] - }, - "type": "Scope" - }, - "Set_RemoveMember_CreatePhase_Status_Success": { - "runAfter": { - "Remove_Member_Verify_Creation_And_Provisioning": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberScopeExecutionStatus", - "value": "Succeeded" - } + "RestoreGroupTest_SCIM_Check_Restored": { + "type": "Http", + "inputs": { + "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(body('RestoreGroupTest_Create_Entra_Group')?['displayName']), '%22')}", + "method": "GET", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, + "RestoreGroupTest_Delay_Restored_15s": { + "runAfter": { + "RestoreGroupTest_SCIM_Check_Restored": [ + "Succeeded", + "Failed" + ] }, - "Set_RemoveMemberCreatePhase_Output_Variables": { - "actions": { - "Set_RemoveMemberTestOutputs_CreatePhase": { - "type": "SetVariable", - "inputs": { - "name": "RemoveMemberTestOutputs", - "value": { - "result": "@if(and(not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'UNKNOWN')), equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success')), if(and(not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'MISSING')), not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed'))), 'success', if(startsWith(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], '')))), if(startsWith(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Create Phase] ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Create Phase] Provisioning: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''))))", - "overallResult": "@outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['overallResult']", - "provisioningLogsResult": "@if(and(not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'UNKNOWN')), and(not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'MISSING')), not(contains(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'Failed')))), 'success', 'failure')", - "scimCheckResult": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", - "errorDetails": { - "provisioningLogs": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", - "scimCheck": "@if(equals(coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('Remove_Member_Analyze_Group_Create_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" - } - } - } - } - }, - "runAfter": { - "Remove_Member_Analyze_Group_Create_Provisioning_Results": [ - "Succeeded", - "Failed" - ] - }, - "type": "Scope" + "type": "Wait", + "inputs": { + "interval": { + "count": 15, + "unit": "Second" + } } + } + } + }, + "RestoreGroupTest_DoUntil_Verify_Restore_ProvisioningLog": { + "runAfter": { + "RestoreGroupTest_DoUntil_Verify_SCIM_Restored": [ + "Succeeded", + "Failed", + "TimedOut" + ] }, - "type": "Scope" - } - }, - "else": { - "actions": {} - }, - "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] + "type": "Until", + "expression": "@greater(length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]'))), 0)", + "limit": { + "count": 20, + "timeout": "PT10M" }, - { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Group_Update_Remove_Member_Test" - ] - } - ] - } - ] - }, - "type": "If" - }, - "POD_Group_Test": { - "actions": { - "POD_Group_Test_Actions": { - "type": "Scope", "actions": { - "POD_Create_Graph_Group": { - "type": "Http", - "inputs": { - "method": "POST", - "uri": "https://graph.microsoft.com/v1.0/groups", - "headers": { "Content-Type": "application/json" }, - "body": { - "displayName": "@{concat('PODTestGroup_', substring(guid(), 0, 8))}", - "mailNickname": "@{concat('podgrp', substring(guid(), 0, 8))}", - "mailEnabled": false, - "securityEnabled": true, - "groupTypes": [] - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "POD_Group_Delay_After_Create": { - "runAfter": { "POD_Create_Graph_Group": ["Succeeded"] }, - "type": "Wait", - "inputs": { "interval": { "count": 30, "unit": "Second" } } - }, - "POD_Group_Assign_AppRole": { - "runAfter": { "POD_Group_Delay_After_Create": ["Succeeded"] }, - "type": "Http", - "inputs": { - "method": "POST", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', body('POD_Create_Graph_Group')?['id'], '/appRoleAssignments')}", - "headers": { "Content-Type": "application/json" }, - "body": { - "principalId": "@{body('POD_Create_Graph_Group')?['id']}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "POD_Group_Delay_After_AppRole": { - "runAfter": { "POD_Group_Assign_AppRole": ["Succeeded"] }, - "type": "Wait", - "inputs": { "interval": { "count": 60, "unit": "Second" } } - }, - "POD_Group_Get_Sync_Rules": { - "runAfter": { "POD_Group_Delay_After_AppRole": ["Succeeded"] }, - "type": "Http", - "inputs": { - "method": "GET", - "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/synchronization/jobs/', triggerBody()?['initializationData']?['syncJobId'], '/schema')}", - "headers": { "Accept": "application/json" }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "POD_Group_Provision_On_Demand": { - "runAfter": { "POD_Group_Get_Sync_Rules": ["Succeeded"] }, - "type": "Http", - "inputs": { - "method": "POST", - "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/synchronization/jobs/', triggerBody()?['initializationData']?['syncJobId'], '/provisionOnDemand')}", - "headers": { "Content-Type": "application/json" }, - "body": { - "parameters": [ - { - "ruleId": "@{first(body('POD_Group_Get_Sync_Rules')?['synchronizationRules'])?['id']}", - "subjects": [ - { - "objectId": "@{body('POD_Create_Graph_Group')?['id']}", - "objectTypeName": "Group" - } - ] - } - ] - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "POD_Group_Delay_After_Provision": { - "runAfter": { "POD_Group_Provision_On_Demand": ["Succeeded", "Failed"] }, - "type": "Wait", - "inputs": { "interval": { "count": 2, "unit": "Minute" } } - }, - "POD_SCIM_Get_Group": { - "runAfter": { "POD_Group_Delay_After_Provision": ["Succeeded"] }, - "type": "Http", - "inputs": { - "method": "GET", - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', body('POD_Create_Graph_Group')?['displayName'], '%22')}", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } + "RestoreGroupTest_Get_Restore_Log": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', variables('restoreEntraGroupId'), '%27%20and%20provisioningAction%20eq%20%27Create%27')}", + "method": "GET", + "headers": { + "Accept": "application/json" + }, + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } + } + }, + "RestoreGroupTest_Wait_Restore_Log_30s": { + "runAfter": { + "RestoreGroupTest_Get_Restore_Log": [ + "Succeeded", + "Failed" + ] }, - "POD_Group_Until_Provisioning_Logs": { - "runAfter": { "POD_SCIM_Get_Group": ["Succeeded", "Failed"] }, - "type": "Until", - "expression": "@greater(length(coalesce(body('POD_Group_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)", - "limit": { "count": 30, "timeout": "PT15M" }, - "actions": { - "POD_Group_Verify_Provisioning_Logs": { - "type": "Http", - "inputs": { - "method": "GET", - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('POD_Create_Graph_Group')?['id'], '%27%20and%20provisioningAction%20eq%20%27create%27')}", - "headers": { "Accept": "application/json" }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "POD_Group_Delay_Log_Poll": { - "runAfter": { "POD_Group_Verify_Provisioning_Logs": ["Succeeded", "Failed"] }, - "type": "Wait", - "inputs": { "interval": { "count": 30, "unit": "Second" } } - } - } + "type": "Wait", + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } } + } } - }, - "POD_Group_Analyze_Results": { - "runAfter": { "POD_Group_Test_Actions": ["Succeeded", "Failed", "TimedOut"] }, + } + } + }, + "RestoreGroupTest_Capture_Phase3_Failed_Actions": { + "actions": { + "RestoreGroupTest_Get_Phase3_Failed_Actions": { "type": "Compose", + "inputs": "@result('RestoreGroupTest_Phase3_Reassign')" + }, + "RestoreGroupTest_Filter_Phase3_Failed_Actions": { + "runAfter": { + "RestoreGroupTest_Get_Phase3_Failed_Actions": [ + "Succeeded" + ] + }, + "type": "Query", "inputs": { - "testName": "POD_Group_Test", - "timestamp": "@utcNow()", - "graphGroupId": "@coalesce(body('POD_Create_Graph_Group')?['id'], '')", - "graphGroupName": "@coalesce(body('POD_Create_Graph_Group')?['displayName'], '')", - "appRoleAssigned": "@equals(outputs('POD_Group_Assign_AppRole')?['statusCode'], 201)", - "podStatusCode": "@coalesce(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 0)", - "podSucceeded": "@equals(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 200)", - "scimGetStatusCode": "@coalesce(outputs('POD_SCIM_Get_Group')?['statusCode'], 0)", - "scimGroupFound": "@greater(length(coalesce(body('POD_SCIM_Get_Group')?['Resources'], json('[]'))), 0)", - "scimGroupId": "@coalesce(first(body('POD_SCIM_Get_Group')?['Resources'])?['id'], '')", - "provisioningLogFound": "@greater(length(coalesce(body('POD_Group_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)", - "provisioningLogStatus": "@coalesce(first(body('POD_Group_Verify_Provisioning_Logs')?['value'])?['provisioningStatusInfo']?['status'], 'notFound')", - "overallResult": "@if(and(equals(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 200), greater(length(coalesce(body('POD_SCIM_Get_Group')?['Resources'], json('[]'))), 0), greater(length(coalesce(body('POD_Group_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)), 'PASSED', 'FAILED')" + "from": "@outputs('RestoreGroupTest_Get_Phase3_Failed_Actions')", + "where": "@equals(item()?['status'], 'Failed')" } - }, - "Set_PODGroupTestOutputs": { - "runAfter": { "POD_Group_Analyze_Results": ["Succeeded"] }, + }, + "RestoreGroupTest_Set_Phase3_Failed_Action_Name": { + "runAfter": { + "RestoreGroupTest_Filter_Phase3_Failed_Actions": [ + "Succeeded" + ] + }, "type": "SetVariable", "inputs": { - "name": "PODGroupTestOutputs", - "value": { - "overallResult": "@coalesce(outputs('POD_Group_Analyze_Results')?['overallResult'], 'FAILED')", - "result": "@if(equals(coalesce(outputs('POD_Group_Analyze_Results')?['overallResult'], 'FAILED'), 'PASSED'), 'success', if(equals(coalesce(outputs('POD_Group_Analyze_Results')?['appRoleAssigned'], false), false), 'FAILED - Action: POD_Group_Assign_AppRole - app role assignment failed', if(not(equals(coalesce(outputs('POD_Group_Analyze_Results')?['podStatusCode'], 0), 200)), concat('FAILED - Action: POD_Group_Provision_On_Demand - HTTP ', string(coalesce(outputs('POD_Group_Analyze_Results')?['podStatusCode'], 0))), if(equals(coalesce(outputs('POD_Group_Analyze_Results')?['scimGroupFound'], false), false), 'FAILED - Action: POD_SCIM_Get_Group - group not found on SCIM endpoint', 'FAILED - Action: POD_Group_Verify_Provisioning_Logs - provisioning log not found'))))", - "summary": "@outputs('POD_Group_Analyze_Results')", - "errorDetails": { - "podResponse": "@if(not(equals(outputs('POD_Group_Provision_On_Demand')?['statusCode'], 200)), string(coalesce(body('POD_Group_Provision_On_Demand'), 'no response')), null)" - } - } + "name": "RestoreGroupFailedActionName", + "value": "@{if(greater(length(body('RestoreGroupTest_Filter_Phase3_Failed_Actions')), 0), first(body('RestoreGroupTest_Filter_Phase3_Failed_Actions'))?['name'], 'Unknown_Action')}" } - }, - "POD_Group_Cleanup_SCIM_Delete": { - "runAfter": { "Set_PODGroupTestOutputs": ["Succeeded", "Failed", "Skipped"] }, - "type": "Http", + }, + "RestoreGroupTest_Set_Phase3_Failed_Action_Response": { + "runAfter": { + "RestoreGroupTest_Set_Phase3_Failed_Action_Name": [ + "Succeeded" + ] + }, + "type": "SetVariable", "inputs": { - "method": "DELETE", - "uri": "@{concat(parameters('scimEndpoint'), '/Groups/', coalesce(first(body('POD_SCIM_Get_Group')?['Resources'])?['id'], 'not-found'))}", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } + "name": "RestoreGroupFailedActionResponse", + "value": "@if(greater(length(body('RestoreGroupTest_Filter_Phase3_Failed_Actions')), 0), coalesce(first(body('RestoreGroupTest_Filter_Phase3_Failed_Actions'))?['outputs'], json('{}')), json('{}'))" } - }, - "POD_Group_Cleanup_Remove_AppRole": { - "runAfter": { "POD_Group_Cleanup_SCIM_Delete": ["Succeeded", "Failed", "Skipped"] }, - "type": "Http", + }, + "RestoreGroupTest_Set_Phase3_Status_Failed": { + "runAfter": { + "RestoreGroupTest_Set_Phase3_Failed_Action_Response": [ + "Succeeded" + ] + }, + "type": "SetVariable", "inputs": { - "method": "DELETE", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', coalesce(body('POD_Create_Graph_Group')?['id'], 'not-found'), '/appRoleAssignments/', coalesce(body('POD_Group_Assign_AppRole')?['id'], 'not-found'))}", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } + "name": "RestoreGroupScopeExecutionStatus", + "value": "Failed" } + } }, - "POD_Group_Cleanup_Graph_Delete": { - "runAfter": { "POD_Group_Cleanup_Remove_AppRole": ["Succeeded", "Failed", "Skipped"] }, - "type": "Http", + "runAfter": { + "RestoreGroupTest_Phase3_Reassign": [ + "Failed" + ] + }, + "type": "Scope" + }, + "RestoreGroupTest_Set_Phase3_Status_Success": { + "runAfter": { + "RestoreGroupTest_Phase3_Reassign": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "RestoreGroupScopeExecutionStatus", + "value": "Succeeded" + } + }, + "RestoreGroupTest_Analyze_Phase3_Provisioning_Results": { + "runAfter": { + "RestoreGroupTest_Phase3_Reassign": [ + "Succeeded", + "Failed", + "TimedOut" + ], + "RestoreGroupTest_Capture_Phase3_Failed_Actions": [ + "Succeeded", + "Skipped" + ], + "RestoreGroupTest_Set_Phase3_Status_Success": [ + "Succeeded", + "Skipped" + ] + }, + "type": "Compose", + "inputs": { + "provisioningLogsCount": "@length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]')))", + "hasProvisioningLogs": "@greater(length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]'))), 0)", + "scimGroupRestored": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0)", + "provisioningResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]'))), 0), 'success', 'RestoreGroupTest_Get_Restore_Log: NO_LOGS_FOUND'), concat('Failed Action: ', variables('RestoreGroupFailedActionName')))", + "provisioningErrorDetails": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), null, variables('RestoreGroupFailedActionResponse'))", + "scimCheckResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0), 'success', 'RestoreGroupTest: Group not restored on SCIM server after reassign'), concat('Failed Action: ', variables('RestoreGroupFailedActionName')))", + "overallResult": "@if(equals(variables('RestoreGroupScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]'))), 0), greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0)), 'PASSED', 'FAILED'), 'FAILED')" + } + }, + "RestoreGroupTest_Set_Phase3_Output_Variables": { + "actions": { + "RestoreGroupTest_Set_RestoreGroupTestOutputs_Phase3": { + "type": "SetVariable", "inputs": { - "method": "DELETE", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', coalesce(body('POD_Create_Graph_Group')?['id'], 'not-found'))}", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" + "name": "RestoreGroupTestOutputs", + "value": { + "result": "@if(and(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success (UnassignReassign)', if(startsWith(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Reassign Phase] ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Reassign Phase] Provisioning: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''))))", + "overallResult": "@outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['overallResult']", + "provisioningLogsResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), 'success', 'failure')", + "scimCheckResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", + "errorDetails": { + "provisioningLogs": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed'))", + "scimCheck": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, 'Group not restored on SCIM server after reassign')" } + } } - } + } + }, + "runAfter": { + "RestoreGroupTest_Analyze_Phase3_Provisioning_Results": [ + "Succeeded", + "Failed" + ] + }, + "type": "Scope" + } + }, + "runAfter": { + "RestoreGroupTest_Set_Phase2_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "else": { + "actions": {} }, - "runAfter": {}, "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] - }, - { - "or": [ - { "equals": ["@triggerBody()?['EnabledTests']", "All"] }, - { "equals": ["@triggerBody()?['EnabledTests']", "GroupTests"] }, - { "equals": ["@triggerBody()?['EnabledTests']", "POD_Group_Test"] } - ] - } - ] + "and": [ + { + "equals": [ + "@toLower(variables('RestoreGroupTestOutputs')['overallResult'])", + "passed" + ] + } + ] }, "type": "If" + } + }, + "runAfter": { + "RestoreGroupTest_Set_Phase1_Output_Variables": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, + "else": { + "actions": {} + }, + "expression": { + "and": [ + { + "equals": [ + "@toLower(variables('RestoreGroupTestOutputs')['overallResult'])", + "passed" + ] + } + ] + }, + "type": "If" + }, + "RestoreGroupTest_Cleanup_DeleteGroup": { + "runAfter": { + "RestoreGroupTest_Check_Phase1_Status": [ + "Succeeded", + "Failed", + "Skipped", + "TimedOut" + ] + }, + "type": "Http", + "inputs": { + "method": "DELETE", + "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'))}", + "authentication": { + "type": "ManagedServiceIdentity", + "audience": "https://graph.microsoft.com/" + } } -, - "Restore_Group_Test": { - "runAfter": {}, - "actions": { - "RestoreGroupTest_Actions": { - "type": "Scope", - "actions": { - "RestoreGroupTest_Phase1_Create_And_Assign": { - "type": "Scope", - "actions": { - "RestoreGroupTest_Create_Entra_Group": { - "type": "Http", - "inputs": { - "method": "POST", - "uri": "https://graph.microsoft.com/v1.0/groups", - "headers": { "Content-Type": "application/json" }, - "body": { - "displayName": "@{coalesce(triggerBody()?['initializationData']?['testGroupNames']?['restoreGroup'], concat('RestoreGrp-', substring(guid(),0,8)))}", - "mailEnabled": false, - "mailNickname": "@{concat('restoregrp', substring(guid(),0,8))}", - "securityEnabled": true, - "groupTypes": [] - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" + } } } }, - "RestoreGroupTest_Set_EntraGroupId": { - "runAfter": { "RestoreGroupTest_Create_Entra_Group": ["Succeeded"] }, - "type": "SetVariable", - "inputs": { - "name": "restoreEntraGroupId", - "value": "@{body('RestoreGroupTest_Create_Entra_Group')?['id']}" - } - }, - "RestoreGroupTest_Delay_Before_AppRole": { - "runAfter": { "RestoreGroupTest_Set_EntraGroupId": ["Succeeded"] }, - "type": "Wait", - "inputs": { - "interval": { - "count": 30, - "unit": "Second" - } - } + "else": { + "actions": {} }, - "RestoreGroupTest_Assign_AppRole": { - "runAfter": { "RestoreGroupTest_Delay_Before_AppRole": ["Succeeded"] }, - "type": "Http", - "inputs": { - "method": "POST", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'), '/appRoleAssignments')}", - "headers": { "Content-Type": "application/json" }, - "body": { - "principalId": "@{variables('restoreEntraGroupId')}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" + "expression": { + "and": [ + { + "equals": [ + "@triggerBody()?['initializationData']?['isGroupSupported']", + true + ] }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "RestoreGroupTest_Set_AppRoleAssignmentId": { - "runAfter": { "RestoreGroupTest_Assign_AppRole": ["Succeeded"] }, - "type": "SetVariable", - "inputs": { - "name": "restoreGroupAppRoleAssignmentId", - "value": "@{body('RestoreGroupTest_Assign_AppRole')?['id']}" - } - }, - "RestoreGroupTest_DoUntil_Verify_SCIM_Create": { - "runAfter": { "RestoreGroupTest_Set_AppRoleAssignmentId": ["Succeeded"] }, - "type": "Until", - "expression": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Created')?['Resources'], json('[]'))), 0)", - "limit": { "count": 200, "timeout": "PT50M" }, - "actions": { - "RestoreGroupTest_SCIM_Check_Created": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(body('RestoreGroupTest_Create_Entra_Group')?['displayName']), '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" + { + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Restore_Group_Test" + ] } - } - }, - "RestoreGroupTest_Delay_Create_15s": { - "runAfter": { "RestoreGroupTest_SCIM_Check_Created": ["Succeeded", "Failed"] }, - "type": "Wait", - "inputs": { "interval": { "count": 15, "unit": "Second" } } + ] } - } + ] }, - "RestoreGroupTest_Get_Create_Log": { - "runAfter": { "RestoreGroupTest_DoUntil_Verify_SCIM_Create": ["Succeeded", "Failed"] }, - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', variables('restoreEntraGroupId'), '%27%20and%20provisioningAction%20eq%20%27Create%27')}", - "method": "GET", - "headers": { "Accept": "application/json" }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - } + "type": "If" } }, - "RestoreGroupTest_Phase2_Unassign": { - "runAfter": { "RestoreGroupTest_Phase1_Create_And_Assign": ["Succeeded"] }, - "type": "Scope", - "actions": { - "RestoreGroupTest_Unassign_AppRole": { - "type": "Http", - "inputs": { - "method": "DELETE", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'), '/appRoleAssignments/', variables('restoreGroupAppRoleAssignmentId'))}", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "RestoreGroupTest_DoUntil_Verify_SCIM_Gone": { - "runAfter": { "RestoreGroupTest_Unassign_AppRole": ["Succeeded"] }, - "type": "Until", - "expression": "@equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[\"placeholder\"]'))), 0)", - "limit": { "count": 200, "timeout": "PT50M" }, - "actions": { - "RestoreGroupTest_SCIM_Check_Gone": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(body('RestoreGroupTest_Create_Entra_Group')?['displayName']), '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "RestoreGroupTest_Delay_Gone_15s": { - "runAfter": { "RestoreGroupTest_SCIM_Check_Gone": ["Succeeded", "Failed"] }, - "type": "Wait", - "inputs": { "interval": { "count": 15, "unit": "Second" } } - } - } - }, - "RestoreGroupTest_Get_Delete_Log": { - "runAfter": { "RestoreGroupTest_DoUntil_Verify_SCIM_Gone": ["Succeeded", "Failed"] }, - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', variables('restoreEntraGroupId'), '%27%20and%20provisioningAction%20eq%20%27Delete%27')}", - "method": "GET", - "headers": { "Accept": "application/json" }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - } - } + "runAfter": { + "Response_Immediate": [ + "Succeeded" + ], + "Initialize_PODGroupTestOutputs": [ + "Succeeded" + ], + "Initialize_RestoreGroupScopeExecutionStatus": [ + "Succeeded" + ] }, - "RestoreGroupTest_Phase3_Reassign": { - "runAfter": { "RestoreGroupTest_Phase2_Unassign": ["Succeeded"] }, - "type": "Scope", - "actions": { - "RestoreGroupTest_Reassign_AppRole": { - "type": "Http", - "inputs": { - "method": "POST", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'), '/appRoleAssignments')}", - "headers": { "Content-Type": "application/json" }, - "body": { - "principalId": "@{variables('restoreEntraGroupId')}", - "resourceId": "@{parameters('servicePrincipalId')}", - "appRoleId": "@{coalesce(first(triggerBody()?['initializationData']?['userAppRole'])?['id'], first(triggerBody()?['initializationData']?['appRoles']?['appRoles'])?['id'])}" - }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, - "RestoreGroupTest_DoUntil_Verify_SCIM_Restored": { - "runAfter": { "RestoreGroupTest_Reassign_AppRole": ["Succeeded"] }, - "type": "Until", - "expression": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0)", - "limit": { "count": 200, "timeout": "PT50M" }, - "actions": { - "RestoreGroupTest_SCIM_Check_Restored": { - "type": "Http", - "inputs": { - "uri": "@{concat(parameters('scimEndpoint'), '/Groups?filter=displayName%20eq%20%22', encodeUriComponent(body('RestoreGroupTest_Create_Entra_Group')?['displayName']), '%22')}", - "method": "GET", - "headers": { - "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", - "Accept": "@{parameters('scimContentType')}" - } - } - }, - "RestoreGroupTest_Delay_Restored_15s": { - "runAfter": { "RestoreGroupTest_SCIM_Check_Restored": ["Succeeded", "Failed"] }, - "type": "Wait", - "inputs": { "interval": { "count": 15, "unit": "Second" } } - } - } - }, - "RestoreGroupTest_Get_Restore_Log": { - "runAfter": { "RestoreGroupTest_DoUntil_Verify_SCIM_Restored": ["Succeeded", "Failed"] }, - "type": "Http", - "inputs": { - "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', variables('restoreEntraGroupId'), '%27%20and%20provisioningAction%20eq%20%27Create%27')}", - "method": "GET", - "headers": { "Accept": "application/json" }, - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - } - } + "type": "Scope" + }, + "Compose_Final_Results": { + "runAfter": { + "GroupTests_Scope": [ + "Succeeded", + "Failed", + "Skipped", + "TimedOut" + ] }, - "RestoreGroupTest_Compose_Summary": { - "runAfter": { - "RestoreGroupTest_Phase3_Reassign": ["Succeeded", "Failed", "Skipped"] - }, - "type": "Compose", - "inputs": { - "testName": "Restore_Group_Test", - "timestamp": "@utcNow()", - "entraGroupId": "@variables('restoreEntraGroupId')", - "phase1_createLogFound": "@greater(length(coalesce(body('RestoreGroupTest_Get_Create_Log')?['value'], json('[]'))), 0)", - "phase1_scimGroupFound": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Created')?['Resources'], json('[]'))), 0)", - "phase2_deleteLogFound": "@greater(length(coalesce(body('RestoreGroupTest_Get_Delete_Log')?['value'], json('[]'))), 0)", - "phase2_scimGroupGone": "@equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[]'))), 0)", - "phase3_restoreLogFound": "@greater(length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]'))), 0)", - "phase3_scimGroupRestored": "@greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0)", - "overallResult": "@if(and(and(and(greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Created')?['Resources'], json('[]'))), 0), equals(length(coalesce(body('RestoreGroupTest_SCIM_Check_Gone')?['Resources'], json('[]'))), 0)), greater(length(coalesce(body('RestoreGroupTest_SCIM_Check_Restored')?['Resources'], json('[]'))), 0)), greater(length(coalesce(body('RestoreGroupTest_Get_Restore_Log')?['value'], json('[]'))), 0)), 'PASSED', 'FAILED')" - } - } - } - }, - "RestoreGroupTest_Set_Outputs": { - "runAfter": { "RestoreGroupTest_Actions": ["Succeeded", "Failed", "Skipped"] }, - "type": "SetVariable", - "inputs": { - "name": "RestoreGroupTestOutputs", - "value": { - "overallResult": "@coalesce(outputs('RestoreGroupTest_Compose_Summary')?['overallResult'], 'FAILED')", - "result": "@if(equals(coalesce(outputs('RestoreGroupTest_Compose_Summary')?['overallResult'], 'FAILED'), 'PASSED'), 'success (UnassignReassign)', if(equals(coalesce(outputs('RestoreGroupTest_Compose_Summary')?['phase1_scimGroupFound'], false), false), 'FAILED - [Create Phase] Action: RestoreGroupTest_SCIM_Check_Created - group not found on SCIM endpoint after provisioning', if(equals(coalesce(outputs('RestoreGroupTest_Compose_Summary')?['phase2_scimGroupGone'], false), false), 'FAILED - [Unassign Phase] Action: RestoreGroupTest_SCIM_Check_Gone - group still present on SCIM endpoint after unassign', 'FAILED - [Reassign Phase] Action: RestoreGroupTest_SCIM_Check_Restored - group not restored on SCIM endpoint after reassign')))", - "summary": "@outputs('RestoreGroupTest_Compose_Summary')", - "detailedResults": [], - "errorDetails": { - "summary": "@if(equals(coalesce(outputs('RestoreGroupTest_Compose_Summary')?['overallResult'], 'FAILED'), 'PASSED'), null, string(outputs('RestoreGroupTest_Compose_Summary')))" - } + "type": "Compose", + "inputs": { + "CreateGroupTestOutputs": "@variables('CreateGroupTestOutputs')", + "UpdateGroupTestOutputs": "@variables('UpdateGroupTestOutputs')", + "DeleteGroupTestOutputs": "@variables('DeleteGroupTestOutputs')", + "AddMemberTestOutputs": "@variables('AddMemberTestOutputs')", + "RemoveMemberTestOutputs": "@variables('RemoveMemberTestOutputs')", + "PODGroupTestOutputs": "@variables('PODGroupTestOutputs')", + "RestoreGroupTestOutputs": "@variables('RestoreGroupTestOutputs')", + "testSuiteName": "GroupTests", + "status": "@if(or(or(or(or(or(equals(variables('CreateGroupTestOutputs')['overallResult'], 'FAILED'), equals(variables('UpdateGroupTestOutputs')['overallResult'], 'FAILED')), equals(variables('DeleteGroupTestOutputs')['overallResult'], 'FAILED')), equals(variables('AddMemberTestOutputs')['overallResult'], 'FAILED')), equals(variables('RemoveMemberTestOutputs')['overallResult'], 'FAILED')), equals(variables('PODGroupTestOutputs')['overallResult'], 'FAILED')), 'Failed', 'Passed')", + "workflowRunId": "@workflow().run.name" } } }, - "RestoreGroupTest_Cleanup": { - "runAfter": { "RestoreGroupTest_Set_Outputs": ["Succeeded", "Failed", "Skipped"] }, - "type": "Http", - "inputs": { - "method": "DELETE", - "uri": "@{concat('https://graph.microsoft.com/v1.0/groups/', variables('restoreEntraGroupId'))}", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - } - }, - "else": { "actions": {} }, - "expression": { - "and": [ - { - "equals": [ - "@triggerBody()?['initializationData']?['isGroupSupported']", - true - ] - }, - { - "or": [ - { "equals": ["@triggerBody()?['EnabledTests']", "All"] }, - { "equals": ["@triggerBody()?['EnabledTests']", "GroupTests"] }, - { "equals": ["@triggerBody()?['EnabledTests']", "Restore_Group_Test"] } - ] - } - ] + "outputs": {} }, - "type": "If" -} - }, - "runAfter": { - "Response_Immediate": [ - "Succeeded" - ], - "Initialize_PODGroupTestOutputs": [ - "Succeeded" - ], - "Initialize_RestoreGroupTestVariables": [ - "Succeeded" - ] - }, - "type": "Scope" - }, - "Compose_Final_Results": { - "runAfter": { - "GroupTests_Scope": [ - "Succeeded", - "Failed", - "Skipped", - "TimedOut" - ] - }, - "type": "Compose", - "inputs": { - "CreateGroupTestOutputs": "@variables('CreateGroupTestOutputs')", - "UpdateGroupTestOutputs": "@variables('UpdateGroupTestOutputs')", - "DeleteGroupTestOutputs": "@variables('DeleteGroupTestOutputs')", - "AddMemberTestOutputs": "@variables('AddMemberTestOutputs')", - "RemoveMemberTestOutputs": "@variables('RemoveMemberTestOutputs')", - "PODGroupTestOutputs": "@variables('PODGroupTestOutputs')", - "RestoreGroupTestOutputs": "@variables('RestoreGroupTestOutputs')", - "testSuiteName": "GroupTests", - "status": "@if(or(or(or(or(or(equals(variables('CreateGroupTestOutputs')['overallResult'], 'FAILED'), equals(variables('UpdateGroupTestOutputs')['overallResult'], 'FAILED')), equals(variables('DeleteGroupTestOutputs')['overallResult'], 'FAILED')), equals(variables('AddMemberTestOutputs')['overallResult'], 'FAILED')), equals(variables('RemoveMemberTestOutputs')['overallResult'], 'FAILED')), equals(variables('PODGroupTestOutputs')['overallResult'], 'FAILED')), 'Failed', 'Passed')", - "workflowRunId": "@workflow().run.name" - } - } - }, - "outputs": {} - }, - "kind": "Stateful" + "kind": "Stateful" } \ No newline at end of file diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Parameters.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Parameters.json index 79b2c026..1848b803 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Parameters.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Parameters.json @@ -18,6 +18,7 @@ "Schema_Discoverability_Test", "SCIM_Null_Update_Test", "Validate_Credentials_Test", + "Federated_Identity_Test", "SCIM_User_Create_Test", "SCIM_Group_Create_Test", "SCIM_User_Update_Test", @@ -28,7 +29,8 @@ "SCIM_Group_Pagination_Test", "POD_User_Test", "POD_Group_Test", - "Restore_User_Test" + "Restore_User_Test", + "Restore_Group_Test" ], "type": "String", "value": "All" @@ -248,6 +250,55 @@ }, "type": "String", "value": "https://scimserver2.yellowsmoke-af7a3fff.eastus.azurecontainerapps.io/scim/oauth/token" + }, + "federatedEntraTenantId": { + "metadata": { + "description": "Entra tenant ID used to construct the token endpoint URL for federated identity token acquisition." + }, + "type": "String", + "value": "changeme-tenant-id" + }, + "federatedApplicationId": { + "metadata": { + "description": "OAuth2 Application ID for the Entra app registration used in federated identity token acquisition." + }, + "type": "String", + "value": "changeme-client-id" + }, + "federatedApplicationClientSecret": { + "metadata": { + "description": "OAuth2 Client Secret for the Entra app registration used in federated identity token acquisition." + }, + "type": "String", + "value": "changeme-client-secret" + }, + "federatedTokenEndpoint": { + "metadata": { + "description": "ISV token endpoint URL for federated identity token exchange." + }, + "type": "String", + "value": "changeme-federated-endpoint" + }, + "federatedClientId": { + "metadata": { + "description": "ISV client ID used in federated identity token exchange." + }, + "type": "String", + "value": "changeme-federated-app-id" + }, + "federatedBaseAddress": { + "metadata": { + "description": "ISV base address sent in the federated identity token exchange request." + }, + "type": "String", + "value": "changeme-base-address" + }, + "federatedAudience": { + "metadata": { + "description": "Audience value for federated token exchange." + }, + "type": "String", + "value": "changeme-audience" }, "servicePrincipalId": { "type": "String", diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json index a1522f50..eea20d17 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json @@ -460,6 +460,7 @@ "scimUserUpdateTestEnabled": "@or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'SCIM_User_Update_Test'))", "scimGroupUpdateTestEnabled": "@and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false), or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'SCIM_Group_Update_Test')))", "validateCredentialsTestEnabled": "@or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'Validate_Credentials_Test'))", + "federatedIdentityTestEnabled": "@or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'Federated_Identity_Test'))", "scimUserPaginationTestEnabled": "@or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'SCIM_User_Pagination_Test'))", "scimGroupPaginationTestEnabled": "@and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false), or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'SCIM_Group_Pagination_Test')))" }, @@ -485,6 +486,7 @@ "scimUserUpdateTestResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'], 'SKIPPED')", "scimGroupUpdateTestResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'], 'SKIPPED')", "validateCredentialsTestResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED')", + "federatedIdentityTestResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED')", "scimUserPaginationTestResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED')", "scimGroupPaginationTestResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED')" }, @@ -500,7 +502,7 @@ "GroupTests_Workflow": "@outputs('Compose_GroupTests_RunLink')", "SCIMTests_Workflow": "@outputs('Compose_SCIMTests_RunLink')" }, - "overallLogicAppResult": "@if(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(equals(coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), equals(coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), or(equals(coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'))), equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(actions('Call_Initialization_Workflow')?['status'], 'Failed')), equals(coalesce(body('Poll_UserTests_Status')?['properties']?['status'], ''), 'Failed')), equals(coalesce(body('Poll_GroupTests_Status')?['properties']?['status'], ''), 'Failed')), 'Failed', if(equals(coalesce(body('Poll_SCIMTests_Status')?['properties']?['status'], ''), 'Failed'), 'Failed', 'Succeeded'))" + "overallLogicAppResult": "@if(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(equals(coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), equals(coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), or(equals(coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'))), equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(actions('Call_Initialization_Workflow')?['status'], 'Failed')), equals(coalesce(body('Poll_UserTests_Status')?['properties']?['status'], ''), 'Failed')), equals(coalesce(body('Poll_GroupTests_Status')?['properties']?['status'], ''), 'Failed')), 'Failed', if(equals(coalesce(body('Poll_SCIMTests_Status')?['properties']?['status'], ''), 'Failed'), 'Failed', 'Succeeded'))" } }, "Final_TestResults": { @@ -656,6 +658,14 @@ "runLink": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))", "message": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', 'Click the runLink and search for the action Compose_Final_Results for more info.')" }, + { + "testName": "Federated_Identity_Test", + "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['result'], 'SKIPPED')", + "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['errorDetails'], '')", + "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", + "runLink": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))", + "message": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', 'Click the runLink and search for the action Compose_Final_Results for more info.')" + }, { "testName": "SCIM_User_Pagination_Test", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['result'], 'SKIPPED')", diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json index 13f5b197..3d423b80 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json @@ -129,6 +129,19 @@ } } }, + { + "name": "FederatedIdentityTestOutputs", + "type": "Object", + "value": { + "overallResult": "SKIPPED", + "result": "SKIPPED", + "summary": null, + "detailedResults": [], + "errorDetails": { + "summary": null + } + } + }, { "name": "flattenedUserAttrNames", "type": "Array", @@ -2976,6 +2989,522 @@ ] }, "type": "If" + }, + "Federated_Identity_Test": { + "runAfter": {}, + "actions": { + "Acquire_Entra_Token": { + "type": "Http", + "inputs": { + "uri": "@{concat('https://login.microsoftonline.com/', parameters('federatedEntraTenantId'), '/oauth2/v2.0/token')}", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "@{concat('grant_type=client_credentials&client_id=', encodeUriComponent(parameters('federatedApplicationId')), '&client_secret=', encodeUriComponent(parameters('federatedApplicationClientSecret')), '&scope=', encodeUriComponent(concat('api://', parameters('federatedApplicationId'), '/.default')))}" + } + }, + "Check_Entra_Token_Acquired": { + "runAfter": { + "Acquire_Entra_Token": ["Succeeded", "Failed", "TimedOut"] + }, + "type": "If", + "expression": { + "and": [ + { + "greaterOrEquals": [ + "@coalesce(outputs('Acquire_Entra_Token')?['statusCode'], 0)", + 200 + ] + }, + { + "less": [ + "@coalesce(outputs('Acquire_Entra_Token')?['statusCode'], 0)", + 300 + ] + }, + { + "not": { + "equals": [ + "@coalesce(body('Acquire_Entra_Token')?['access_token'], '')", + "" + ] + } + } + ] + }, + "actions": { + "Check_Is_Google_SA_Flow": { + "type": "If", + "expression": { + "and": [ + { + "contains": [ + "@parameters('federatedTokenEndpoint')", + "googleapis.com" + ] + }, + { + "contains": [ + "@parameters('federatedTokenEndpoint')", + "serviceAccounts" + ] + } + ] + }, + "actions": { + "Acquire_Google_STS_Token": { + "type": "Http", + "inputs": { + "uri": "https://sts.googleapis.com/v1/token", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", + "audience": "@{parameters('federatedAudience')}", + "requested_token_type": "urn:ietf:params:oauth:token-type:access_token", + "subject_token": "@{body('Acquire_Entra_Token')?['access_token']}", + "subject_token_type": "urn:ietf:params:oauth:token-type:id_token", + "scope": "https://www.googleapis.com/auth/cloud-platform" + } + } + }, + "Check_Google_STS_Token": { + "runAfter": { + "Acquire_Google_STS_Token": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "type": "If", + "expression": { + "and": [ + { + "greaterOrEquals": [ + "@coalesce(outputs('Acquire_Google_STS_Token')?['statusCode'], 0)", + 200 + ] + }, + { + "less": [ + "@coalesce(outputs('Acquire_Google_STS_Token')?['statusCode'], 0)", + 300 + ] + }, + { + "not": { + "equals": [ + "@coalesce(body('Acquire_Google_STS_Token')?['access_token'], '')", + "" + ] + } + } + ] + }, + "actions": { + "Acquire_Google_SA_Token": { + "type": "Http", + "inputs": { + "uri": "@{parameters('federatedTokenEndpoint')}", + "method": "POST", + "headers": { + "Content-Type": "application/json", + "Authorization": "@{concat('Bearer ', body('Acquire_Google_STS_Token')?['access_token'])}" + }, + "body": { + "scope": [ + "https://www.googleapis.com/auth/cloud-platform" + ] + } + } + }, + "Check_Google_SA_Token": { + "runAfter": { + "Acquire_Google_SA_Token": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "type": "If", + "expression": { + "and": [ + { + "greaterOrEquals": [ + "@coalesce(outputs('Acquire_Google_SA_Token')?['statusCode'], 0)", + 200 + ] + }, + { + "less": [ + "@coalesce(outputs('Acquire_Google_SA_Token')?['statusCode'], 0)", + 300 + ] + }, + { + "not": { + "equals": [ + "@coalesce(body('Acquire_Google_SA_Token')?['accessToken'], '')", + "" + ] + } + } + ] + }, + "actions": { + "Compose_Federated_Validation_Summary_GoogleSA": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity_Google_SA", + "entraTokenAcquisition": { + "endpoint": "@concat('https://login.microsoftonline.com/', parameters('federatedEntraTenantId'), '/oauth2/v2.0/token')", + "statusCode": "@outputs('Acquire_Entra_Token')['statusCode']", + "passed": true + }, + "googleStsTokenExchange": { + "endpoint": "https://sts.googleapis.com/v1/token", + "statusCode": "@outputs('Acquire_Google_STS_Token')['statusCode']", + "passed": true + }, + "googleSaImpersonation": { + "endpoint": "@parameters('federatedTokenEndpoint')", + "statusCode": "@outputs('Acquire_Google_SA_Token')['statusCode']", + "passed": true + }, + "overallResult": "PASSED" + } + } + }, + "else": { + "actions": { + "Compose_Federated_Validation_Summary_GoogleSA_Fail": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity_Google_SA", + "entraTokenAcquisition": { + "passed": true + }, + "googleStsTokenExchange": { + "passed": true + }, + "googleSaImpersonation": { + "endpoint": "@parameters('federatedTokenEndpoint')", + "statusCode": "@coalesce(outputs('Acquire_Google_SA_Token')?['statusCode'], 0)", + "hasAccessToken": "@not(equals(coalesce(body('Acquire_Google_SA_Token')?['accessToken'], ''), ''))", + "passed": false + }, + "overallResult": "FAILED" + } + } + } + } + } + }, + "else": { + "actions": { + "Compose_Federated_Validation_Summary_GoogleSTS_Fail": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity_Google_SA", + "entraTokenAcquisition": { + "passed": true + }, + "googleStsTokenExchange": { + "endpoint": "https://sts.googleapis.com/v1/token", + "statusCode": "@coalesce(outputs('Acquire_Google_STS_Token')?['statusCode'], 0)", + "hasAccessToken": "@not(equals(coalesce(body('Acquire_Google_STS_Token')?['access_token'], ''), ''))", + "passed": false + }, + "overallResult": "FAILED" + } + } + } + } + } + }, + "else": { + "actions": { + "Check_Is_Google_STS_Flow": { + "type": "If", + "expression": { + "and": [ + { + "contains": [ + "@parameters('federatedTokenEndpoint')", + "googleapis.com" + ] + } + ] + }, + "actions": { + "Acquire_Google_STS_Token_Only": { + "type": "Http", + "inputs": { + "uri": "@{parameters('federatedTokenEndpoint')}", + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", + "audience": "@{parameters('federatedAudience')}", + "requested_token_type": "urn:ietf:params:oauth:token-type:access_token", + "subject_token": "@{body('Acquire_Entra_Token')?['access_token']}", + "subject_token_type": "urn:ietf:params:oauth:token-type:id_token", + "scope": "https://www.googleapis.com/auth/cloud-platform" + } + } + }, + "Check_Google_STS_Only_Token": { + "runAfter": { + "Acquire_Google_STS_Token_Only": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "type": "If", + "expression": { + "and": [ + { + "greaterOrEquals": [ + "@coalesce(outputs('Acquire_Google_STS_Token_Only')?['statusCode'], 0)", + 200 + ] + }, + { + "less": [ + "@coalesce(outputs('Acquire_Google_STS_Token_Only')?['statusCode'], 0)", + 300 + ] + }, + { + "not": { + "equals": [ + "@coalesce(body('Acquire_Google_STS_Token_Only')?['access_token'], '')", + "" + ] + } + } + ] + }, + "actions": { + "Compose_Federated_Validation_Summary_GoogleSTSOnly": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity_Google_STS", + "entraTokenAcquisition": { + "endpoint": "@concat('https://login.microsoftonline.com/', parameters('federatedEntraTenantId'), '/oauth2/v2.0/token')", + "statusCode": "@outputs('Acquire_Entra_Token')['statusCode']", + "passed": true + }, + "googleStsTokenExchange": { + "endpoint": "@parameters('federatedTokenEndpoint')", + "statusCode": "@outputs('Acquire_Google_STS_Token_Only')['statusCode']", + "passed": true + }, + "overallResult": "PASSED" + } + } + }, + "else": { + "actions": { + "Compose_Federated_Validation_Summary_GoogleSTSOnly_Fail": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity_Google_STS", + "entraTokenAcquisition": { + "passed": true + }, + "googleStsTokenExchange": { + "endpoint": "@parameters('federatedTokenEndpoint')", + "statusCode": "@coalesce(outputs('Acquire_Google_STS_Token_Only')?['statusCode'], 0)", + "hasAccessToken": "@not(equals(coalesce(body('Acquire_Google_STS_Token_Only')?['access_token'], ''), ''))", + "passed": false + }, + "overallResult": "FAILED" + } + } + } + } + } + }, + "else": { + "actions": { + "Acquire_Federated_Token": { + "type": "Http", + "inputs": { + "uri": "@{parameters('federatedTokenEndpoint')}", + "method": "POST", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": "@{concat('grant_type=client_credentials&client_id=', encodeUriComponent(parameters('federatedClientId')), '&client_assertion=', encodeUriComponent(body('Acquire_Entra_Token')?['access_token']), '&client_assertion_type=', encodeUriComponent('urn:ietf:params:oauth:client-assertion-type:jwt-bearer'), '&baseAddress=', encodeUriComponent(parameters('federatedBaseAddress')))}" + } + }, + "Check_Federated_Token_Acquired": { + "runAfter": { + "Acquire_Federated_Token": [ + "Succeeded", + "Failed", + "TimedOut" + ] + }, + "type": "If", + "expression": { + "and": [ + { + "greaterOrEquals": [ + "@coalesce(outputs('Acquire_Federated_Token')?['statusCode'], 0)", + 200 + ] + }, + { + "less": [ + "@coalesce(outputs('Acquire_Federated_Token')?['statusCode'], 0)", + 300 + ] + }, + { + "not": { + "equals": [ + "@coalesce(body('Acquire_Federated_Token')?['access_token'], '')", + "" + ] + } + } + ] + }, + "actions": { + "Compose_Federated_Validation_Summary": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity", + "entraTokenAcquisition": { + "endpoint": "@concat('https://login.microsoftonline.com/', parameters('federatedEntraTenantId'), '/oauth2/v2.0/token')", + "statusCode": "@outputs('Acquire_Entra_Token')['statusCode']", + "passed": true + }, + "federatedTokenExchange": { + "endpoint": "@parameters('federatedTokenEndpoint')", + "statusCode": "@outputs('Acquire_Federated_Token')['statusCode']", + "passed": true + }, + "overallResult": "PASSED" + } + } + }, + "else": { + "actions": { + "Compose_Federated_Validation_Summary_TokenFail": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity", + "entraTokenAcquisition": { + "passed": true + }, + "federatedTokenExchange": { + "endpoint": "@parameters('federatedTokenEndpoint')", + "statusCode": "@coalesce(outputs('Acquire_Federated_Token')?['statusCode'], 0)", + "hasAccessToken": "@not(equals(coalesce(body('Acquire_Federated_Token')?['access_token'], ''), ''))", + "passed": false + }, + "overallResult": "FAILED" + } + } + } + } + } + } + } + } + } + } + } + }, + "else": { + "actions": { + "Compose_Federated_Validation_Summary_EntraFail": { + "type": "Compose", + "inputs": { + "testName": "Federated_Identity_Test", + "timestamp": "@utcNow()", + "authMode": "FederatedIdentity", + "entraTokenAcquisition": { + "endpoint": "@concat('https://login.microsoftonline.com/', parameters('federatedEntraTenantId'), '/oauth2/v2.0/token')", + "statusCode": "@coalesce(outputs('Acquire_Entra_Token')?['statusCode'], 0)", + "hasAccessToken": "@not(equals(coalesce(body('Acquire_Entra_Token')?['access_token'], ''), ''))", + "passed": false + }, + "federatedTokenExchange": null, + "scimEndpointValidation": null, + "overallResult": "FAILED" + } + } + } + } + }, + "Set_FederatedIdentityTestOutputs": { + "runAfter": { + "Check_Entra_Token_Acquired": [ + "Succeeded", + "Failed", + "TimedOut", + "Skipped" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "FederatedIdentityTestOutputs", + "value": { + "overallResult": "@coalesce(outputs('Compose_Federated_Validation_Summary')?['overallResult'], outputs('Compose_Federated_Validation_Summary_TokenFail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSA')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSA_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTS_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_EntraFail')?['overallResult'], 'FAILED')", + "result": "@if(equals(coalesce(outputs('Compose_Federated_Validation_Summary')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSA')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly')?['overallResult'], outputs('Compose_Federated_Validation_Summary_TokenFail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSA_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTS_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_EntraFail')?['overallResult'], 'FAILED'), 'PASSED'), 'success', if(not(empty(coalesce(outputs('Compose_Federated_Validation_Summary_EntraFail'), json('null')))), 'Entra token acquisition failed', 'Federated token exchange failed'))", + "summary": "@coalesce(outputs('Compose_Federated_Validation_Summary'), outputs('Compose_Federated_Validation_Summary_TokenFail'), outputs('Compose_Federated_Validation_Summary_GoogleSA'), outputs('Compose_Federated_Validation_Summary_GoogleSA_Fail'), outputs('Compose_Federated_Validation_Summary_GoogleSTS_Fail'), outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly'), outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly_Fail'), outputs('Compose_Federated_Validation_Summary_EntraFail'))", + "detailedResults": [], + "errorDetails": { + "summary": "@if(equals(coalesce(outputs('Compose_Federated_Validation_Summary')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSA')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly')?['overallResult'], outputs('Compose_Federated_Validation_Summary_TokenFail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSA_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTS_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly_Fail')?['overallResult'], outputs('Compose_Federated_Validation_Summary_EntraFail')?['overallResult'], 'FAILED'), 'PASSED'), null, if(not(empty(coalesce(outputs('Compose_Federated_Validation_Summary_EntraFail'), json('null')))), concat('Entra token acquisition failed. Status: ', string(coalesce(outputs('Acquire_Entra_Token')?['statusCode'], 0))), if(not(empty(coalesce(outputs('Compose_Federated_Validation_Summary_GoogleSTS_Fail'), json('null')))), concat('Google STS token exchange failed. Status: ', string(coalesce(outputs('Acquire_Google_STS_Token')?['statusCode'], 0))), if(not(empty(coalesce(outputs('Compose_Federated_Validation_Summary_GoogleSA_Fail'), json('null')))), concat('Google SA impersonation failed. Status: ', string(coalesce(outputs('Acquire_Google_SA_Token')?['statusCode'], 0))), if(not(empty(coalesce(outputs('Compose_Federated_Validation_Summary_GoogleSTSOnly_Fail'), json('null')))), concat('Google STS token exchange failed. Status: ', string(coalesce(outputs('Acquire_Google_STS_Token_Only')?['statusCode'], 0))), concat('Federated token exchange failed. Status: ', string(coalesce(outputs('Acquire_Federated_Token')?['statusCode'], 0))))))))" + } + } + } + } + }, + "else": { + "actions": {} + }, + "expression": { + "or": [ + { + "equals": ["@triggerBody()?['EnabledTests']", "All"] + }, + { + "equals": ["@triggerBody()?['EnabledTests']", "SCIMTests"] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Federated_Identity_Test" + ] + } + ] + }, + "type": "If" }, "SCIM_User_Pagination_Test": { "runAfter": {}, @@ -3591,24 +4120,20 @@ }, "Compose_Final_Results": { "runAfter": { - "SCIMTests_Scope": [ - "Succeeded", - "Failed", - "Skipped", - "TimedOut" - ] + "SCIMTests_Scope": ["Succeeded", "Failed", "Skipped", "TimedOut"] }, "type": "Compose", "inputs": { "SchemaDiscoverabilityTestOutputs": "@variables('SchemaDiscoverabilityTestOutputs')", "SCIMNullUpdateTestOutputs": "@variables('SCIMNullUpdateTestOutputs')", "ValidateCredentialsTestOutputs": "@variables('ValidateCredentialsTestOutputs')", + "FederatedIdentityTestOutputs": "@variables('FederatedIdentityTestOutputs')", "SCIMUserCreateTestOutputs": "@variables('SCIMUserCreateTestOutputs')", "SCIMGroupCreateTestOutputs": "@variables('SCIMGroupCreateTestOutputs')", "SCIMUserUpdateTestOutputs": "@variables('SCIMUserUpdateTestOutputs')", "SCIMGroupUpdateTestOutputs": "@variables('SCIMGroupUpdateTestOutputs')", "testSuiteName": "SCIMTests", - "status": "@if(or(or(or(equals(variables('SchemaDiscoverabilityTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMNullUpdateTestOutputs')['overallResult'], 'FAILED')), or(equals(variables('ValidateCredentialsTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMUserCreateTestOutputs')['overallResult'], 'FAILED'))), or(or(equals(variables('SCIMGroupCreateTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMUserUpdateTestOutputs')['overallResult'], 'FAILED')), equals(variables('SCIMGroupUpdateTestOutputs')['overallResult'], 'FAILED'))), 'Failed', 'Passed')", + "status": "@if(or(or(or(equals(variables('SchemaDiscoverabilityTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMNullUpdateTestOutputs')['overallResult'], 'FAILED')), or(or(equals(variables('ValidateCredentialsTestOutputs')['overallResult'], 'FAILED'), equals(variables('FederatedIdentityTestOutputs')['overallResult'], 'FAILED')), equals(variables('SCIMUserCreateTestOutputs')['overallResult'], 'FAILED'))), or(or(equals(variables('SCIMGroupCreateTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMUserUpdateTestOutputs')['overallResult'], 'FAILED')), equals(variables('SCIMGroupUpdateTestOutputs')['overallResult'], 'FAILED'))), 'Failed', 'Passed')", "workflowRunId": "@workflow().run.name", "SCIMUserPaginationTestOutputs": "@variables('SCIMUserPaginationTestOutputs')", "SCIMGroupPaginationTestOutputs": "@variables('SCIMGroupPaginationTestOutputs')" diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json index 89e5705e..f2962918 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json @@ -3983,7 +3983,24 @@ "RestoreUserTest_Phase1_Create_And_Assign": { "type": "Scope", "actions": { + "RestoreUserTest_SCIM_Pre_Check": { + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat(parameters('scimEndpoint'), '/Users?filter=userName%20eq%20%22', coalesce(triggerBody()?['initializationData']?['testUserNames']?['restoreUser'], ''), '%22')}", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, "RestoreUserTest_Create_Entra_User": { + "runAfter": { + "RestoreUserTest_SCIM_Pre_Check": [ + "Succeeded", + "Failed" + ] + }, "type": "Http", "inputs": { "method": "POST", @@ -3996,12 +4013,31 @@ "displayName": "@{triggerBody()?['initializationData']?['testUserNames']?['restoreUser']}", "mailNickname": "@{triggerBody()?['initializationData']?['testUserNames']?['restoreUserNickname']}", "userPrincipalName": "@{triggerBody()?['initializationData']?['testUserNames']?['restoreUser']}", + "givenName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName']), concat('Given', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName'])}", + "surname": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname']), concat('Sur', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname'])}", + "jobTitle": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle']), concat('Title', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle'])}", + "department": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department']), concat('Dept', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department'])}", + "companyName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName']), concat('Company', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName'])}", + "businessPhones": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['businessPhones'], json(concat('[\"+ 1-555-', substring(guid(),0,4), '\"]')))", + "mobilePhone": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone'])}", + "officeLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation']), concat('Office', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation'])}", + "preferredLanguage": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage']), 'en-US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage'])}", + "employeeId": "@{substring(guid(), 0, 8)}", + "employeeType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType']), 'Employee', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType'])}", + "streetAddress": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress']), concat('Street', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress'])}", + "city": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city']), concat('City', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city'])}", + "state": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state']), 'WA', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state'])}", + "country": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country'])}", + "postalCode": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode'])}", + "usageLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation'])}", "mail": "@{triggerBody()?['initializationData']?['testUserNames']?['restoreUserMail']}", - "givenName": "RestoreUser", - "surname": "Test", + "otherMails": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['otherMails'], json(concat('[\"', substring(guid(),0,8), '@example.com\"]')))", + "faxNumber": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber'])}", + "userType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType']), 'Member', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType'])}", + "employeeOrgData": "@if(or(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'])), json(concat('{\"division\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), concat('Div', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), '\",\"costCenter\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), '\"}')), json(concat('{\"division\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division'], '\",\"costCenter\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'], '\"}')))", "passwordProfile": { - "forceChangePasswordNextSignIn": true, - "password": "@{concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8))}" + "forceChangePasswordNextSignIn": "@{coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['forceChangePasswordNextSignIn'], true)}", + "password": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password']), concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password'])}" } }, "authentication": { @@ -4275,27 +4311,11 @@ "runAfter": {}, "type": "Scope", "actions": { - "RestoreUserTest_Get_AppRoleAssignment": { - "type": "Http", - "inputs": { - "method": "GET", - "uri": "@{concat('https://graph.microsoft.com/v1.0/users/', variables('restoreEntraUserId'), '/appRoleAssignments?$filter=resourceId%20eq%20', parameters('servicePrincipalId'))}", - "authentication": { - "type": "ManagedServiceIdentity", - "audience": "https://graph.microsoft.com/" - } - } - }, "RestoreUserTest_Unassign_AppRole": { - "runAfter": { - "RestoreUserTest_Get_AppRoleAssignment": [ - "Succeeded" - ] - }, "type": "Http", "inputs": { "method": "DELETE", - "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/appRoleAssignments/', first(body('RestoreUserTest_Get_AppRoleAssignment')?['value'])?['id'])}", + "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/appRoleAssignedTo/', body('RestoreUserTest_Assign_AppRole')?['id'])}", "authentication": { "type": "ManagedServiceIdentity", "audience": "https://graph.microsoft.com/" @@ -4754,9 +4774,10 @@ "provisioningErrorDetails": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('RestoreUserTest_Get_Restore_Log')?['value'], json('[]'))), 0), equals(toLower(first(body('RestoreUserTest_Get_Restore_Log')?['value'])?['provisioningStatusInfo']?['status']), 'failure')), first(body('RestoreUserTest_Get_Restore_Log')?['value'])?['provisioningStatusInfo']?['errorInformation'], null), variables('RestoreUserFailedActionResponse'))", "deprovisionAction": "@coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Unknown')", "restoreMode": "@if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), 'SoftDeleteRestore', 'HardDeleteReprovision')", - "scimCheckResult": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true)), 'success', 'RestoreUserTest: User not re-active on SCIM server after reassign'), if(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), 'success', 'RestoreUserTest: User not re-created on SCIM server after reassign (hard delete re-provision)')), concat('Failed Action: ', variables('RestoreUserFailedActionName')))", - "scimCheckErrorDetails": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true)), null, concat('SCIM verification failed: User not restored on SCIM server. totalResults: ', string(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 'N/A')), ', active: ', string(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], 'N/A')))), if(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), null, concat('SCIM verification failed: User not re-created after hard delete. totalResults: ', string(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 'N/A'))))), concat('Scope execution failed. Failed action: ', variables('RestoreUserFailedActionName')))", - "overallResult": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('RestoreUserTest_Get_Restore_Log')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('RestoreUserTest_Get_Restore_Log')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true)), 'PASSED', 'FAILED'), if(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), 'PASSED', 'FAILED')), 'FAILED'), 'FAILED')" + "scimCheckResult": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(and(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true)), variables('restoreIdentityLinkPreserved')), 'success', if(not(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true))), 'RestoreUserTest: User not re-active on SCIM server after reassign', concat('RestoreUserTest: Identity link NOT preserved after soft-delete restore (RFC 7643 Section 3.1). Original SCIM id: ', variables('restoreOriginalScimId'), ', Final SCIM id: ', variables('restoreFinalScimId')))), if(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), 'success', 'RestoreUserTest: User not re-created on SCIM server after reassign (hard delete re-provision)')), concat('Failed Action: ', variables('RestoreUserFailedActionName')))", + "scimCheckErrorDetails": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(and(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true)), variables('restoreIdentityLinkPreserved')), null, if(not(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true))), concat('SCIM verification failed: User not restored on SCIM server. totalResults: ', string(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 'N/A')), ', active: ', string(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], 'N/A'))), concat('SCIM identity link NOT preserved after soft-delete restore (RFC 7643 Section 3.1: id must be stable, non-reassignable). Original SCIM id: ', variables('restoreOriginalScimId'), ', Final SCIM id: ', variables('restoreFinalScimId')))), if(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), null, concat('SCIM verification failed: User not re-created after hard delete. totalResults: ', string(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 'N/A'))))), concat('Scope execution failed. Failed action: ', variables('RestoreUserFailedActionName')))", + "identityLinkCheck": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(variables('restoreIdentityLinkPreserved'), 'PASSED_REQUIRED', concat('FAILED_REQUIRED: RFC 7643 Section 3.1 violation - SCIM id changed from ', variables('restoreOriginalScimId'), ' to ', variables('restoreFinalScimId'))), if(variables('restoreIdentityLinkPreserved'), 'PASSED_INFORMATIONAL', 'NOT_PRESERVED_INFORMATIONAL')), 'SKIPPED')", + "overallResult": "@if(equals(variables('RestoreUserScopeExecutionStatus'), 'Succeeded'), if(and(greater(length(coalesce(body('RestoreUserTest_Get_Restore_Log')?['value'], json('[]'))), 0), equals(toLower(coalesce(first(body('RestoreUserTest_Get_Restore_Log')?['value'])?['provisioningStatusInfo']?['status'], '')), 'success')), if(equals(toLower(coalesce(first(body('RestoreUserTest_Get_Deprovision_Log')?['value'])?['provisioningAction'], 'Disable')), 'disable'), if(and(and(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), equals(coalesce(first(body('RestoreUserTest_SCIM_Get_Restore')?['Resources'])?['active'], false), true)), variables('restoreIdentityLinkPreserved')), 'PASSED', 'FAILED'), if(greaterOrEquals(coalesce(body('RestoreUserTest_SCIM_Get_Restore')?['totalResults'], 0), 1), 'PASSED', 'FAILED')), 'FAILED'), 'FAILED')" } }, "RestoreUserTest_Set_Phase3_Output_Variables": { @@ -4775,6 +4796,7 @@ "identityLinkPreserved": "@variables('restoreIdentityLinkPreserved')", "deprovisionAction": "@coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['deprovisionAction'], 'Unknown')", "restoreMode": "@coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['restoreMode'], 'Unknown')", + "identityLinkCheck": "@coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['identityLinkCheck'], 'SKIPPED')", "errorDetails": { "provisioningLogs": "@if(equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), null, coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningErrorDetails'], 'Analyze step failed - unable to retrieve provisioning error details'))", "scimCheck": "@if(equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success'), null, coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckErrorDetails'], 'Analyze step failed - unable to retrieve SCIM error details'))" @@ -4897,16 +4919,39 @@ "inputs": { "method": "POST", "uri": "https://graph.microsoft.com/v1.0/users", - "headers": { "Content-Type": "application/json" }, + "headers": { + "Content-Type": "application/json" + }, "body": { "accountEnabled": true, "displayName": "@{concat('PODTestUser_', substring(guid(), 0, 8))}", "mailNickname": "@{concat('poduser', substring(guid(), 0, 8))}", "userPrincipalName": "@{concat('poduser', substring(guid(), 0, 8), '@', last(split(coalesce(triggerBody()?['initializationData']?['testUserNames']?['createUser'], 'x@scimtest.onmicrosoft.com'), '@')))}", + "givenName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName']), concat('Given', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['givenName'])}", + "surname": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname']), concat('Sur', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['surname'])}", + "jobTitle": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle']), concat('Title', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['jobTitle'])}", + "department": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department']), concat('Dept', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['department'])}", + "companyName": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName']), concat('Company', substring(guid(),0,6)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['companyName'])}", + "businessPhones": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['businessPhones'], json(concat('[\"+ 1-555-', substring(guid(),0,4), '\"]')))", + "mobilePhone": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['mobilePhone'])}", + "officeLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation']), concat('Office', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['officeLocation'])}", + "preferredLanguage": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage']), 'en-US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['preferredLanguage'])}", + "employeeId": "@{substring(guid(), 0, 8)}", + "employeeType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType']), 'Employee', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeType'])}", + "streetAddress": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress']), concat('Street', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['streetAddress'])}", + "city": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city']), concat('City', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['city'])}", + "state": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state']), 'WA', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['state'])}", + "country": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['country'])}", + "postalCode": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['postalCode'])}", + "usageLocation": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation']), 'US', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['usageLocation'])}", "mail": "@{concat('poduser', substring(guid(), 0, 8), '@', last(split(coalesce(triggerBody()?['initializationData']?['testUserNames']?['createUser'], 'x@scimtest.onmicrosoft.com'), '@')))}", + "otherMails": "@coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['otherMails'], json(concat('[\"', substring(guid(),0,8), '@example.com\"]')))", + "faxNumber": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber']), concat('+1-555-', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['faxNumber'])}", + "userType": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType']), 'Member', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['userType'])}", + "employeeOrgData": "@if(or(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'])), json(concat('{\"division\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), concat('Div', substring(guid(),0,4)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division']), '\",\"costCenter\":\"', if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), substring(guid(),0,5), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter']), '\"}')), json(concat('{\"division\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['division'], '\",\"costCenter\":\"', parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['employeeOrgData']?['costCenter'], '\"}')))", "passwordProfile": { - "forceChangePasswordNextSignIn": false, - "password": "@{concat('P@ss', substring(guid(), 0, 12), '!')}" + "forceChangePasswordNextSignIn": "@{coalesce(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['forceChangePasswordNextSignIn'], true)}", + "password": "@{if(empty(parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password']), concat('Tmp!', substring(guid(),0,8), '@', substring(guid(),24,8)), parameters('defaultUserProperties')[triggerBody()?['initializationData']?['testUserNames']?['index']]['passwordProfile']['password'])}" } }, "authentication": { @@ -4915,18 +4960,50 @@ } } }, + "POD_SCIM_Pre_Check_User": { + "runAfter": { + "POD_Create_Graph_User": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "method": "GET", + "uri": "@{concat(parameters('scimEndpoint'), '/Users?filter=userName%20eq%20%22', body('POD_Create_Graph_User')?['userPrincipalName'], '%22')}", + "headers": { + "Authorization": "@{concat('Bearer ', parameters('scimBearerToken'))}", + "Accept": "@{parameters('scimContentType')}" + } + } + }, "POD_Delay_After_Create": { - "runAfter": { "POD_Create_Graph_User": ["Succeeded"] }, + "runAfter": { + "POD_SCIM_Pre_Check_User": [ + "Succeeded", + "Failed" + ] + }, "type": "Wait", - "inputs": { "interval": { "count": 30, "unit": "Second" } } + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } + } }, "POD_Assign_AppRole": { - "runAfter": { "POD_Delay_After_Create": ["Succeeded"] }, + "runAfter": { + "POD_Delay_After_Create": [ + "Succeeded" + ] + }, "type": "Http", "inputs": { "method": "POST", "uri": "@{concat('https://graph.microsoft.com/v1.0/users/', body('POD_Create_Graph_User')?['id'], '/appRoleAssignments')}", - "headers": { "Content-Type": "application/json" }, + "headers": { + "Content-Type": "application/json" + }, "body": { "principalId": "@{body('POD_Create_Graph_User')?['id']}", "resourceId": "@{parameters('servicePrincipalId')}", @@ -4939,17 +5016,32 @@ } }, "POD_Delay_After_AppRole": { - "runAfter": { "POD_Assign_AppRole": ["Succeeded"] }, + "runAfter": { + "POD_Assign_AppRole": [ + "Succeeded" + ] + }, "type": "Wait", - "inputs": { "interval": { "count": 60, "unit": "Second" } } + "inputs": { + "interval": { + "count": 60, + "unit": "Second" + } + } }, "POD_Get_Sync_Rules": { - "runAfter": { "POD_Delay_After_AppRole": ["Succeeded"] }, + "runAfter": { + "POD_Delay_After_AppRole": [ + "Succeeded" + ] + }, "type": "Http", "inputs": { "method": "GET", "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/synchronization/jobs/', triggerBody()?['initializationData']?['syncJobId'], '/schema')}", - "headers": { "Accept": "application/json" }, + "headers": { + "Accept": "application/json" + }, "authentication": { "type": "ManagedServiceIdentity", "audience": "https://graph.microsoft.com/" @@ -4957,12 +5049,18 @@ } }, "POD_Provision_On_Demand": { - "runAfter": { "POD_Get_Sync_Rules": ["Succeeded"] }, + "runAfter": { + "POD_Get_Sync_Rules": [ + "Succeeded" + ] + }, "type": "Http", "inputs": { "method": "POST", "uri": "@{concat('https://graph.microsoft.com/v1.0/servicePrincipals/', parameters('servicePrincipalId'), '/synchronization/jobs/', triggerBody()?['initializationData']?['syncJobId'], '/provisionOnDemand')}", - "headers": { "Content-Type": "application/json" }, + "headers": { + "Content-Type": "application/json" + }, "body": { "parameters": [ { @@ -4983,12 +5081,26 @@ } }, "POD_Delay_After_Provision": { - "runAfter": { "POD_Provision_On_Demand": ["Succeeded", "Failed"] }, + "runAfter": { + "POD_Provision_On_Demand": [ + "Succeeded", + "Failed" + ] + }, "type": "Wait", - "inputs": { "interval": { "count": 2, "unit": "Minute" } } + "inputs": { + "interval": { + "count": 2, + "unit": "Minute" + } + } }, "POD_SCIM_Get_User": { - "runAfter": { "POD_Delay_After_Provision": ["Succeeded"] }, + "runAfter": { + "POD_Delay_After_Provision": [ + "Succeeded" + ] + }, "type": "Http", "inputs": { "method": "GET", @@ -5000,17 +5112,27 @@ } }, "POD_Until_Provisioning_Logs": { - "runAfter": { "POD_SCIM_Get_User": ["Succeeded", "Failed"] }, + "runAfter": { + "POD_SCIM_Get_User": [ + "Succeeded", + "Failed" + ] + }, "type": "Until", "expression": "@greater(length(coalesce(body('POD_Verify_Provisioning_Logs')?['value'], json('[]'))), 0)", - "limit": { "count": 30, "timeout": "PT15M" }, + "limit": { + "count": 30, + "timeout": "PT15M" + }, "actions": { "POD_Verify_Provisioning_Logs": { "type": "Http", "inputs": { "method": "GET", "uri": "@{concat('https://graph.microsoft.com/v1.0/auditLogs/provisioning?$top=1&$orderby=activityDateTime%20desc&$filter=jobId%20eq%20%27', triggerBody()?['initializationData']?['syncJobId'], '%27%20and%20servicePrincipal/id%20eq%20%27', parameters('servicePrincipalId'), '%27%20and%20sourceIdentity/id%20eq%20%27', body('POD_Create_Graph_User')?['id'], '%27%20and%20provisioningAction%20eq%20%27create%27')}", - "headers": { "Accept": "application/json" }, + "headers": { + "Accept": "application/json" + }, "authentication": { "type": "ManagedServiceIdentity", "audience": "https://graph.microsoft.com/" @@ -5018,9 +5140,19 @@ } }, "POD_Delay_Log_Poll": { - "runAfter": { "POD_Verify_Provisioning_Logs": ["Succeeded", "Failed"] }, + "runAfter": { + "POD_Verify_Provisioning_Logs": [ + "Succeeded", + "Failed" + ] + }, "type": "Wait", - "inputs": { "interval": { "count": 30, "unit": "Second" } } + "inputs": { + "interval": { + "count": 30, + "unit": "Second" + } + } } } } @@ -5028,7 +5160,11 @@ }, "POD_User_Analyze_Results": { "runAfter": { - "POD_User_Test_Actions": ["Succeeded", "Failed", "TimedOut"] + "POD_User_Test_Actions": [ + "Succeeded", + "Failed", + "TimedOut" + ] }, "type": "Compose", "inputs": { @@ -5048,7 +5184,11 @@ } }, "Set_PODUserTestOutputs": { - "runAfter": { "POD_User_Analyze_Results": ["Succeeded"] }, + "runAfter": { + "POD_User_Analyze_Results": [ + "Succeeded" + ] + }, "type": "SetVariable", "inputs": { "name": "PODUserTestOutputs", @@ -5063,7 +5203,13 @@ } }, "POD_User_Cleanup_SCIM_Delete": { - "runAfter": { "Set_PODUserTestOutputs": ["Succeeded", "Failed", "Skipped"] }, + "runAfter": { + "Set_PODUserTestOutputs": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, "type": "Http", "inputs": { "method": "DELETE", @@ -5075,7 +5221,13 @@ } }, "POD_User_Cleanup_Graph_Delete": { - "runAfter": { "POD_User_Cleanup_SCIM_Delete": ["Succeeded", "Failed", "Skipped"] }, + "runAfter": { + "POD_User_Cleanup_SCIM_Delete": [ + "Succeeded", + "Failed", + "Skipped" + ] + }, "type": "Http", "inputs": { "method": "DELETE", @@ -5090,9 +5242,24 @@ "runAfter": {}, "expression": { "or": [ - { "equals": ["@triggerBody()?['EnabledTests']", "All"] }, - { "equals": ["@triggerBody()?['EnabledTests']", "UserTests"] }, - { "equals": ["@triggerBody()?['EnabledTests']", "POD_User_Test"] } + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "UserTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "POD_User_Test" + ] + } ] }, "type": "If" diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION index 819e07a2..e0ea36fe 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION @@ -1 +1 @@ -5.0 +6.0