Skip to content

Commit 3e3783b

Browse files
committed
Add ability to completely skip Delegated connection
1 parent 36bf181 commit 3e3783b

File tree

1 file changed

+64
-33
lines changed

1 file changed

+64
-33
lines changed

SOA/SOA-Prerequisites.psm1

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ function Remove-SOAAppSecret {
209209
param ()
210210

211211
# Get application again from Entra to be sure it includes any added secrets
212-
$App = (Invoke-MgGraphRequest -Method GET -Uri "$GraphHost/v1.0/applications?`$filter=web/redirectUris/any(p:p eq 'https://security.optimization.assessment.local')&`$count=true" -Headers @{'ConsistencyLevel' = 'eventual'} -OutputType PSObject).Value
212+
$App = (Invoke-MgGraphRequest -Method GET -Uri "$GraphHost/v1.0/applications?`$filter=web/redirectUris/any(p:p eq 'https://security.optimization.assessment.local')&`$count=true" -Headers @{'ConsistencyLevel' = 'eventual'} -OutputType PSObject -ErrorAction SilentlyContinue).Value
213213

214214
$secrets = $App.passwordCredentials
215215
foreach ($secret in $secrets) {
@@ -2254,6 +2254,11 @@ Function Install-SOAPrerequisites {
22542254
}
22552255

22562256
If($EntraAppCheck -eq $True) {
2257+
# Check if the InitialDomain was not provided, which is required when skipping delegated connection entirely
2258+
if (($null -ne $GraphClientId -and $PromptForApplicationSecret -eq $true) -and $null -eq $InitialDomain) {
2259+
Exit-Script
2260+
throw "The GraphClientId and PromptForApplicationSecret parameters were used, but InitialDomain was not specified. Re-run the script with the InitialDomain parameter"
2261+
}
22572262

22582263
# Get the cloud environment if not provided
22592264
if (-not $CloudEnvironment) {
@@ -2288,7 +2293,8 @@ Function Install-SOAPrerequisites {
22882293
}
22892294

22902295
$mgContext = (Get-MgContext).Scopes
2291-
if ($mgContext -notcontains 'Application.ReadWrite.All' -or ($mgContext -notcontains 'Organization.Read.All' -and $mgContext -notcontains 'Directory.Read.All') -or ($PromptForApplicationSecret)) {
2296+
# Skip delegated connection if providing GraphClientId and the App Secret manually, otherwise evaluate whether the correct scope was requested
2297+
if ($mgContext -notcontains 'Application.ReadWrite.All' -or ($mgContext -notcontains 'Organization.Read.All' -and $mgContext -notcontains 'Directory.Read.All') -and ($null -eq $GraphClientId -or $PromptForApplicationSecret -ne $true)) {
22922298
Write-Host "$(Get-Date) Connecting to Graph with delegated authentication..."
22932299
if ($null -ne (Get-MgContext)){Disconnect-MgGraph | Out-Null}
22942300
$connCount = 0
@@ -2327,9 +2333,6 @@ Function Install-SOAPrerequisites {
23272333
if (Get-MgContext) {
23282334
Write-Host "$(Get-Date) Checking Microsoft Entra enterprise application..."
23292335

2330-
# Get the tenant domain
2331-
$tenantdomain = Get-InitialDomain
2332-
23332336
$script:MDELicensed = Get-LicenseStatus -LicenseType MDE
23342337
#Write-Verbose "$(Get-Date) Get-LicenseStatus MDE License found: $($script:MDELicensed)"
23352338

@@ -2339,31 +2342,14 @@ Function Install-SOAPrerequisites {
23392342
$script:ATPP2Licensed = Get-LicenseStatus -LicenseType ATPP2
23402343
#Write-Verbose "$(Get-Date) Get-LicenseStatus ATPP2 License found: $($script:ATPP2Licensed)"
23412344

2342-
# Determine if Microsoft Entra application exists (and has public client redirect URI set), create if doesn't
2345+
# Determine if Microsoft Entra application exists (and has public client redirect URI set) and create (or recreate) if it doesn't.
23432346
$EntraApp = Get-SOAEntraApp -CloudEnvironment $CloudEnvironment
23442347
}
23452348

2346-
If($EntraApp) {
2347-
# Check if redirect URIs not set for existing app because DoNotRemediate is True
2348-
$webRUri = @("https://security.optimization.assessment.local","https://o365soa.github.io/soa/")
2349-
if (($EntraApp.PublicClient.RedirectUris -notcontains 'https://login.microsoftonline.com/common/oauth2/nativeclient' -or (Compare-Object -ReferenceObject $EntraApp.Web.RedirectUris -DifferenceObject $webRUri)) -and $DoNotRemediate) {
2350-
# Fail the Entra app check
2351-
$CheckResults += New-Object -Type PSObject -Property @{
2352-
Check="Entra Application"
2353-
Pass=$false
2354-
}
2355-
}
2356-
else {
2357-
# Pass the Entra app check
2358-
$CheckResults += New-Object -Type PSObject -Property @{
2359-
Check="Entra Application"
2360-
Pass=$true
2361-
}
2362-
}
2363-
$CheckResults += New-Object -Type PSObject -Property @{
2364-
Check="Entra Application Owner"
2365-
Pass=$script:appSelfOwner
2366-
}
2349+
# EntraApp will have a value if connecting using Delegated. If skipping Delegated entirely, then the initial domain still needs to be queried
2350+
If($EntraApp -or ($GraphClientId -and $PromptForApplicationSecret)) {
2351+
# Get the tenant domain
2352+
$tenantdomain = Get-InitialDomain
23672353

23682354
if ($PromptForApplicationSecret -eq $True) {
23692355
# Prompt for the client secret needed to connect to the application
@@ -2374,6 +2360,7 @@ Function Install-SOAPrerequisites {
23742360
while ($null -eq $SSCred -or $SSCred.Length -eq 0) {
23752361
# UserName is a required parameter for Get-Credential but it's value is not used elsewhere in the script
23762362
$SSCred = (Get-Credential -Message "Enter the app registration's client secret into the password field." -UserName "Microsoft Security Assessment").Password
2363+
Start-Sleep 1 # Add a delay to allow to aborting to console
23772364
}
23782365
} else {
23792366
# Reset secret
@@ -2384,20 +2371,52 @@ Function Install-SOAPrerequisites {
23842371
}
23852372

23862373
# Reconnect with Application permissions
2387-
Disconnect-MgGraph | Out-Null
2388-
$GraphCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($EntraApp.AppId), $SSCred
2374+
Try {Disconnect-MgGraph -ErrorAction Stop | Out-Null} Catch {}
2375+
if ($GraphClientId) {
2376+
$GraphCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $GraphClientId, $SSCred
2377+
} else {
2378+
$GraphCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($EntraApp.AppId), $SSCred
2379+
}
2380+
23892381
$ConnCount = 0
23902382
Write-Host "$(Get-Date) Connecting to Graph with application authentication..."
23912383
Do {
23922384
Try {
23932385
$ConnCount++
2394-
Write-Verbose "$(Get-Date) Graph connection attempt #$ConnCount"
2386+
if ($ConnCount -gt 5) {$ConnectionVerbose = @{Verbose = $true}} # Suppress Verbose output for the first 5 attempts, but display when connection is taking longer
2387+
Write-Verbose "$(Get-Date) Graph connection attempt #$ConnCount" @ConnectionVerbose
23952388
Connect-MgGraph -TenantId $tenantdomain -ClientSecretCredential $GraphCred -Environment $cloud -ContextScope "Process" -ErrorAction Stop | Out-Null
23962389
} Catch {
23972390
Start-Sleep 5
23982391
}
23992392
} Until ($null -ne (Get-MgContext))
24002393

2394+
# If the Delegated permissions were skipped, then the EntraApp has not yet been collected. Specifying the App ID allows the Application.ReadWrite.OwnedBy permission to be sufficient.
2395+
if ($GraphClientId -and $PromptForApplicationSecret) {
2396+
$EntraApp = Invoke-MgGraphRequest -Method GET -Uri "$GraphHost/v1.0/applications(appId=`'$GraphClientId`')"
2397+
}
2398+
2399+
# Check if redirect URIs not set for existing app because DoNotRemediate is True. Needs to be evaulated after switching to Application permissions for scenarios where Delegated is not used.
2400+
$webRUri = @("https://security.optimization.assessment.local","https://o365soa.github.io/soa/")
2401+
if (($EntraApp.PublicClient.RedirectUris -notcontains 'https://login.microsoftonline.com/common/oauth2/nativeclient' -or (Compare-Object -ReferenceObject $EntraApp.Web.RedirectUris -DifferenceObject $webRUri)) -and $DoNotRemediate) {
2402+
# Fail the Entra app check
2403+
$CheckResults += New-Object -Type PSObject -Property @{
2404+
Check="Entra Application"
2405+
Pass=$false
2406+
}
2407+
}
2408+
else {
2409+
# Pass the Entra app check
2410+
$CheckResults += New-Object -Type PSObject -Property @{
2411+
Check="Entra Application"
2412+
Pass=$true
2413+
}
2414+
}
2415+
$CheckResults += New-Object -Type PSObject -Property @{
2416+
Check="Entra Application Owner"
2417+
Pass=$script:appSelfOwner
2418+
}
2419+
24012420
$AppTest = Test-SOAApplication -App $EntraApp -Secret $clientsecret -TenantDomain $tenantdomain -CloudEnvironment $CloudEnvironment -WriteHost
24022421

24032422
# Entra App Permission - Perform remediation if specified
@@ -2454,9 +2473,20 @@ Function Install-SOAPrerequisites {
24542473
Connect-MgGraph -TenantId $tenantdomain -ClientSecretCredential $GraphCred -Environment $cloud -ErrorAction SilentlyContinue -ErrorVariable ConnectError | Out-Null
24552474

24562475
If($ConnectError){
2457-
$CheckResults += New-Object -Type PSObject -Property @{
2458-
Check="Graph SDK Connection"
2459-
Pass=$False
2476+
# Try again to confirm it wasn't a transient issue
2477+
Write-Verbose "$(Get-Date) Error when connecting using Graph SDK. Retrying in 15 seconds"
2478+
Start-Sleep 15
2479+
Connect-MgGraph -TenantId $tenantdomain -ClientSecretCredential $GraphCred -Environment $cloud -ErrorAction SilentlyContinue -ErrorVariable ConnectError2 | Out-Null
2480+
if ($ConnectError2) {
2481+
$CheckResults += New-Object -Type PSObject -Property @{
2482+
Check="Graph SDK Connection"
2483+
Pass=$False
2484+
}
2485+
} else {
2486+
$CheckResults += New-Object -Type PSObject -Property @{
2487+
Check="Graph SDK Connection"
2488+
Pass=$True
2489+
}
24602490
}
24612491
}
24622492
else {
@@ -2466,6 +2496,7 @@ Function Install-SOAPrerequisites {
24662496
}
24672497

24682498
if ($PromptForApplicationSecret -eq $false) {
2499+
Start-Sleep 10 # Avoid a race condition
24692500
# Remove client secret
24702501
Remove-SOAAppSecret
24712502
}

0 commit comments

Comments
 (0)