Add browser auth for headless runs

This commit is contained in:
2026-04-08 16:09:30 +02:00
parent c803a00df7
commit 239e3ec16e
12 changed files with 222 additions and 19 deletions

View File

@@ -563,6 +563,14 @@ function Add-MSALPrereq
}
$RequiredAssemblies.Add('System.Security.dll')
$RequiredAssemblies.Add('mscorlib.dll')
if($PSVersionTable.PSVersion.Major -ge 7)
{
$netStandardAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq "netstandard" } | Select-Object -First 1
if($netStandardAssembly -and $netStandardAssembly.Location)
{
$RequiredAssemblies.Add($netStandardAssembly.Location)
}
}
if($PSVersionTable.PSVersion.Major -ge 7) {
$RequiredAssemblies.Add('System.Security.Cryptography.ProtectedData.dll')
}
@@ -574,6 +582,7 @@ function Add-MSALPrereq
}
catch
{
$global:SkipTokenCacheHelperEx = $true
Write-LogError "Failed to compile TokenCacheHelperEx. The access token will not be cached. Check write access to the CS folder and ASR policies" $_.Exception
}
}
@@ -732,7 +741,10 @@ function Add-MSALPrereq_old
$global:SkipTokenCacheHelperEx = $true
Write-LogError "Failed to compile TokenCacheHelperEx. The access token will not be cached. Check write access to the CS folder and ASR policies" $_.Exception
}
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
if(Test-IsWindowsPlatform)
{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
}
}
function Connect-MSALClientApp
@@ -931,7 +943,14 @@ function Get-MSALApp
[void]$appBuilder.WithAuthority($authority)
if($appInfo.RedirectUri) { [void]$appBuilder.WithRedirectUri($appInfo.RedirectUri) }
if($appInfo.RedirectUri)
{
[void]$appBuilder.WithRedirectUri($appInfo.RedirectUri)
}
else
{
[void]$appBuilder.WithDefaultRedirectUri()
}
[void] $appBuilder.WithClientName("CloudAPIPowerShellManagement")
[void] $appBuilder.WithClientVersion($PSVersionTable.PSVersion)
@@ -952,7 +971,7 @@ function Get-MSALApp
$msalApp = $appBuilder.Build()
if($global:SkipTokenCacheHelperEx -ne $true -and (Get-SettingValue "CacheMSALToken"))
if($global:SkipTokenCacheHelperEx -ne $true -and ("TokenCacheHelperEx" -as [type]) -and (Get-SettingValue "CacheMSALToken"))
{
[TokenCacheHelperEx]::EnableSerialization($msalApp.UserTokenCache, (Join-Path (Get-CloudApiDataFolder) "msalcahce.bin3"))
}
@@ -961,6 +980,53 @@ function Get-MSALApp
return $msalApp
}
function Get-HeadlessPublicClientAppInfo
{
$appObj = $null
if($global:MSGraphGlobalApps)
{
$templateApp = $global:MSGraphGlobalApps | Where-Object ClientId -eq $global:AzureAppId | Select-Object -First 1
if($templateApp)
{
$appObj = [PSCustomObject]@{
Name = $templateApp.Name
ClientId = $templateApp.ClientId
RedirectUri = $templateApp.RedirectUri
Authority = $templateApp.Authority
TenantId = $global:TenantId
}
}
}
if(-not $appObj)
{
$appObj = [PSCustomObject]@{
Name = "Headless Browser Login"
ClientId = $global:AzureAppId
RedirectUri = $null
Authority = $null
TenantId = $global:TenantId
}
}
elseif($appObj.RedirectUri -and $appObj.RedirectUri -notmatch '^http://localhost(:\d+)?/?$')
{
$appObj.RedirectUri = $null
}
if($global:MSALRedirectUri)
{
$appObj.RedirectUri = $global:MSALRedirectUri
}
if($global:TenantId)
{
$appObj.TenantId = $global:TenantId
}
$appObj
}
function Get-MSALAppAuthority
{
try
@@ -1001,20 +1067,33 @@ function Connect-MSALUser
if($global:hideUI -eq $true)
{
if($global:AzureAppId -and $global:ClientSecret -and $global:TenantId)
$headlessAuthMode = ?? $global:HeadlessAuthMode "AppOnly"
if($headlessAuthMode -eq "Browser")
{
if(-not $global:AzureAppId -or -not $global:TenantId)
{
Write-Log "Azure AppId and Tenant Id must be specified for browser auth" 3
return
}
$global:appObj = Get-HeadlessPublicClientAppInfo
}
elseif($global:AzureAppId -and $global:ClientSecret -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -secret $global:ClientSecret
return
}
elseif($global:AzureAppId -and $global:ClientCert -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -certificate $global:ClientCert
return
}
else
{
Write-Log "Azure AppId, Tenant Id and Sercret/Cert must be specified for batch jobs" 3
Write-Log "Azure AppId, Tenant Id and Secret/Cert must be specified for AppOnly auth, or use browser auth" 3
return
}
return
}
# No login during first time the app is started
@@ -1348,7 +1427,7 @@ function Connect-MSALUser
$app = $appBuilder.Build()
if((Get-SettingValue "CacheMSALToken"))
if($global:SkipTokenCacheHelperEx -ne $true -and ("TokenCacheHelperEx" -as [type]) -and (Get-SettingValue "CacheMSALToken"))
{
[TokenCacheHelperEx]::EnableSerialization($app.UserTokenCache, (Join-Path (Get-CloudApiDataFolder) "msalcahce.bin3"))
}

View File

@@ -1313,6 +1313,7 @@ function Show-GraphExportForm
function Invoke-InitSilentBatchJob
{
$global:MSALToken = $null
$headlessAuthMode = ?? $global:HeadlessAuthMode "AppOnly"
if(-not $global:TenantId)
{
@@ -1320,12 +1321,15 @@ function Invoke-InitSilentBatchJob
return
}
if(-not $global:AzureAppId -or (-not $global:ClientSecret -and -not $global:ClientCert))
if(-not $global:AzureAppId -or ($headlessAuthMode -eq "AppOnly" -and (-not $global:ClientSecret -and -not $global:ClientCert)))
{
# Get login info for silent job from settings
$global:AzureAppId = Get-SettingValue "GraphAzureAppId" -TenantID $global:TenantId
$global:ClientSecret = Get-SettingValue "GraphAzureAppSecret" -TenantID $global:TenantId
$global:ClientCert = Get-SettingValue "GraphAzureAppCert" -TenantID $global:TenantId
if($headlessAuthMode -eq "AppOnly")
{
$global:ClientSecret = Get-SettingValue "GraphAzureAppSecret" -TenantID $global:TenantId
$global:ClientCert = Get-SettingValue "GraphAzureAppCert" -TenantID $global:TenantId
}
}
if(-not $global:AzureAppId)
@@ -1334,7 +1338,7 @@ function Invoke-InitSilentBatchJob
return
}
if(-not $global:ClientSecret -and -not $global:ClientCert)
if($headlessAuthMode -eq "AppOnly" -and -not $global:ClientSecret -and -not $global:ClientCert)
{
Write-Log "Secret or Certificate must be specified. Either specify Secret/Certificate in Settings or Command Line" 3
return