-
Notifications
You must be signed in to change notification settings - Fork 120
35002 - Add test for Cross-Tenant Access Policy (XTAP) RMS settings #720
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,337 @@ | ||||||
| Describe "Test-Assessment-35002" { | ||||||
| BeforeAll { | ||||||
| $here = $PSScriptRoot | ||||||
| $srcRoot = Join-Path $here "../../src/powershell" | ||||||
| <# | ||||||
| # Import required module functions | ||||||
| @( | ||||||
| "private/core/Add-ZtTestResultDetail.ps1" | ||||||
| "public/Invoke-ZtGraphRequest.ps1" | ||||||
| "private/core/Write-ZtProgress.ps1" | ||||||
| "private/core/Get-ZtTestStatus.ps1" | ||||||
| "private/core/Get-SafeMarkdown.ps1" | ||||||
| ) | ForEach-Object { . (Join-Path $srcRoot $_) } | ||||||
| #> | ||||||
| # Mock external module dependencies | ||||||
| if (-not (Get-Command Write-PSFMessage -ErrorAction SilentlyContinue)) { | ||||||
| function Write-PSFMessage {} | ||||||
| } | ||||||
|
|
||||||
| # Load the class | ||||||
| $classPath = Join-Path $srcRoot "classes/ZtTest.ps1" | ||||||
| if (-not ("ZtTest" -as [type])) { | ||||||
| . $classPath | ||||||
| } | ||||||
|
|
||||||
| # Load the SUT | ||||||
| $sut = Join-Path $srcRoot "tests/Test-Assessment.35002.ps1" | ||||||
| . $sut | ||||||
|
|
||||||
| # Setup output file | ||||||
| $script:outputFile = Join-Path $here "../TestResults/Report-Test-Assessment.35002.md" | ||||||
| $outputDir = Split-Path $script:outputFile | ||||||
| if (-not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir | Out-Null } | ||||||
| "# Test Results for 35002`n" | Set-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| BeforeEach { | ||||||
| Mock Write-PSFMessage {} | ||||||
| Mock Write-ZtProgress {} | ||||||
| Mock Get-SafeMarkdown { param($Text) return $Text } | ||||||
| $script:defaultPolicyResponse = $null | ||||||
| $script:partnersResponse = @() | ||||||
| } | ||||||
|
|
||||||
| Context "When Default Policy allows RMS" { | ||||||
| It "Should pass when Inbound and Outbound allow RMS explicitly" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" }) | ||||||
| } | ||||||
| } | ||||||
| b2bCollaborationOutbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| $script:partnersResponse = @() | ||||||
|
|
||||||
| Mock Invoke-ZtGraphRequest { | ||||||
| if ($RelativeUri -match "default") { return $script:defaultPolicyResponse } | ||||||
| if ($RelativeUri -match "partners") { return $script:partnersResponse } | ||||||
| } | ||||||
|
|
||||||
| Mock Add-ZtTestResultDetail { | ||||||
| param($TestId, $Title, $Status, $Result) | ||||||
| "## Scenario: Default Allowed Explicitly`n`n$Result`n" | Add-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| Test-Assessment-35002 | ||||||
|
|
||||||
| Should -Invoke Add-ZtTestResultDetail -ParameterFilter { | ||||||
| $Status -eq $true -and $Result -match "RMS application is allowed" | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| It "Should pass when Inbound and Outbound allow All Apps" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "AllApplications" }) | ||||||
| } | ||||||
| } | ||||||
| b2bCollaborationOutbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "AllApplications" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| $script:partnersResponse = @() | ||||||
|
|
||||||
| Mock Invoke-ZtGraphRequest { | ||||||
| if ($RelativeUri -match "default") { return $script:defaultPolicyResponse } | ||||||
| if ($RelativeUri -match "partners") { return $script:partnersResponse } | ||||||
| } | ||||||
|
|
||||||
| Mock Add-ZtTestResultDetail { | ||||||
| param($TestId, $Title, $Status, $Result) | ||||||
| "## Scenario: Default Allowed All Apps`n`n$Result`n" | Add-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| Test-Assessment-35002 | ||||||
|
|
||||||
| Should -Invoke Add-ZtTestResultDetail -ParameterFilter { | ||||||
| $Status -eq $true | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| It "Should pass when Inbound and Outbound Block specific apps but NOT RMS (Implicit Allow)" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
|
||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "blocked" | ||||||
| targets = @([PSCustomObject]@{ target = "some-other-app-id" }) | ||||||
| } | ||||||
| } | ||||||
| b2bCollaborationOutbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "blocked" | ||||||
| targets = @([PSCustomObject]@{ target = "some-other-app-id" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| $script:partnersResponse = @() | ||||||
|
|
||||||
| Mock Invoke-ZtGraphRequest { | ||||||
| if ($RelativeUri -match "default") { return $script:defaultPolicyResponse } | ||||||
| if ($RelativeUri -match "partners") { return $script:partnersResponse } | ||||||
| } | ||||||
|
|
||||||
| Mock Add-ZtTestResultDetail { | ||||||
| param($TestId, $Title, $Status, $Result) | ||||||
| "## Scenario: Default Implicit Allow`n`n$Result`n" | Add-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| Test-Assessment-35002 | ||||||
|
|
||||||
| Should -Invoke Add-ZtTestResultDetail -ParameterFilter { | ||||||
| $Status -eq $true | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| Context "When Default Policy blocks RMS" { | ||||||
| It "Should fail when Inbound explicitly blocks RMS" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "blocked" | ||||||
| targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" }) | ||||||
| } | ||||||
| } | ||||||
| b2bCollaborationOutbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "AllApplications" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| $script:partnersResponse = @() | ||||||
|
|
||||||
| Mock Invoke-ZtGraphRequest { | ||||||
| if ($RelativeUri -match "default") { return $script:defaultPolicyResponse } | ||||||
| if ($RelativeUri -match "partners") { return $script:partnersResponse } | ||||||
| } | ||||||
|
|
||||||
| $script:capturedResult = $null | ||||||
| Mock Add-ZtTestResultDetail { | ||||||
| param($TestId, $Title, $Status, $Result) | ||||||
| $script:capturedResult = $Result | ||||||
| "## Scenario: Default Inbound Blocked Explicitly`n`n$Result`n" | Add-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| Test-Assessment-35002 | ||||||
|
|
||||||
| Should -Invoke Add-ZtTestResultDetail -ParameterFilter { | ||||||
| $Status -eq $false | ||||||
| } | ||||||
| $script:capturedResult | Should -Match "Blocked \(Explicit\)" | ||||||
| } | ||||||
|
|
||||||
| It "Should fail when Inbound allows specific apps but NOT RMS (Implicit Block)" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "some-other-app-id" }) | ||||||
| } | ||||||
| } | ||||||
| b2bCollaborationOutbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "AllApplications" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| $script:partnersResponse = @() | ||||||
|
|
||||||
| Mock Invoke-ZtGraphRequest { | ||||||
| if ($RelativeUri -match "default") { return $script:defaultPolicyResponse } | ||||||
| if ($RelativeUri -match "partners") { return $script:partnersResponse } | ||||||
| } | ||||||
|
|
||||||
| $script:capturedResult = $null | ||||||
| Mock Add-ZtTestResultDetail { | ||||||
| param($TestId, $Title, $Status, $Result) | ||||||
| $script:capturedResult = $Result | ||||||
| "## Scenario: Default Inbound Blocked Implicitly`n`n$Result`n" | Add-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| Test-Assessment-35002 | ||||||
|
|
||||||
| Should -Invoke Add-ZtTestResultDetail -ParameterFilter { | ||||||
| $Status -eq $false | ||||||
| } | ||||||
| $script:capturedResult | Should -Match "Blocked \(Implicit\)" | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| Context "When Partner Policies exist" { | ||||||
| It "Should fail if a Partner Policy blocks RMS" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "AllApplications" }) | ||||||
| } | ||||||
| } | ||||||
| b2bCollaborationOutbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "allowed" | ||||||
| targets = @([PSCustomObject]@{ target = "AllApplications" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| $script:partnersResponse = @( | ||||||
| [PSCustomObject]@{ | ||||||
| tenantId = "partner-tenant-id" | ||||||
| b2bCollaborationInbound = [PSCustomObject]@{ | ||||||
| applications = [PSCustomObject]@{ | ||||||
| accessType = "blocked" | ||||||
| targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" }) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| ) | ||||||
|
|
||||||
| Mock Invoke-ZtGraphRequest { | ||||||
| if ($RelativeUri -match "default") { return $script:defaultPolicyResponse } | ||||||
| if ($RelativeUri -match "partners") { return $script:partnersResponse } | ||||||
| } | ||||||
|
|
||||||
| $script:capturedResult = $null | ||||||
| Mock Add-ZtTestResultDetail { | ||||||
| param($TestId, $Title, $Status, $Result) | ||||||
| $script:capturedResult = $Result | ||||||
| "## Scenario: Partner Blocked`n`n$Result`n" | Add-Content $script:outputFile | ||||||
| } | ||||||
|
|
||||||
| Test-Assessment-35002 | ||||||
|
|
||||||
| Should -Invoke Add-ZtTestResultDetail -ParameterFilter { | ||||||
| $Status -eq $false | ||||||
| } | ||||||
| $script:capturedResult | Should -Match "Partner \(partner-tenant-id\)" | ||||||
| $script:capturedResult | Should -Match "Blocked \(Explicit\)" | ||||||
| } | ||||||
|
|
||||||
| It "Should ignore inherited partner settings" { | ||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | ||||||
|
||||||
| $script:defaultPolicyResponse = [PSCustomObject]@{ | |
| $script:defaultPolicyResponse = [PSCustomObject]@{ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| Cross-tenant access policies (XTAP) in Microsoft Entra ID control how users in your organization collaborate with external organizations. When users share encrypted content across organizational boundaries or receive encrypted documents from external partners, the Microsoft Rights Management Service (RMS) must authenticate users from both organizations to enforce encryption permissions. If cross-tenant access settings block or restrict the RMS application (App ID: `00000012-0000-0000-c000-000000000000`), users will encounter "Access is blocked by your organization" or "Access is blocked by the organization" error messages when attempting to open encrypted emails or documents from external organizations. This prevents legitimate cross-organizational collaboration on protected content. Organizations should configure both inbound and outbound cross-tenant access settings to explicitly allow the RMS application, ensuring that external users can open encrypted content shared by your organization (inbound) and your users can open encrypted content received from external partners (outbound). Without proper XTAP configuration, encrypted content sharing fails even when users have appropriate permissions assigned through sensitivity label encryption settings. | ||
|
|
||
| **Remediation action** | ||
|
|
||
| To configure cross-tenant access settings to allow RMS: | ||
| 1. Navigate to [Microsoft Entra admin center > External Identities > Cross-tenant access settings](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/CompanyRelationshipsMenuBlade/~/CrossTenantAccessSettings) | ||
| 2. Select "Default settings" or a specific organizational setting | ||
| 3. Under "Inbound access", select "B2B collaboration" | ||
| 4. Select "Applications" tab | ||
| 5. Choose "Allow access" and add "Microsoft Rights Management Services" (App ID: `00000012-0000-0000-c000-000000000000`) | ||
| 6. Repeat for "Outbound access" settings | ||
| 7. Save changes | ||
|
|
||
| - [Cross-tenant access settings and encrypted content](https://learn.microsoft.com/purview/encryption-azure-ad-configuration#cross-tenant-access-settings-and-encrypted-content) | ||
| - [Configure cross-tenant access settings for B2B collaboration](https://learn.microsoft.com/entra/external-id/cross-tenant-access-settings-b2b-collaboration) | ||
|
|
||
| <!--- Results ---> | ||
| %TestResult% |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation: the variable assignment uses extra leading spaces (6 spaces instead of the standard 12 spaces for this level). This should be aligned with the indentation used in other test cases in this file.