diff --git a/source/Private/Invoke-TestFunction.ps1 b/source/Private/Invoke-TestFunction.ps1 index b708652..1aae8bb 100644 --- a/source/Private/Invoke-TestFunction.ps1 +++ b/source/Private/Invoke-TestFunction.ps1 @@ -6,7 +6,9 @@ function Invoke-TestFunction { [Parameter(Mandatory = $false)] [string]$DomainName, [Parameter(Mandatory = $false)] - [string[]]$ApprovedCloudStorageProviders + [string[]]$ApprovedCloudStorageProviders, + [Parameter(Mandatory = $false)] + [string[]]$ApprovedFederatedDomains ) $functionName = $FunctionFile.BaseName @@ -20,6 +22,9 @@ function Invoke-TestFunction { if ('ApprovedCloudStorageProviders' -in $functionCmd.Parameters.Keys) { $paramList.ApprovedCloudStorageProviders = $ApprovedCloudStorageProviders } + if ('ApprovedFederatedDomains' -in $functionCmd.Parameters.Keys) { + $paramList.ApprovedFederatedDomains = $ApprovedFederatedDomains + } # Use splatting to pass parameters Write-Verbose "Running $functionName..." try { diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index f9f0235..e45799e 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -23,6 +23,8 @@ Specifies specific recommendations to exclude from the audit. Accepts an array of recommendation numbers. .PARAMETER ApprovedCloudStorageProviders Specifies the approved cloud storage providers for the audit. Accepts an array of cloud storage provider names. + .PARAMETER ApprovedFederatedDomains + Specifies the approved federated domains for the audit test 8.2.1. Accepts an array of allowed domain names. .PARAMETER DoNotConnect If specified, the cmdlet will not establish a connection to Microsoft 365 services. .PARAMETER DoNotDisconnect @@ -131,7 +133,7 @@ function Invoke-M365SecurityAudit { [ValidatePattern('^https://[a-zA-Z0-9-]+-admin\.sharepoint\.com$')] [string]$TenantAdminUrl, - [Parameter(Mandatory = $false, HelpMessage = "Specify this to test only the default domain for password expiration policy when '1.3.1' is included in the tests to be run. The domain name of your organization, e.g., 'example.com'.")] + [Parameter(Mandatory = $false, HelpMessage = "Specify this to test only the default domain for password expiration and DKIM Config for tests '1.3.1' and 2.1.9. The domain name of your organization, e.g., 'example.com'.")] [ValidatePattern('^[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$')] [string]$DomainName, @@ -187,6 +189,9 @@ function Invoke-M365SecurityAudit { )] [string[]]$ApprovedCloudStorageProviders = @(), + [Parameter(Mandatory = $false, HelpMessage = "Specifies the approved federated domains for the audit test 8.2.1. Accepts an array of allowed domain names.")] + [string[]]$ApprovedFederatedDomains, + [Parameter(Mandatory = $false, HelpMessage = "Specifies that the cmdlet will not establish a connection to Microsoft 365 services.")] [switch]$DoNotConnect, @@ -300,7 +305,7 @@ function Invoke-M365SecurityAudit { Write-Progress -Activity "Executing Tests" -Status "Executing $($currentTestIndex) of $($totalTests): $($testFunction.Name)" -PercentComplete (($currentTestIndex / $totalTests) * 100) $functionName = $testFunction.BaseName if ($PSCmdlet.ShouldProcess($functionName, "Execute test")) { - $auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $DomainName -ApprovedCloudStorageProviders $ApprovedCloudStorageProviders + $auditResult = Invoke-TestFunction -FunctionFile $testFunction -DomainName $DomainName -ApprovedCloudStorageProviders $ApprovedCloudStorageProviders -ApprovedFederatedDomains $ApprovedFederatedDomains # Add the result to the collection [void]$allAuditResults.Add($auditResult) } diff --git a/source/tests/Test-TeamsExternalAccess.ps1 b/source/tests/Test-TeamsExternalAccess.ps1 index 9c7d320..22e58f4 100644 --- a/source/tests/Test-TeamsExternalAccess.ps1 +++ b/source/tests/Test-TeamsExternalAccess.ps1 @@ -2,8 +2,8 @@ function Test-TeamsExternalAccess { [CmdletBinding()] [OutputType([CISAuditResult])] param ( - # Aligned - # Parameters can be defined here if needed + [Parameter(Mandatory = $false, HelpMessage = "Specifies the approved federated domains for the audit. Accepts an array of allowed domain names.")] + [string[]]$ApprovedFederatedDomains ) begin { @@ -23,33 +23,66 @@ function Test-TeamsExternalAccess { # - Condition A: The `AllowTeamsConsumer` setting is `False`. # - Condition B: The `AllowPublicUsers` setting is `False`. # - Condition C: The `AllowFederatedUsers` setting is `False` or, if `True`, the `AllowedDomains` contains only authorized domain names. - # - # Validate test for a fail: - # - Confirm that the failure conditions in the automated test are consistent with the manual audit results. - # - Specific conditions to check: - # - Condition A: The `AllowTeamsConsumer` setting is not `False`. - # - Condition B: The `AllowPublicUsers` setting is not `False`. - # - Condition C: The `AllowFederatedUsers` setting is `True` and the `AllowedDomains` contains unauthorized domain names or is not configured correctly. # Connect to Teams PowerShell using Connect-MicrosoftTeams - + # $externalAccessConfig Mock Object + <# + $externalAccessConfig = [PSCustomObject]@{ + Identity = 'Global' + AllowedDomains = 'AllowAllKnownDomains' + BlockedDomains = @() + AllowFederatedUsers = $true + AllowPublicUsers = $true + AllowTeamsConsumer = $true + AllowTeamsConsumerInbound = $true + } + $ApprovedFederatedDomains = @('msn.com', 'google.com') + $externalAccessConfig = [PSCustomObject]@{ + Identity = 'Global' + AllowedDomains = @('msn.com', 'google.com') + BlockedDomains = @() + AllowFederatedUsers = $true + AllowPublicUsers = $false + AllowTeamsConsumer = $false + AllowTeamsConsumerInbound = $true + } + #> $externalAccessConfig = Get-CISMSTeamsOutput -Rec $recnum + # Testing + #$externalAccessConfig.AllowedDomains = @("msn.com", "google.com") + #$externalAccessConfig.AllowTeamsConsumer = $false + #$externalAccessConfig.AllowPublicUsers = $false + #$externalAccessConfig.AllowFederatedUsers = $true + # The above is for testing and will be replaced with the actual values from the Teams PowerShell output in production. + $allowedDomainsLimited = $false - if ($externalAccessConfig.AllowFederatedUsers -and $externalAccessConfig.AllowedDomains -and $externalAccessConfig.AllowedDomains.AllowedDomain.Count -gt 0) { - $allowedDomainsLimited = $true + $allowedDomainsMatch = $false + $invalidDomains = @() + + if ($externalAccessConfig.AllowFederatedUsers) { + if ($externalAccessConfig.AllowedDomains -ne 'AllowAllKnownDomains' -and $externalAccessConfig.AllowedDomains.Count -gt 0) { + $allowedDomainsLimited = $true + if ($ApprovedFederatedDomains) { + $invalidDomains = $externalAccessConfig.AllowedDomains | Where-Object { $_ -notin $ApprovedFederatedDomains } + if ($invalidDomains.Count -eq 0) { + $invalidDomains = "None" + } + $allowedDomainsMatch = $invalidDomains.Count -eq 0 + } + } } # Check if the configurations are as recommended - $isCompliant = -not $externalAccessConfig.AllowTeamsConsumer -and -not $externalAccessConfig.AllowPublicUsers -and (-not $externalAccessConfig.AllowFederatedUsers -or $allowedDomainsLimited) + $isCompliant = -not $externalAccessConfig.AllowTeamsConsumer -and -not $externalAccessConfig.AllowPublicUsers -and (-not $externalAccessConfig.AllowFederatedUsers -or ($allowedDomainsLimited -and $allowedDomainsMatch)) # Create an instance of CISAuditResult and populate it $params = @{ Rec = $recnum Result = $isCompliant Status = if ($isCompliant) { "Pass" } else { "Fail" } - Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited" - FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant." } else { "N/A" } + Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited; AllowedDomains match: $allowedDomainsMatch; Invalid Domains: $($invalidDomains -join ', ')" + FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant. Invalid domains found: $($invalidDomains -join ', ')" } else { "N/A" } } $auditResult = Initialize-CISAuditResult @params }