Modules/AzureDevOpsDsc.Common/Api/Functions/Private/Authentication/Add-AuthenticationHTTPHeader.ps1
|
<#
.SYNOPSIS Adds the appropriate authentication HTTP header based on the type of authentication token. .DESCRIPTION The Add-AuthenticationHTTPHeader function determines the type of authentication token and adds the corresponding HTTP header. It supports Personal Access Tokens and Managed Identity Tokens. If the token is null or the token type is not supported, an error is thrown. .PARAMETER None This function does not take any parameters. .OUTPUTS String Returns the authentication HTTP header as a string. .NOTES The function relies on the global variables $Global:DSCAZDO_AuthenticationToken and $Global:DSCAZDO_OrganizationName. .EXAMPLE $header = Add-AuthenticationHTTPHeader # Adds the appropriate authentication HTTP header and returns it as a string. #> Function Add-AuthenticationHTTPHeader { # If the global token is null, attempt to restore from clixml cache. # This handles the DSC isolated-runspace scenario where Construct() sets globals in the # constructor runspace but the method (Set/Test/Get) executes in the calling runspace. if ($null -eq $Global:DSCAZDO_AuthenticationToken) { Write-Verbose "[Add-AuthenticationHTTPHeader] Authentication token is null. Attempting to restore from cache." if ($ENV:AZDODSC_CACHE_DIRECTORY) { $settingsPath = Join-Path -Path $ENV:AZDODSC_CACHE_DIRECTORY -ChildPath 'ModuleSettings.clixml' if (Test-Path -LiteralPath $settingsPath) { $objectSettings = Import-Clixml -LiteralPath $settingsPath $organizationName = $objectSettings.OrganizationName # tokenType is serialized as an integer or string enum value: # 0=ManagedIdentity, 1=PersonalAccessToken, 2=Certificate, # 3=ServicePrincipal, 4=AzureCLI, 5=WorkloadIdentityFederation $tokenType = $objectSettings.Token.tokenType try { if ($tokenType -eq 'ManagedIdentity' -or $tokenType -eq 0) { # Reconstruct a live ManagedIdentityToken from the deserialized cached token. # Avoid calling the IMDS endpoint (requires Azure Arc secret-file ACL access). $ct = $objectSettings.Token $epochStart = [datetime]::new(1970, 1, 1, 0, 0, 0, [DateTimeKind]::Utc) $expiresOnUnix = [long]($ct.expires_on.ToUniversalTime() - $epochStart).TotalSeconds $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ct.access_token) $plainToken = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) $tokenData = [PSCustomObject]@{ access_token = $plainToken expires_on = $expiresOnUnix expires_in = [int]$ct.expires_in resource = [string]$ct.resource token_type = [string]$ct.token_type } $Global:DSCAZDO_AuthenticationToken = New-ManagedIdentityToken $tokenData $Global:DSCAZDO_OrganizationName = $organizationName } elseif ($tokenType -eq 'PersonalAccessToken' -or $tokenType -eq 1) { New-AzDoAuthenticationProvider -OrganizationName $organizationName -SecureStringPersonalAccessToken $objectSettings.Token.access_token -isResource -NoVerify } elseif ($tokenType -eq 'Certificate' -or $tokenType -eq 2) { $ct = $objectSettings.Token if (-not [String]::IsNullOrEmpty($ct.certificateThumbprint)) { New-AzDoAuthenticationProvider -OrganizationName $organizationName -TenantId $ct.tenantId -ClientId $ct.clientId -CertificateThumbprint $ct.certificateThumbprint -isResource -NoVerify } else { New-AzDoAuthenticationProvider -OrganizationName $organizationName -TenantId $ct.tenantId -ClientId $ct.clientId -CertificatePath $ct.certificatePath -CertificatePassword $ct.certificatePassword -isResource -NoVerify } } elseif ($tokenType -eq 'ServicePrincipal' -or $tokenType -eq 3) { $ct = $objectSettings.Token New-AzDoAuthenticationProvider -OrganizationName $organizationName -TenantId $ct.tenantId -ClientId $ct.clientId -SecureStringClientSecret $ct.clientSecret -isResource -NoVerify } elseif ($tokenType -eq 'AzureCLI' -or $tokenType -eq 4) { New-AzDoAuthenticationProvider -OrganizationName $organizationName -useAzureCLI -isResource -NoVerify } elseif ($tokenType -eq 'WorkloadIdentityFederation' -or $tokenType -eq 5) { $ct = $objectSettings.Token switch ($ct.federatedTokenSource) { 'File' { New-AzDoAuthenticationProvider -OrganizationName $organizationName -TenantId $ct.tenantId -ClientId $ct.clientId -FederatedTokenFile $ct.federatedTokenFile -isResource -NoVerify } 'GitHubActions' { New-AzDoAuthenticationProvider -OrganizationName $organizationName -TenantId $ct.tenantId -ClientId $ct.clientId -useGitHubActionsOIDC -isResource -NoVerify } default { Write-Warning "[Add-AuthenticationHTTPHeader] WorkloadIdentityFederation source '$($ct.federatedTokenSource)' cannot be restored from cache. Call New-AzDoAuthenticationProvider again to re-authenticate." } } } } catch { Write-Warning "[Add-AuthenticationHTTPHeader] Failed to restore authentication token from cache: $_" } } } } # Dertimine the type of token. $headerValue = "" switch ($Global:DSCAZDO_AuthenticationToken.tokenType) { # If the token is null {[String]::IsNullOrEmpty($_)} { throw "[Add-AuthenticationHTTPHeader] Error. The authentication token is null. Please ensure that the authentication token is set." } {$_ -eq 'PersonalAccessToken'} { # Personal Access Token # Add the Personal Access Token to the header $headerValue = 'Authorization: Basic {0}' -f $Global:DSCAZDO_AuthenticationToken.Get() break } {$_ -eq 'ManagedIdentity'} { # Managed Identity Token Write-Verbose "[Add-AuthenticationHTTPHeader] Adding Managed Identity Token to the HTTP Headers." # Test if the Managed Identity Token has expired if ($Global:DSCAZDO_AuthenticationToken.isExpired()) { Write-Verbose "[Add-AuthenticationHTTPHeader] Managed Identity Token has expired. Obtaining a new token." # Update-AzManagedIdentity sets $Global:DSCAZDO_AuthenticationToken directly; do NOT capture # its return value or the assignment would overwrite the global with $null (the function # has no explicit return statement). Update-AzManagedIdentity -OrganizationName $Global:DSCAZDO_OrganizationName } # Add the Managed Identity Token to the header $headerValue = 'Bearer {0}' -f $Global:DSCAZDO_AuthenticationToken.Get() break } {$_ -eq 'ServicePrincipal'} { Write-Verbose "[Add-AuthenticationHTTPHeader] Adding Service Principal Token to the HTTP Headers." if ($Global:DSCAZDO_AuthenticationToken.isExpired()) { Write-Verbose "[Add-AuthenticationHTTPHeader] Service Principal Token has expired. Obtaining a new token." $Global:DSCAZDO_AuthenticationToken = Update-AzServicePrincipal } $headerValue = 'Bearer {0}' -f $Global:DSCAZDO_AuthenticationToken.Get() break } {$_ -eq 'Certificate'} { Write-Verbose "[Add-AuthenticationHTTPHeader] Adding Certificate Token to the HTTP Headers." if ($Global:DSCAZDO_AuthenticationToken.isExpired()) { Write-Verbose "[Add-AuthenticationHTTPHeader] Certificate Token has expired. Obtaining a new token." $Global:DSCAZDO_AuthenticationToken = Update-AzServicePrincipalCertificate } $headerValue = 'Bearer {0}' -f $Global:DSCAZDO_AuthenticationToken.Get() break } {$_ -eq 'AzureCLI'} { Write-Verbose "[Add-AuthenticationHTTPHeader] Adding Azure CLI Token to the HTTP Headers." if ($Global:DSCAZDO_AuthenticationToken.isExpired()) { Write-Verbose "[Add-AuthenticationHTTPHeader] Azure CLI Token has expired. Obtaining a new token." $Global:DSCAZDO_AuthenticationToken = Update-AzCliToken } $headerValue = 'Bearer {0}' -f $Global:DSCAZDO_AuthenticationToken.Get() break } {$_ -eq 'WorkloadIdentityFederation'} { Write-Verbose "[Add-AuthenticationHTTPHeader] Adding Workload Identity Federation Token to the HTTP Headers." if ($Global:DSCAZDO_AuthenticationToken.isExpired()) { Write-Verbose "[Add-AuthenticationHTTPHeader] Workload Identity Federation Token has expired. Obtaining a new token." $Global:DSCAZDO_AuthenticationToken = Update-AzWorkloadIdentityFederation } $headerValue = 'Bearer {0}' -f $Global:DSCAZDO_AuthenticationToken.Get() break } default { throw "[Add-AuthenticationHTTPHeader] Error. The authentication token type is not supported." } } Write-Verbose "[Add-AuthenticationHTTPHeader] Adding Header" # Return the header value return $headerValue } |