Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ $roleId = az ad sp show --id $graphSpId --query "appRoles[?value=='$roleValue'].
$body = @{ principalId=$miObjId; resourceId=$graphSpId; appRoleId=$roleId } | ConvertTo-Json
az rest --method POST --uri "https://graph.microsoft.com/v1.0/servicePrincipals/$miObjId/appRoleAssignments" --headers "Content-Type=application/json" --body "$body"

$roleValue="Synchronization.Read.All"
$roleValue="Synchronization.ReadWrite.All"
$roleId = az ad sp show --id $graphSpId --query "appRoles[?value=='$roleValue'].id" -o tsv
$body = @{ principalId=$miObjId; resourceId=$graphSpId; appRoleId=$roleId } | ConvertTo-Json
az rest --method POST --uri "https://graph.microsoft.com/v1.0/servicePrincipals/$miObjId/appRoleAssignments" --headers "Content-Type=application/json" --body "$body"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
"SCIM_Group_Update_Test",
"SCIM_User_Delete_Test",
"SCIM_Group_Delete_Test",
"SCIM_Pagination_Test",
"SCIM_User_Pagination_Test",
"SCIM_Group_Pagination_Test",
"POD_User_Test",
"POD_Group_Test",
"Restore_User_Test"
],
"type": "String",
"value": "SCIMTests"
"value": "All"
},
"IsSoftDeleted": {
"metadata": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,8 @@
"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'))",
"scimUserPaginationTestEnabled": "@or(equals(parameters('EnabledTests'), 'All'), equals(parameters('EnabledTests'), 'SCIMTests'), equals(parameters('EnabledTests'), 'SCIM_User_Pagination_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')))"
},
"testResults": {
"createUserTestResult": "@coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'], 'SKIPPED')",
Expand Down Expand Up @@ -663,6 +664,14 @@
"runLink": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))",
"message": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', 'Click the runLink and search for the action Compose_Final_Results for more info.')"
},
{
"testName": "SCIM_Group_Pagination_Test",
"testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - IsGroupSupported is false', 'SKIPPED'))",
"provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['errorDetails'], '')",
"recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['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')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))",
"message": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', 'Click the runLink and search for the action Compose_Final_Results for more info.')"
},
{
"testName": "POD_User_Test",
"testResult": "@coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['result'], 'SKIPPED')",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Purpose

The SCIM Validation Logic App runs **22 automated tests** against an ISV's SCIM 2.0 endpoint to verify it is ready for publication in the Microsoft Entra app gallery. Tests cover the full provisioning lifecycle — user and group CRUD, attribute mappings, soft delete, provision-on-demand, direct SCIM compliance, and credential validation.
The SCIM Validation Logic App runs **23 automated tests** against an ISV's SCIM 2.0 endpoint to verify it is ready for publication in the Microsoft Entra app gallery. Tests cover the full provisioning lifecycle — user and group CRUD, attribute mappings, soft delete, provision-on-demand, direct SCIM compliance, and credential validation.

The Logic App is deployed as a Standard Azure Logic App with 5 workflows that execute in parallel, completing a full validation run in 30–60 minutes.

Expand All @@ -15,8 +15,8 @@ Orchestrator_Workflow (entry point)
├── Initialization_Workflow — reads sync schema, builds dynamic test bodies
├── UserTests_Workflow — 7 tests (parallel with Group/SCIM)
├── GroupTests_Workflow — 7 tests (parallel with User/SCIM)
└── SCIMTests_Workflow — 8 tests (parallel with User/Group)
└── Final_TestResults — aggregates 22 results, determines pass/fail
└── SCIMTests_Workflow — 9 tests (parallel with User/Group)
└── Final_TestResults — aggregates 23 results, determines pass/fail
```

**Dynamic capability detection:** The Initialization workflow reads the provisioning schema and automatically determines which tests apply based on the ISV's attribute mappings:
Expand Down Expand Up @@ -59,7 +59,7 @@ Tests that don't apply are reported as **SKIPPED** (not failures).

> **Note:** All 7 group tests are **skipped** if the ISV's schema does not have an enabled Group object mapping.

### SCIM Compliance Tests (SCIMTests_Workflow) — 8 tests
### SCIM Compliance Tests (SCIMTests_Workflow) — 9 tests

| # | Test Name | What It Validates |
|---|-----------|-------------------|
Expand All @@ -70,7 +70,8 @@ Tests that don't apply are reported as **SKIPPED** (not failures).
| 19 | **SCIM_Group_Create_Test** | Directly calls `POST /Groups` with a SCIM group body. **Skipped** if groups are not supported. |
| 20 | **SCIM_Group_Update_Test** | Directly calls `PATCH /Groups/{id}` with attribute updates. **Skipped** if groups are not supported. |
| 21 | **SCIM_User_Pagination_Test** | Ensures ≥11 users exist on the endpoint (creates throwaway users from `initializationData.scimUserBody` if needed), then paginates `/Users?startIndex=N&count=5` across multiple pages. Verifies `startIndex`, `totalResults`, and page traversal. Cleans up created users afterward. |
| 22 | **Validate_Credentials_Test** | Tests the OAuth 2.0 Client Credentials flow — acquires a token from the ISV's token endpoint using client ID/secret, then validates the SCIM connection. **Skipped** when `scimTokenEndpoint` is empty (static bearer token setup). |
| 22 | **SCIM_Group_Pagination_Test** | Ensures ≥11 groups exist on the endpoint (creates throwaway groups from `initializationData.scimGroupBody` if needed), then paginates `/Groups?startIndex=N&count=5` across multiple pages. Verifies `startIndex`, `totalResults`, and page traversal. Cleans up created groups afterward. **Skipped** if groups are not supported. |
| 23 | **Validate_Credentials_Test** | Tests the OAuth 2.0 Client Credentials flow — acquires a token from the ISV's token endpoint using client ID/secret, then validates the SCIM connection. **Skipped** when `scimTokenEndpoint` is empty (static bearer token setup). |

---

Expand All @@ -80,17 +81,17 @@ Tests that don't apply are reported as **SKIPPED** (not failures).
|----------|-------|-----------|
| **User Lifecycle** | 7 | Full CRUD + Manager + Restore + POD via Entra provisioning engine |
| **Group Lifecycle** | 7 | Full CRUD + Membership + POD + Restore via Entra provisioning engine |
| **SCIM Direct Compliance** | 7 | Direct HTTP calls to SCIM endpoint — schema, CRUD, null update, pagination |
| **SCIM Direct Compliance** | 8 | Direct HTTP calls to SCIM endpoint — schema, CRUD, null update, user & group pagination |
| **Credential Validation** | 1 | OAuth client credentials flow |
| **Total Scored** | **22** |
| **Total Scored** | **23** |

---

## What "Passing" Means

| Scenario | Acceptable? |
|----------|-------------|
| All 22 tests: `success` | **Ready for gallery submission** |
| All 23 tests: `success` | **Ready for gallery submission** |
| Group tests: `SKIPPED` (no group mapping) | Acceptable if ISV only supports /Users |
| Disable_User_Test: `SKIPPED` (no `active` mapping) | Acceptable — ISV should document |
| Manager test: `SKIPPED` (no `manager` mapping) | Acceptable — ISV should document |
Expand Down Expand Up @@ -124,4 +125,4 @@ Both methods produce the same output: a `validation-result-<RunId>.json` file to

---

*Document version: June 2026 — Covers Logic App validation template v4 with 22 tests across 5 workflows. Includes User Pagination, Restore tests, Schema_Discoverability_Test v2 with flatten loops, scimTargetUserValues, and Provision on Demand.*
*Document version: June 2026 — Covers Logic App validation template v4 with 23 tests across 5 workflows. Includes User & Group Pagination, Restore tests, Schema_Discoverability_Test v2 with flatten loops, scimTargetUserValues, and Provision on Demand.*
Loading
Loading