Skip to content

Commit bc7ed87

Browse files
authored
Merge pull request #139 from o365soa/jondev-6257-provideappid
Add ability to completely skip Delegated connection
2 parents f586afd + 3e3783b commit bc7ed87

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) {
@@ -2256,6 +2256,11 @@ Function Install-SOAPrerequisites {
22562256
}
22572257

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

22602265
# Get the cloud environment if not provided
22612266
if (-not $CloudEnvironment) {
@@ -2290,7 +2295,8 @@ Function Install-SOAPrerequisites {
22902295
}
22912296

22922297
$mgContext = (Get-MgContext).Scopes
2293-
if ($mgContext -notcontains 'Application.ReadWrite.All' -or ($mgContext -notcontains 'Organization.Read.All' -and $mgContext -notcontains 'Directory.Read.All') -or ($PromptForApplicationSecret)) {
2298+
# Skip delegated connection if providing GraphClientId and the App Secret manually, otherwise evaluate whether the correct scope was requested
2299+
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)) {
22942300
Write-Host "$(Get-Date) Connecting to Graph with delegated authentication..."
22952301
if ($null -ne (Get-MgContext)){Disconnect-MgGraph | Out-Null}
22962302
$connCount = 0
@@ -2329,9 +2335,6 @@ Function Install-SOAPrerequisites {
23292335
if (Get-MgContext) {
23302336
Write-Host "$(Get-Date) Checking Microsoft Entra enterprise application..."
23312337

2332-
# Get the tenant domain
2333-
$tenantdomain = Get-InitialDomain
2334-
23352338
$script:MDELicensed = Get-LicenseStatus -LicenseType MDE
23362339
#Write-Verbose "$(Get-Date) Get-LicenseStatus MDE License found: $($script:MDELicensed)"
23372340

@@ -2341,31 +2344,14 @@ Function Install-SOAPrerequisites {
23412344
$script:ATPP2Licensed = Get-LicenseStatus -LicenseType ATPP2
23422345
#Write-Verbose "$(Get-Date) Get-LicenseStatus ATPP2 License found: $($script:ATPP2Licensed)"
23432346

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

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

23702356
if ($PromptForApplicationSecret -eq $True) {
23712357
# Prompt for the client secret needed to connect to the application
@@ -2376,6 +2362,7 @@ Function Install-SOAPrerequisites {
23762362
while ($null -eq $SSCred -or $SSCred.Length -eq 0) {
23772363
# UserName is a required parameter for Get-Credential but it's value is not used elsewhere in the script
23782364
$SSCred = (Get-Credential -Message "Enter the app registration's client secret into the password field." -UserName "Microsoft Security Assessment").Password
2365+
Start-Sleep 1 # Add a delay to allow to aborting to console
23792366
}
23802367
} else {
23812368
# Reset secret
@@ -2386,20 +2373,52 @@ Function Install-SOAPrerequisites {
23862373
}
23872374

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

2396+
# 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.
2397+
if ($GraphClientId -and $PromptForApplicationSecret) {
2398+
$EntraApp = Invoke-MgGraphRequest -Method GET -Uri "$GraphHost/v1.0/applications(appId=`'$GraphClientId`')"
2399+
}
2400+
2401+
# 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.
2402+
$webRUri = @("https://security.optimization.assessment.local","https://o365soa.github.io/soa/")
2403+
if (($EntraApp.PublicClient.RedirectUris -notcontains 'https://login.microsoftonline.com/common/oauth2/nativeclient' -or (Compare-Object -ReferenceObject $EntraApp.Web.RedirectUris -DifferenceObject $webRUri)) -and $DoNotRemediate) {
2404+
# Fail the Entra app check
2405+
$CheckResults += New-Object -Type PSObject -Property @{
2406+
Check="Entra Application"
2407+
Pass=$false
2408+
}
2409+
}
2410+
else {
2411+
# Pass the Entra app check
2412+
$CheckResults += New-Object -Type PSObject -Property @{
2413+
Check="Entra Application"
2414+
Pass=$true
2415+
}
2416+
}
2417+
$CheckResults += New-Object -Type PSObject -Property @{
2418+
Check="Entra Application Owner"
2419+
Pass=$script:appSelfOwner
2420+
}
2421+
24032422
$AppTest = Test-SOAApplication -App $EntraApp -Secret $clientsecret -TenantDomain $tenantdomain -CloudEnvironment $CloudEnvironment -WriteHost
24042423

24052424
# Entra App Permission - Perform remediation if specified
@@ -2456,9 +2475,20 @@ Function Install-SOAPrerequisites {
24562475
Connect-MgGraph -TenantId $tenantdomain -ClientSecretCredential $GraphCred -Environment $cloud -ErrorAction SilentlyContinue -ErrorVariable ConnectError | Out-Null
24572476

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

24702500
if ($PromptForApplicationSecret -eq $false) {
2501+
Start-Sleep 10 # Avoid a race condition
24712502
# Remove client secret
24722503
Remove-SOAAppSecret
24732504
}

0 commit comments

Comments
 (0)