Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2b5cc42
Initial plan
Copilot Dec 2, 2025
8b6b788
Add Test-MtCaAuthContextProtectedActionsExist test for Protected Acti…
Copilot Dec 2, 2025
532c4f5
Remove unused API calls for authentication strength policies
Copilot Dec 2, 2025
4ca5797
Update website/docs/tests/maester/MT.1090.md
SamErde Dec 2, 2025
550d061
Address review feedback: rename to MT.1106, filter enabled CA policie…
Copilot Dec 2, 2025
4d3cad8
Clarify description for MT.1106 test
SamErde Dec 21, 2025
f9ead48
Clarify test description for Authentication Contexts
SamErde Dec 21, 2025
6f5ed1f
Update synopsis and description for clarity
SamErde Dec 21, 2025
f7e79a2
Update website/docs/tests/maester/MT.1106.md
SamErde Feb 4, 2026
2221aa7
Update powershell/public/maester/entra/Test-MtCaAuthContextProtectedA…
SamErde Feb 4, 2026
e71a633
Update powershell/public/maester/entra/Test-MtCaAuthContextProtectedA…
SamErde Feb 4, 2026
6f70868
Update powershell/public/maester/entra/Test-MtCaAuthContextProtectedA…
SamErde Feb 4, 2026
bb22969
Update tests/Maester/Entra/Test-ConditionalAccessBaseline.Tests.ps1
SamErde Feb 4, 2026
d87aa9c
Update website/docs/tests/maester/MT.1106.md
SamErde Feb 4, 2026
d67059b
Use 'referenced' instead of 'enforced' for consistency in warning mes…
Copilot Feb 4, 2026
cd8cbf9
Add UTF-8 BOM to Test-MtCaAuthContextProtectedActionsExist.ps1
Copilot Feb 4, 2026
534a4b7
Add Test-MtCaAuthContextProtectedActionsExist to module manifest Func…
Copilot Feb 4, 2026
30abcb0
Add verbose logging to diagnose protected actions detection issue
Copilot Feb 4, 2026
ffd203d
Fix Protected Actions detection by using correct API endpoint (roleMa…
Copilot Feb 4, 2026
1049fa3
Add enhanced verbose logging to debug Protected Actions structure and…
Copilot Feb 4, 2026
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
3 changes: 2 additions & 1 deletion powershell/Maester.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ FunctionsToExport = 'Add-MtTestResultDetail',
'Resolve-SpfRecord', 'Send-MtMail', 'Send-MtTeamsMessage',
'Test-MtAppManagementPolicyEnabled', 'Test-MtAppRegistrationsWithSecrets', 'Test-MtSpExchangeAppAccessPolicy',
'Test-MtServicePrincipalsForAllUsers', 'Test-MtAuthenticationPolicyReferencedObjectsExist',
'Test-MtCaAllAppsExists', 'Test-MtCaApplicationEnforcedRestriction', 'Test-MtCaBlockLegacyExchangeActiveSyncAuthentication',
'Test-MtCaAllAppsExists', 'Test-MtCaApplicationEnforcedRestriction', 'Test-MtCaAuthContextProtectedActionsExist',
'Test-MtCaBlockLegacyExchangeActiveSyncAuthentication',
'Test-MtCaBlockLegacyOtherAuthentication', 'Test-MtCaBlockUnknownOrUnsupportedDevicePlatform',
'Test-MtCaDeviceCodeFlow', 'Test-MtCaDeviceComplianceAdminsExists', 'Test-MtCaDeviceComplianceExists',
'Test-MtCaEmergencyAccessExists', 'Test-MtCaEnforceNonPersistentBrowserSession', 'Test-MtCaEnforceSignInFrequency',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Protected Actions Authentication Contexts should have Conditional Access policies

Protected Actions allow organizations to require step-up authentication for sensitive operations by
assigning Authentication Contexts to those actions. However, if an Authentication Context is not
referenced in any Conditional Access policy, the protected action is not effectively protected.

This test verifies that all Authentication Contexts used by Protected Actions are properly referenced
in at least one Conditional Access policy.

## How to fix

If this test fails, you need to create or update Conditional Access policies to reference the Authentication Contexts used by your Protected Actions:

1. Navigate to the [Microsoft Entra admin center](https://entra.microsoft.com)
2. Go to **Protection** > **Conditional Access** > **Policies**
3. Create a new policy or edit an existing one
4. Under **Target resources** > **Authentication context**, select the Authentication Context(s) that need to be protected
5. Configure the appropriate grant controls (e.g., require authentication context, require compliant device)
6. Enable the policy and save

Alternatively, if the Protected Action no longer needs step-up authentication, you can remove the Authentication Context assignment from the Protected Action:

1. Navigate to the [Microsoft Entra admin center](https://entra.microsoft.com)
2. Go to **Identity** > **Roles & admins** > **Protected actions (Preview)**
3. Select the Protected Action
4. Remove or update the Authentication Context assignment

## Learn more

- [Protected actions in Microsoft Entra ID](https://learn.microsoft.com/entra/identity/role-based-access-control/protected-actions-overview)
- [Conditional Access: Target resources](https://learn.microsoft.com/entra/identity/conditional-access/concept-conditional-access-cloud-apps)
- [Authentication context in Conditional Access](https://learn.microsoft.com/entra/identity/conditional-access/concept-conditional-access-cloud-apps#authentication-context)

## Related links

- [Entra admin center - Conditional Access Policies](https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/Overview/fromNav/)
- [Entra admin center - Authentication contexts](https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/AuthenticationContext)
- [Entra admin center - Protected actions](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/ProtectedActions)

<!--- Results --->
%TestResult%
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<#
.Synopsis
Checks if all Protected Actions Authentication Contexts are referenced by a conditional access policy.

.Description
Protected Actions allow organizations to require step-up authentication for sensitive operations by
assigning Authentication Contexts to those actions. However, if an Authentication Context is not
referenced in any Conditional Access policy, the protected action is not effectively protected.

This test verifies that all Authentication Contexts used by Protected Actions are properly referenced
in at least one Conditional Access policy.

Learn more:
https://learn.microsoft.com/entra/identity/role-based-access-control/protected-actions-overview

.Example
Test-MtCaAuthContextProtectedActionsExist

.LINK
https://maester.dev/docs/commands/Test-MtCaAuthContextProtectedActionsExist
#>
function Test-MtCaAuthContextProtectedActionsExist {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'Exists is not a plural.')]
[CmdletBinding()]
[OutputType([bool])]
param ()

$EntraIDPlan = Get-MtLicenseInformation -Product EntraID
$pim = $EntraIDPlan -eq "P2" -or $EntraIDPlan -eq "Governance"
if (-not $pim) {
Add-MtTestResultDetail -SkippedBecause NotLicensedEntraIDP2
return $null
}

try {
# Get all authentication contexts
$authContexts = Invoke-MtGraphRequest -RelativeUri 'identity/conditionalAccess/authenticationContextClassReferences' -ApiVersion beta

if (-not $authContexts -or ($authContexts | Measure-Object).Count -eq 0) {
$testResult = 'No Authentication Contexts are configured in the tenant.'
Add-MtTestResultDetail -Result $testResult
return $true
}

# Get Protected Actions with authentication contexts
# Protected Actions are accessed through roleManagement/directory/resourceNamespaces
try {
$resourceNamespaces = Invoke-MtGraphRequest -RelativeUri 'roleManagement/directory/resourceNamespaces' -ApiVersion beta -ErrorAction SilentlyContinue
Write-Verbose "Found $($resourceNamespaces.Count) resource namespaces"
} catch {
Write-Verbose "Could not retrieve resource namespaces: $_"
$resourceNamespaces = @()
}

# Collect all auth context IDs that are used in protected actions
$authContextsInProtectedActions = [System.Collections.Generic.HashSet[string]]::new()

# Check each resource namespace for protected actions with authentication contexts
if ($resourceNamespaces) {
$namespaceCount = 0
foreach ($namespace in $resourceNamespaces) {
$namespaceCount++
try {
# Get resource actions for this namespace
$resourceActions = Invoke-MtGraphRequest -RelativeUri "roleManagement/directory/resourceNamespaces/$($namespace.id)/resourceActions" -ApiVersion beta -ErrorAction SilentlyContinue
if ($resourceActions) {
Write-Verbose "Namespace $namespaceCount/$($resourceNamespaces.Count) ($($namespace.id)): Found $($resourceActions.Count) resource actions"
foreach ($action in $resourceActions) {
# Debug: Log all properties of the first few actions to understand structure
if ($namespaceCount -le 3 -and $resourceActions.IndexOf($action) -le 2) {
Write-Verbose "Sample action properties: $($action | ConvertTo-Json -Depth 2 -Compress)"
}

# Check if this action has an authentication context requirement
# Try multiple possible property names
$authContextId = $null
if ($action.authenticationContextId) {
$authContextId = $action.authenticationContextId
} elseif ($action.authenticationContext) {
$authContextId = $action.authenticationContext
} elseif ($action.authContext) {
$authContextId = $action.authContext
} elseif ($action.PSObject.Properties['authenticationContextId']) {
$authContextId = $action.PSObject.Properties['authenticationContextId'].Value
}

if ($authContextId) {
Write-Verbose "Found protected action '$($action.name)' with authentication context: $authContextId"
[void]$authContextsInProtectedActions.Add($authContextId)
}
}
}
} catch {
Write-Verbose "Could not retrieve resource actions for namespace $($namespace.id): $_"
}
}
}

Write-Verbose "Total authentication contexts found in protected actions: $($authContextsInProtectedActions.Count)"

# Get all enabled conditional access policies
$caPolicies = Get-MtConditionalAccessPolicy | Where-Object { $_.state -eq 'enabled' }

# Collect all auth context IDs referenced in CA policies
$authContextsInCAPolicies = [System.Collections.Generic.HashSet[string]]::new()
foreach ($policy in $caPolicies) {
if ($policy.conditions.applications.includeAuthenticationContextClassReferences) {
foreach ($context in $policy.conditions.applications.includeAuthenticationContextClassReferences) {
[void]$authContextsInCAPolicies.Add($context)
}
}
}

# Check for auth contexts that are used in protected actions but not in CA policies
$unprotectedContexts = [System.Collections.Generic.List[object]]::new()

foreach ($id in $authContextsInProtectedActions) {
if (-not $authContextsInCAPolicies.Contains($id)) {
$ctx = $authContexts | Where-Object { $_.id -eq $id } | Select-Object -First 1
$unprotectedContexts.Add(@{
Id = $id
DisplayName = if ($ctx) { $ctx.displayName } else { '(Deleted or not found)' }
Description = if ($ctx) { $ctx.description } else { '' }
IsAvailable = if ($ctx) { $ctx.isAvailable } else { $null }
})
}
}

# Determine result
$result = $unprotectedContexts.Count -eq 0

if ($result) {
if ($authContextsInProtectedActions.Count -eq 0) {
$testResult = 'No Authentication Contexts are configured for Protected Actions in this tenant.'
} else {
$testResult = "All Authentication Contexts used in Protected Actions are properly referenced in Conditional Access policies.`n`n"
$testResult += "**Protected Action Auth Contexts with CA policies:**`n`n"
foreach ($authContext in $authContexts) {
if ($authContextsInProtectedActions.Contains($authContext.id)) {
$testResult += "- $($authContext.displayName) ($($authContext.id))`n"
}
}
}
} else {
$testResult = "The following Authentication Contexts are used in Protected Actions but are not referenced by any Conditional Access policy:`n`n"
$testResult += "| Authentication Context | ID | Description |`n"
$testResult += "| --- | --- | --- |`n"
foreach ($context in $unprotectedContexts) {
$displayName = if ($context.DisplayName) { $context.DisplayName } else { "(No name)" }
$description = if ($context.Description) { $context.Description } else { "(No description)" }
$testResult += "| $displayName | $($context.Id) | $description |`n"
}
$testResult += "`n`n⚠️ **Warning**: These Protected Actions are not effectively protected because their Authentication Contexts are not referenced by any Conditional Access policy.`n"
}

Add-MtTestResultDetail -Result $testResult
return $result

} catch {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
return $null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@
Test-MtCaApprovedClientApp | Should -Be $true -Because "no policy use the deprecated Approved Client App grant."
}

It "MT.1106: All Protected Actions Authentication Contexts should be referenced by a Conditional Access policy. See https://maester.dev/docs/tests/MT.1106" -Tag "MT.1106" {
Test-MtCaAuthContextProtectedActionsExist | Should -Be $true -Because "all Authentication Contexts used in Protected Actions should be referenced by Conditional Access policies."
}

Context "Maester/Entra" -Tag "Entra", "License" {
It "MT.1022: All users utilizing a P1 license should be licensed. See https://maester.dev/docs/tests/MT.1022" -Tag "MT.1022" {
$LicenseReport = Test-MtCaLicenseUtilization -License "P1"
Expand Down
50 changes: 50 additions & 0 deletions website/docs/tests/maester/MT.1106.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: MT.1106 - All Protected Actions Authentication Contexts should be referenced by a Conditional Access policy
description: This test checks if all Authentication Contexts used in Protected Actions are properly referenced in at least one active Conditional Access policy.
slug: /tests/MT.1106
sidebar_class_name: hidden
---

# Protected Actions Authentication Contexts should have Conditional Access policies

## Description

Protected Actions allow organizations to require step-up authentication for sensitive operations by assigning Authentication Contexts to those actions. However, if an Authentication Context is not referenced in any Conditional Access policy, the protected action is not effectively protected.

This test verifies that all Authentication Contexts used by Protected Actions are properly referenced in at least one active Conditional Access policy.

When a Protected Action has an Authentication Context assigned but that context is not referenced by any Conditional Access policy:

- Users will not be prompted for additional authentication when performing the protected action
- The security benefit of the Protected Action is lost
- The tenant may be exposed to unauthorized sensitive operations

## How to fix

If this test fails, you need to create or update Conditional Access policies to reference the Authentication Contexts used by your Protected Actions:

1. Navigate to the [Microsoft Entra admin center](https://entra.microsoft.com)
2. Go to **Protection** > **Conditional Access** > **Policies**
3. Create a new policy or edit an existing one
4. Under **Target resources** > **Authentication context**, select the Authentication Context(s) that need to be protected
5. Configure the appropriate grant controls (e.g., require multifactor authentication, require device to be marked as compliant, require approved client app)
6. Enable the policy and save

Alternatively, if the Protected Action no longer needs step-up authentication, you can remove the Authentication Context assignment from the Protected Action:

1. Navigate to the [Microsoft Entra admin center](https://entra.microsoft.com)
2. Go to **Identity** > **Roles & admins** > **Protected actions (Preview)**
3. Select the Protected Action
4. Remove or update the Authentication Context assignment

## Learn more

- [Protected actions in Microsoft Entra ID](https://learn.microsoft.com/entra/identity/role-based-access-control/protected-actions-overview)
- [Conditional Access: Target resources](https://learn.microsoft.com/entra/identity/conditional-access/concept-conditional-access-cloud-apps)
- [Authentication context in Conditional Access](https://learn.microsoft.com/entra/identity/conditional-access/concept-conditional-access-cloud-apps#authentication-context)

## Related links

- [Entra admin center - Conditional Access Policies](https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/Overview/fromNav/)
- [Entra admin center - Authentication contexts](https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/AuthenticationContext)
- [Entra admin center - Protected actions](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/ProtectedActions)