Skip to content

Commit abd2a77

Browse files
authored
Merge pull request #641 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 342c02a + df632ea commit abd2a77

File tree

9 files changed

+234
-7
lines changed

9 files changed

+234
-7
lines changed

CIPPTimers.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,14 @@
231231
"Priority": 22,
232232
"RunOnProcessor": true,
233233
"IsSystem": true
234+
},
235+
{
236+
"Id": "1f2e3d4c-5b6a-7c8d-9e0f-1a2b3c4d5e6f",
237+
"Command": "Start-TestsOrchestrator",
238+
"Description": "Timer to run security and compliance tests against cached data",
239+
"Cron": "0 0 4 * * *",
240+
"Priority": 23,
241+
"RunOnProcessor": true,
242+
"IsSystem": true
234243
}
235244
]

Modules/CIPPCore/Public/Add-CIPPDbItem.ps1

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,8 @@ function Add-CIPPDbItem {
6262
Type = $Type
6363
}
6464
}
65+
Add-CIPPAzDataTableEntity @Table -Entity $Entities -Force | Out-Null
6566

66-
$BatchSize = 1000
67-
for ($i = 0; $i -lt $Entities.Count; $i += $BatchSize) {
68-
$Batch = $Entities[$i..([Math]::Min($i + $BatchSize - 1, $Entities.Count - 1))]
69-
foreach ($Entity in $Batch) {
70-
Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force | Out-Null
71-
}
72-
}
7367
}
7468

7569
Write-LogMessage -API 'CIPPDbItem' -tenant $TenantFilter -message "Added $($Data.Count) items of type $Type$(if ($Count) { ' (count mode)' })" -sev Info

Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheData.ps1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ function Push-CIPPDBCacheData {
5858
Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "AdminConsentRequestPolicy collection failed: $($_.Exception.Message)" -sev Error
5959
}
6060

61+
try { Set-CIPPDBCacheAuthorizationPolicy -TenantFilter $TenantFilter } catch {
62+
Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "AuthorizationPolicy collection failed: $($_.Exception.Message)" -sev Error
63+
}
64+
6165
try { Set-CIPPDBCacheDeviceSettings -TenantFilter $TenantFilter } catch {
6266
Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "DeviceSettings collection failed: $($_.Exception.Message)" -sev Error
6367
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
function Push-CIPPTest {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
#>
6+
param(
7+
$Item
8+
)
9+
10+
$TenantFilter = $Item.TenantFilter
11+
$TestId = $Item.TestId
12+
13+
Write-Information "Running test $TestId for tenant $TenantFilter"
14+
15+
try {
16+
$FunctionName = "Invoke-CippTest$TestId"
17+
18+
if (-not (Get-Command $FunctionName -ErrorAction SilentlyContinue)) {
19+
Write-LogMessage -API 'Tests' -tenant $TenantFilter -message "Test function not found: $FunctionName" -sev Error
20+
return
21+
}
22+
23+
Write-Information "Executing $FunctionName for $TenantFilter"
24+
& $FunctionName -Tenant $TenantFilter
25+
26+
} catch {
27+
$ErrorMessage = Get-CippException -Exception $_
28+
Write-LogMessage -API 'Tests' -tenant $TenantFilter -message "Failed to run test $TestId $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
29+
}
30+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
function Invoke-CIPPTestsRun {
2+
<#
3+
.FUNCTIONALITY
4+
Entrypoint
5+
.ROLE
6+
Tenant.Tests.Read
7+
#>
8+
[CmdletBinding()]
9+
param(
10+
[Parameter(Mandatory = $false)]
11+
[string]$TenantFilter = 'allTenants'
12+
)
13+
14+
Write-Information "Starting tests run for tenant: $TenantFilter"
15+
16+
try {
17+
$AllTests = Get-Command -Name 'Invoke-CippTest*' -Module CIPPCore | Select-Object -ExpandProperty Name | ForEach-Object {
18+
$_ -replace '^Invoke-CippTest', ''
19+
}
20+
21+
if ($AllTests.Count -eq 0) {
22+
Write-LogMessage -API 'Tests' -message 'No test functions found.' -sev Error
23+
return
24+
}
25+
26+
Write-Information "Found $($AllTests.Count) test functions to run"
27+
$AllTenantsList = if ($TenantFilter -eq 'allTenants') {
28+
$DbCounts = Get-CIPPDbItem -CountsOnly
29+
$TenantsWithData = $DbCounts | Where-Object { $_.Count -gt 0 } | Select-Object -ExpandProperty PartitionKey -Unique
30+
Write-Information "Found $($TenantsWithData.Count) tenants with data in database"
31+
$TenantsWithData
32+
} else {
33+
$DbCounts = Get-CIPPDbItem -TenantFilter $TenantFilter -CountsOnly
34+
if (($DbCounts | Measure-Object -Property Count -Sum).Sum -gt 0) {
35+
@($TenantFilter)
36+
} else {
37+
Write-LogMessage -API 'Tests' -tenant $TenantFilter -message 'Tenant has no data in database. Skipping tests.' -sev Info
38+
@()
39+
}
40+
}
41+
42+
if ($AllTenantsList.Count -eq 0) {
43+
Write-LogMessage -API 'Tests' -message 'No tenants with data found. Exiting.' -sev Info
44+
return
45+
}
46+
47+
# Build batch: all tests for all tenants
48+
$Batch = foreach ($Tenant in $AllTenantsList) {
49+
foreach ($Test in $AllTests) {
50+
@{
51+
FunctionName = 'CIPPTest'
52+
TenantFilter = $Tenant
53+
TestId = $Test
54+
}
55+
}
56+
}
57+
58+
Write-Information "Built batch of $($Batch.Count) test activities ($($AllTests.Count) tests × $($AllTenantsList.Count) tenants)"
59+
60+
$InputObject = [PSCustomObject]@{
61+
OrchestratorName = 'TestsRun'
62+
Batch = @($Batch)
63+
SkipLog = $true
64+
}
65+
66+
$InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 5 -Compress)
67+
Write-Information "Started tests orchestration with ID = '$InstanceId'"
68+
69+
return @{
70+
InstanceId = $InstanceId
71+
Message = "Tests orchestration started: $($AllTests.Count) tests for $($AllTenantsList.Count) tenants"
72+
}
73+
} catch {
74+
$ErrorMessage = Get-CippException -Exception $_
75+
Write-LogMessage -API 'Tests' -message "Failed to start tests orchestration: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
76+
throw
77+
}
78+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function Start-TestsOrchestrator {
2+
<#
3+
.SYNOPSIS
4+
Start the Tests Orchestrator
5+
6+
.FUNCTIONALITY
7+
Entrypoint
8+
#>
9+
[CmdletBinding(SupportsShouldProcess = $true)]
10+
param()
11+
12+
if ($PSCmdlet.ShouldProcess('Start-TestsOrchestrator', 'Starting Tests Orchestrator')) {
13+
Write-LogMessage -API 'Tests' -message 'Starting Tests Schedule' -sev Info
14+
Invoke-CIPPTestsRun -TenantFilter 'allTenants'
15+
}
16+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
function Set-CIPPDBCacheAuthorizationPolicy {
2+
<#
3+
.SYNOPSIS
4+
Caches authorization policy for a tenant
5+
6+
.PARAMETER TenantFilter
7+
The tenant to cache authorization policy for
8+
#>
9+
[CmdletBinding()]
10+
param(
11+
[Parameter(Mandatory = $true)]
12+
[string]$TenantFilter
13+
)
14+
15+
try {
16+
Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching authorization policy' -sev Info
17+
$AuthPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy' -tenantid $TenantFilter
18+
Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthorizationPolicy' -Data @($AuthPolicy)
19+
$AuthPolicy = $null
20+
21+
Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached authorization policy successfully' -sev Info
22+
23+
} catch {
24+
Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Failed to cache authorization policy: $($_.Exception.Message)" -sev Error
25+
}
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function Invoke-CippTestZTNA21776 {
2+
param($Tenant)
3+
4+
try {
5+
$AuthPolicy = New-CIPPDbRequest -TenantFilter $Tenant -Type 'AuthorizationPolicy'
6+
if (-not $AuthPolicy) {
7+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21776' -TestType 'Identity' -Status 'Investigate' -ResultMarkdown 'Authorization policy not found in database' -Risk 'High' -Name 'User consent settings are restricted' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Application Management'
8+
return
9+
}
10+
11+
$Matched = $AuthPolicy | Where-Object { $_.defaultUserRolePermissions.permissionGrantPoliciesAssigned -match '^ManagePermissionGrantsForSelf' }
12+
$NoMatch = $Matched.Count -eq 0
13+
$LowImpact = $Matched.defaultUserRolePermissions.permissionGrantPoliciesAssigned -contains 'managePermissionGrantsForSelf.microsoft-user-default-low'
14+
15+
if ($NoMatch -or $LowImpact) {
16+
$Status = 'Passed'
17+
$Result = if ($NoMatch) { 'User consent is disabled' } else { 'User consent restricted to verified publishers and low-impact permissions' }
18+
} else {
19+
$Status = 'Failed'
20+
$Result = 'Users can consent to any application'
21+
}
22+
23+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21776' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'High' -Name 'User consent settings are restricted' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Application Management'
24+
} catch {
25+
$ErrorMessage = Get-CippException -Exception $_
26+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
27+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21776' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'High' -Name 'User consent settings are restricted' -UserImpact 'High' -ImplementationEffort 'Medium' -Category 'Application Management'
28+
}
29+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
function Invoke-CippTestZTNA21808 {
2+
param($Tenant)
3+
4+
try {
5+
$CAPolicies = New-CIPPDbRequest -TenantFilter $Tenant -Type 'ConditionalAccessPolicies'
6+
if (-not $CAPolicies) {
7+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21808' -TestType 'Identity' -Status 'Investigate' -ResultMarkdown 'Conditional Access policies not found in database' -Risk 'High' -Name 'Restrict device code flow' -UserImpact 'Medium' -ImplementationEffort 'Low' -Category 'Access Control'
8+
return
9+
}
10+
11+
$Enabled = $CAPolicies | Where-Object { $_.state -eq 'enabled' }
12+
$DeviceCodePolicies = $Enabled | Where-Object {
13+
if ($_.conditions.authenticationFlows.transferMethods) {
14+
$Methods = $_.conditions.authenticationFlows.transferMethods -split ','
15+
$Methods -contains 'deviceCodeFlow'
16+
} else {
17+
$false
18+
}
19+
}
20+
21+
$BlockPolicies = $DeviceCodePolicies | Where-Object { $_.grantControls.builtInControls -contains 'block' }
22+
23+
if ($BlockPolicies.Count -gt 0) {
24+
$Status = 'Passed'
25+
$Result = "Device code flow is properly restricted with $($BlockPolicies.Count) blocking policy/policies"
26+
} elseif ($DeviceCodePolicies.Count -eq 0) {
27+
$Status = 'Failed'
28+
$Result = 'No Conditional Access policies found targeting device code flow'
29+
#Add table with existing policies?
30+
} else {
31+
$Status = 'Failed'
32+
$Result = 'Device code flow policies exist but none are configured to block'
33+
}
34+
35+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21808' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'High' -Name 'Restrict device code flow' -UserImpact 'Medium' -ImplementationEffort 'Low' -Category 'Access Control'
36+
} catch {
37+
$ErrorMessage = Get-CippException -Exception $_
38+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
39+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21808' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'High' -Name 'Restrict device code flow' -UserImpact 'Medium' -ImplementationEffort 'Low' -Category 'Access Control'
40+
}
41+
}

0 commit comments

Comments
 (0)