Skip to content

Commit

Permalink
Fix AAD 401 authentication errors against GCC high tenants (cisagov#1266
Browse files Browse the repository at this point in the history
)

* changed Invoke-MgGraphRequest to use the FQDN in the -Uri parameter and added the M365Environment command line parameter to support changing the endpoint FQDN based on the type of tenant

* removed trailing whitespace powershell linter errors

* test importing module before discovery

* remove import

* add removed code back

* test PSScriptRoot

* Use PSScriptRoot instead of get location

* Use module path

* Fix getting parent path

* Remove debug

* Update comments on the import module

* Update PowerShell/ScubaGear/Modules/Support/Support.psm1

Co-authored-by: Addam Schroll <108814318+schrolla@users.noreply.github.com>

* Update PowerShell/ScubaGear/Modules/Support/Support.psm1

Co-authored-by: Addam Schroll <108814318+schrolla@users.noreply.github.com>

* Remove whitespace per linter

---------

Co-authored-by: James Garriss <52328727+james-garriss@users.noreply.github.com>
Co-authored-by: Addam Schroll <108814318+schrolla@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 8, 2024
1 parent ba1cfbe commit 2e945ba
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 16 deletions.
2 changes: 1 addition & 1 deletion PowerShell/ScubaGear/Modules/Orchestrator.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ function Invoke-ProviderList {
$RetVal = ""
switch ($Product) {
"aad" {
$RetVal = Export-AADProvider | Select-Object -Last 1
$RetVal = Export-AADProvider -M365Environment $M365Environment | Select-Object -Last 1
}
"exo" {
$RetVal = Export-EXOProvider | Select-Object -Last 1
Expand Down
61 changes: 47 additions & 14 deletions PowerShell/ScubaGear/Modules/Providers/ExportAADProvider.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ function Invoke-GraphDirectly {
[string]
$commandlet,

[ValidateNotNullOrEmpty()]
[string]
$M365Environment,

[System.Collections.Hashtable]
$queryParams
)
Expand All @@ -25,6 +29,16 @@ function Invoke-GraphDirectly {
Write-Error "The commandlet $commandlet can't be used with the Invoke-GraphDirectly function yet."
}

if ($M365Environment -eq "gcchigh") {
$endpoint = "https://graph.microsoft.us" + $endpoint
}
elseif ($M365Environment -eq "dod") {
$endpoint = "https://dod-graph.microsoft.us" + $endpoint
}
else {
$endpoint = "https://graph.microsoft.com" + $endpoint
}

if ($queryParams) {
<#
If query params are passed in, we need to augment the endpoint URI to include the params. Paperwork below.
Expand All @@ -41,7 +55,7 @@ function Invoke-GraphDirectly {
}
Write-Debug "Graph Api direct: $endpoint"

$resp = Invoke-MgGraphRequest -Uri $endpoint -UserAgent 'ScubaGear'
$resp = Invoke-MgGraphRequest -Uri $endpoint
return $resp.Value
}

Expand All @@ -55,6 +69,13 @@ function Export-AADProvider {
Internal
#>

[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string]
$M365Environment
)

Import-Module $PSScriptRoot/ProviderHelpers/CommandTracker.psm1
$Tracker = Get-CommandTracker

Expand Down Expand Up @@ -103,10 +124,10 @@ function Export-AADProvider {
# Get-PrivilegedUser provides a list of privileged users and their role assignments. Used for 2.11 and 2.12
if ($RequiredServicePlan) {
# If the tenant has the premium license then we want to also include PIM Eligible role assignments - otherwise we don't to avoid an API error
$PrivilegedUsers = $Tracker.TryCommand("Get-PrivilegedUser", @{"TenantHasPremiumLicense"=$true})
$PrivilegedUsers = $Tracker.TryCommand("Get-PrivilegedUser", @{"TenantHasPremiumLicense"=$true; "M365Environment"=$M365Environment})
}
else{
$PrivilegedUsers = $Tracker.TryCommand("Get-PrivilegedUser", @{"TenantHasPremiumLicense"=$false})
$PrivilegedUsers = $Tracker.TryCommand("Get-PrivilegedUser", @{"TenantHasPremiumLicense"=$false; "M365Environment"=$M365Environment})
}
$PrivilegedUsers = $PrivilegedUsers | ConvertTo-Json
# The above Converto-Json call doesn't need to have the input wrapped in an
Expand All @@ -125,10 +146,10 @@ function Export-AADProvider {
# Get-PrivilegedRole provides data for 2.14 - 2.16, policies that evaluate conditions related to Azure AD PIM
if ($RequiredServicePlan){
# If the tenant has the premium license then we want to also include PIM Eligible role assignments - otherwise we don't to avoid an API error
$PrivilegedRoles = $Tracker.TryCommand("Get-PrivilegedRole", @{"TenantHasPremiumLicense"=$true})
$PrivilegedRoles = $Tracker.TryCommand("Get-PrivilegedRole", @{"TenantHasPremiumLicense"=$true; "M365Environment"=$M365Environment})
}
else {
$PrivilegedRoles = $Tracker.TryCommand("Get-PrivilegedRole", @{"TenantHasPremiumLicense"=$false})
$PrivilegedRoles = $Tracker.TryCommand("Get-PrivilegedRole", @{"TenantHasPremiumLicense"=$false; "M365Environment"=$M365Environment})
}
$PrivilegedRoles = ConvertTo-Json -Depth 10 @($PrivilegedRoles) # Depth required to get policy rule object details
}
Expand Down Expand Up @@ -246,7 +267,11 @@ function Get-PrivilegedUser {
param (
[ValidateNotNullOrEmpty()]
[switch]
$TenantHasPremiumLicense
$TenantHasPremiumLicense,

[ValidateNotNullOrEmpty()]
[string]
$M365Environment
)

# A hashtable of privileged users
Expand Down Expand Up @@ -305,7 +330,7 @@ function Get-PrivilegedUser {
$graphArgs = @{
"commandlet" = "Get-MgBetaIdentityGovernancePrivilegedAccessGroupEligibilityScheduleInstance"
"queryParams" = @{'$filter' = "groupId eq '$GroupId'"}
}
"M365Environment" = $M365Environment }
$PIMGroupMembers = Invoke-GraphDirectly @graphArgs
foreach ($GroupMember in $PIMGroupMembers) {
# If the user is not a member of the PIM group (i.e. they are an owner) then skip them
Expand All @@ -332,7 +357,7 @@ function Get-PrivilegedUser {
# Get a list of all the users and groups that have Eligible assignments
$graphArgs = @{
"commandlet" = "Get-MgBetaRoleManagementDirectoryRoleEligibilityScheduleInstance"
}
"M365Environment" = $M365Environment }
$AllPIMRoleAssignments = Invoke-GraphDirectly @graphArgs

# Add to the list of privileged users based on Eligible assignments
Expand Down Expand Up @@ -389,7 +414,7 @@ function Get-PrivilegedUser {
$graphArgs = @{
"commandlet" = "Get-MgBetaIdentityGovernancePrivilegedAccessGroupEligibilityScheduleInstance"
"queryParams" = @{'$filter' = "groupId eq '$UserObjectId'"}
}
"M365Environment" = $M365Environment}
$PIMGroupMembers = Invoke-GraphDirectly @graphArgs
foreach ($GroupMember in $PIMGroupMembers) {
# If the user is not a member of the PIM group (i.e. they are an owner) then skip them
Expand Down Expand Up @@ -453,14 +478,18 @@ function GetConfigurationsForPimGroups{

[ValidateNotNullOrEmpty()]
[array]
$AllRoleAssignments
$AllRoleAssignments,

[ValidateNotNullOrEmpty()]
[string]
$M365Environment
)

# Get a list of the groups that are enrolled in PIM - we want to ignore the others
$graphArgs = @{
"commandlet" = "Get-MgBetaPrivilegedAccessResource"
"queryParams" = @{'$PrivilegedAccessId' = "aadGroups"}
}
"M365Environment" = $M365Environment }
$PIMGroups = Invoke-GraphDirectly @graphArgs

foreach ($RoleAssignment in $AllRoleAssignments){
Expand Down Expand Up @@ -564,7 +593,11 @@ function Get-PrivilegedRole {
param (
[ValidateNotNullOrEmpty()]
[switch]
$TenantHasPremiumLicense
$TenantHasPremiumLicense,

[ValidateNotNullOrEmpty()]
[string]
$M365Environment
)

$PrivilegedRoles = [ScubaConfig]::ScubaDefault('DefaultPrivilegedRoles')
Expand All @@ -580,14 +613,14 @@ function Get-PrivilegedRole {
# Get ALL the roles and users actively assigned to them
$graphArgs = @{
"commandlet" = "Get-MgBetaRoleManagementDirectoryRoleAssignmentScheduleInstance"
}
"M365Environment" = $M365Environment }
$AllRoleAssignments = Invoke-GraphDirectly @graphArgs

# Each of the helper functions below add configuration settings (aka rules) to the role hashtable.
# Get the PIM configurations for the roles
GetConfigurationsForRoles -PrivilegedRoleHashtable $PrivilegedRoleHashtable -AllRoleAssignments $AllRoleAssignments
# Get the PIM configurations for the groups
GetConfigurationsForPimGroups -PrivilegedRoleHashtable $PrivilegedRoleHashtable -AllRoleAssignments $AllRoleAssignments
GetConfigurationsForPimGroups -PrivilegedRoleHashtable $PrivilegedRoleHashtable -AllRoleAssignments $AllRoleAssignments -M365Environment $M365Environment
}

# Return the hashtable
Expand Down
7 changes: 7 additions & 0 deletions PowerShell/ScubaGear/Modules/Support/Support.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ function Initialize-SCuBA {
$Stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

# Need to determine where module is so we can get required versions info
$ParentPath = Split-Path -parent $PSScriptRoot
$ModulePath = Split-Path -parent $ParentPath
# Removing the import below causes issues with testing, let it be.
# Import module magic may be helping by:
# * restricting the import so only that only function is exported
# * imported function takes precedence over imported modules w/ function
Import-Module $ModulePath -Function Initialize-Scuba
$ModuleParentDir = Split-Path -Path (Get-Module ScubaGear).Path -Parent
try {
($RequiredModulesPath = Join-Path -Path $ModuleParentDir -ChildPath 'RequiredVersions.ps1') *> $null
Expand Down
1 change: 0 additions & 1 deletion Testing/Functional/Products/Products.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ Import-Module $ConnectionModule
Import-Module Selenium

BeforeDiscovery{

if ($Variant) {
$TestPlanFileName = "TestPlans/$ProductName.$Variant.testplan.yaml"
}
Expand Down

0 comments on commit 2e945ba

Please sign in to comment.