diff --git a/go.mod b/go.mod
index 9ee61b3cc..cf1ed430d 100644
--- a/go.mod
+++ b/go.mod
@@ -33,11 +33,11 @@ require (
cloud.google.com/go/compute/metadata v0.9.0 // indirect
dario.cat/mergo v1.0.2 // indirect
github.com/42wim/httpsig v1.2.3 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
- github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect
+ github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
diff --git a/go.sum b/go.sum
index 21a3dbe81..041058678 100644
--- a/go.sum
+++ b/go.sum
@@ -8,10 +8,10 @@ github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 h1:wL5IEG5zb7BVv1Kv0Xm92orq+5hB5Nipn3B5tn4Rqfk=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
@@ -20,8 +20,8 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEK
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
index 1799c6ef2..47d2b85fa 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
@@ -1,5 +1,16 @@
# Release History
+## 1.20.0 (2025-11-06)
+
+### Features Added
+
+* Added `runtime.FetcherForNextLinkOptions.HTTPVerb` to specify the HTTP verb when fetching the next page via next link. Defaults to `http.MethodGet`.
+
+### Bugs Fixed
+
+* Fixed potential panic when decoding base64 strings.
+* Fixed an issue in resource identifier parsing which prevented it from returning an error for malformed resource IDs.
+
## 1.19.1 (2025-09-11)
### Bugs Fixed
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go
index b8348b7d8..8a40ebe4d 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go
@@ -217,6 +217,7 @@ func appendNext(parent *ResourceID, parts []string, id string) (*ResourceID, err
func splitStringAndOmitEmpty(v, sep string) []string {
r := make([]string, 0)
for _, s := range strings.Split(v, sep) {
+ s = strings.TrimSpace(s)
if len(s) == 0 {
continue
}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go
index 460170034..612af11ac 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go
@@ -92,7 +92,7 @@ func DecodeByteArray(s string, v *[]byte, format Base64Encoding) error {
return nil
}
payload := string(s)
- if payload[0] == '"' {
+ if len(payload) >= 2 && payload[0] == '"' && payload[len(payload)-1] == '"' {
// remove surrounding quotes
payload = payload[1 : len(payload)-1]
}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
index 8aebe5ce5..f15200091 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
@@ -40,5 +40,5 @@ const (
Module = "azcore"
// Version is the semantic version (see http://semver.org) of this module.
- Version = "v1.19.1"
+ Version = "v1.20.0"
)
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go
index c66fc0a90..edb4a3cd4 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pager.go
@@ -99,6 +99,11 @@ type FetcherForNextLinkOptions struct {
// StatusCodes contains additional HTTP status codes indicating success.
// The default value is http.StatusOK.
StatusCodes []int
+
+ // HTTPVerb specifies the HTTP verb to use when fetching the next page.
+ // The default value is http.MethodGet.
+ // This field is only used when NextReq is not specified.
+ HTTPVerb string
}
// FetcherForNextLink is a helper containing boilerplate code to simplify creating a PagingHandler[T].Fetcher from a next link URL.
@@ -119,7 +124,11 @@ func FetcherForNextLink(ctx context.Context, pl Pipeline, nextLink string, first
if options.NextReq != nil {
req, err = options.NextReq(ctx, nextLink)
} else {
- req, err = NewRequest(ctx, http.MethodGet, nextLink)
+ verb := http.MethodGet
+ if options.HTTPVerb != "" {
+ verb = options.HTTPVerb
+ }
+ req, err = NewRequest(ctx, verb, nextLink)
}
}
if err != nil {
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
index ab63f9c03..4a6349e16 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
@@ -1,5 +1,34 @@
# Release History
+## 1.13.1 (2025-11-10)
+
+### Bugs Fixed
+
+- `AzureCLICredential` quoted arguments incorrectly on Windows
+
+## 1.13.0 (2025-10-07)
+
+### Features Added
+
+- Added `AzurePowerShellCredential`, which authenticates as the identity logged in to Azure PowerShell
+ (thanks [ArmaanMcleod](https://github.com/ArmaanMcleod))
+- When `AZURE_TOKEN_CREDENTIALS` is set to `ManagedIdentityCredential`, `DefaultAzureCredential` behaves the same as
+ does `ManagedIdentityCredential` when used directly. It doesn't apply special retry configuration or attempt to
+ determine whether IMDS is available. ([#25265](https://github.com/Azure/azure-sdk-for-go/issues/25265))
+
+### Breaking Changes
+
+* Removed the `WorkloadIdentityCredential` support for identity binding mode added in v1.13.0-beta.1.
+ It will return in v1.14.0-beta.1
+
+## 1.13.0-beta.1 (2025-09-17)
+
+### Features Added
+
+- Added `AzurePowerShellCredential`, which authenticates as the identity logged in to Azure PowerShell
+ (thanks [ArmaanMcleod](https://github.com/ArmaanMcleod))
+- `WorkloadIdentityCredential` supports identity binding mode ([#25056](https://github.com/Azure/azure-sdk-for-go/issues/25056))
+
## 1.12.0 (2025-09-16)
### Features Added
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md
index 069bc688d..127c25b72 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md
@@ -1,6 +1,6 @@
# Azure Identity Client Module for Go
-The Azure Identity module provides Microsoft Entra ID ([formerly Azure Active Directory](https://learn.microsoft.com/entra/fundamentals/new-name)) token authentication support across the Azure SDK. It includes a set of `TokenCredential` implementations, which can be used with Azure SDK clients supporting token authentication.
+The Azure Identity module provides [Microsoft Entra ID](https://learn.microsoft.com/entra/fundamentals/whatis) token-based authentication support across the Azure SDK. It includes a set of `TokenCredential` implementations, which can be used with Azure SDK clients supporting token authentication.
[](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity)
| [Microsoft Entra ID documentation](https://learn.microsoft.com/entra/identity/)
@@ -153,6 +153,7 @@ client := armresources.NewResourceGroupsClient("subscription ID", chain, nil)
|-|-
|[AzureCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureCLICredential)|Authenticate as the user signed in to the Azure CLI
|[AzureDeveloperCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureDeveloperCLICredential)|Authenticates as the user signed in to the Azure Developer CLI
+|[AzurePowerShellCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzurePowerShellCredential)|Authenticates as the user signed in to Azure PowerShell
## Environment Variables
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD
index da2094e36..8bdaf8165 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD
@@ -40,6 +40,7 @@ The following table indicates the state of in-memory and persistent caching in e
| ------------------------------ | ------------------------------------------------------------------- | ------------------------ |
| `AzureCLICredential` | Not Supported | Not Supported |
| `AzureDeveloperCLICredential` | Not Supported | Not Supported |
+| `AzurePowerShellCredential` | Not Supported | Not Supported |
| `AzurePipelinesCredential` | Supported | Supported |
| `ClientAssertionCredential` | Supported | Supported |
| `ClientCertificateCredential` | Supported | Supported |
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
index 838601d69..517006a42 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
@@ -12,6 +12,7 @@ This troubleshooting guide covers failure investigation techniques, common error
- [Troubleshoot AzureCLICredential authentication issues](#troubleshoot-azureclicredential-authentication-issues)
- [Troubleshoot AzureDeveloperCLICredential authentication issues](#troubleshoot-azuredeveloperclicredential-authentication-issues)
- [Troubleshoot AzurePipelinesCredential authentication issues](#troubleshoot-azurepipelinescredential-authentication-issues)
+- [Troubleshoot AzurePowerShellCredential authentication issues](#troubleshoot-azurepowershellcredential-authentication-issues)
- [Troubleshoot ClientCertificateCredential authentication issues](#troubleshoot-clientcertificatecredential-authentication-issues)
- [Troubleshoot ClientSecretCredential authentication issues](#troubleshoot-clientsecretcredential-authentication-issues)
- [Troubleshoot DefaultAzureCredential authentication issues](#troubleshoot-defaultazurecredential-authentication-issues)
@@ -205,6 +206,34 @@ azd auth token --output json --scope https://management.core.windows.net/.defaul
```
>Note that output of this command will contain a valid access token, and SHOULD NOT BE SHARED to avoid compromising account security.
+
+## Troubleshoot `AzurePowerShellCredential` authentication issues
+
+| Error Message |Description| Mitigation |
+|---|---|---|
+|executable not found on path|No local installation of PowerShell was found.|Ensure that PowerShell is properly installed on the machine. Instructions for installing PowerShell can be found [here](https://learn.microsoft.com/powershell/scripting/install/installing-powershell).|
+|Az.Accounts module not found|The Az.Account module needed for authentication in Azure PowerShell isn't installed.|Install the latest Az.Account module. Installation instructions can be found [here](https://learn.microsoft.com/powershell/azure/install-az-ps).|
+|Please run "Connect-AzAccount" to set up account.|No account is currently logged into Azure PowerShell.|
- Log in to Azure PowerShell using the `Connect-AzAccount` command. More instructions for authenticating Azure PowerShell can be found at [Sign in with Azure PowerShell](https://learn.microsoft.com/powershell/azure/authenticate-azureps).
- Validate that Azure PowerShell can obtain tokens. For instructions, see [Verify Azure PowerShell can obtain tokens](#verify-azure-powershell-can-obtain-tokens).
|
+
+#### __Verify Azure PowerShell can obtain tokens__
+
+You can manually verify that Azure PowerShell is authenticated and can obtain tokens. First, use the `Get-AzContext` command to verify the account that is currently logged in to Azure PowerShell.
+
+```
+PS C:\> Get-AzContext
+
+Name Account SubscriptionName Environment TenantId
+---- ------- ---------------- ----------- --------
+Subscription1 (xxxxxxxx-xxxx-xxxx-xxx... test@outlook.com Subscription1 AzureCloud xxxxxxxx-x...
+```
+
+Once you've verified Azure PowerShell is using correct account, validate that it's able to obtain tokens for this account:
+
+```bash
+Get-AzAccessToken -ResourceUrl "https://management.core.windows.net"
+```
+>Note that output of this command will contain a valid access token, and SHOULD NOT BE SHARED to avoid compromising account security.
+
## Troubleshoot `WorkloadIdentityCredential` authentication issues
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go
new file mode 100644
index 000000000..082965554
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_powershell_credential.go
@@ -0,0 +1,234 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azidentity
+
+import (
+ "context"
+ "encoding/base64"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os/exec"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+ "unicode/utf16"
+
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore"
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
+ "github.com/Azure/azure-sdk-for-go/sdk/internal/log"
+)
+
+const (
+ credNameAzurePowerShell = "AzurePowerShellCredential"
+ noAzAccountModule = "Az.Accounts module not found"
+)
+
+// AzurePowerShellCredentialOptions contains optional parameters for AzurePowerShellCredential.
+type AzurePowerShellCredentialOptions struct {
+ // AdditionallyAllowedTenants specifies tenants to which the credential may authenticate, in addition to
+ // TenantID. When TenantID is empty, this option has no effect and the credential will authenticate to
+ // any requested tenant. Add the wildcard value "*" to allow the credential to authenticate to any tenant.
+ AdditionallyAllowedTenants []string
+
+ // TenantID identifies the tenant the credential should authenticate in.
+ // Defaults to Azure PowerShell's default tenant, which is typically the home tenant of the logged in user.
+ TenantID string
+
+ // inDefaultChain is true when the credential is part of DefaultAzureCredential
+ inDefaultChain bool
+
+ // exec is used by tests to fake invoking Azure PowerShell
+ exec executor
+}
+
+// AzurePowerShellCredential authenticates as the identity logged in to Azure PowerShell.
+type AzurePowerShellCredential struct {
+ mu *sync.Mutex
+ opts AzurePowerShellCredentialOptions
+}
+
+// NewAzurePowerShellCredential constructs an AzurePowerShellCredential. Pass nil to accept default options.
+func NewAzurePowerShellCredential(options *AzurePowerShellCredentialOptions) (*AzurePowerShellCredential, error) {
+ cp := AzurePowerShellCredentialOptions{}
+
+ if options != nil {
+ cp = *options
+ }
+
+ if cp.TenantID != "" && !validTenantID(cp.TenantID) {
+ return nil, errInvalidTenantID
+ }
+
+ if cp.exec == nil {
+ cp.exec = shellExec
+ }
+
+ cp.AdditionallyAllowedTenants = resolveAdditionalTenants(cp.AdditionallyAllowedTenants)
+
+ return &AzurePowerShellCredential{mu: &sync.Mutex{}, opts: cp}, nil
+}
+
+// GetToken requests a token from Azure PowerShell. This credential doesn't cache tokens, so every call invokes Azure PowerShell.
+// This method is called automatically by Azure SDK clients.
+func (c *AzurePowerShellCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
+ at := azcore.AccessToken{}
+
+ if len(opts.Scopes) != 1 {
+ return at, errors.New(credNameAzurePowerShell + ": GetToken() requires exactly one scope")
+ }
+
+ if !validScope(opts.Scopes[0]) {
+ return at, fmt.Errorf("%s.GetToken(): invalid scope %q", credNameAzurePowerShell, opts.Scopes[0])
+ }
+
+ tenant, err := resolveTenant(c.opts.TenantID, opts.TenantID, credNameAzurePowerShell, c.opts.AdditionallyAllowedTenants)
+ if err != nil {
+ return at, err
+ }
+
+ // Always pass a Microsoft Entra ID v1 resource URI (not a v2 scope) because Get-AzAccessToken only supports v1 resource URIs.
+ resource := strings.TrimSuffix(opts.Scopes[0], defaultSuffix)
+
+ tenantArg := ""
+ if tenant != "" {
+ tenantArg = fmt.Sprintf(" -TenantId '%s'", tenant)
+ }
+
+ if opts.Claims != "" {
+ encoded := base64.StdEncoding.EncodeToString([]byte(opts.Claims))
+ return at, fmt.Errorf(
+ "%s.GetToken(): Azure PowerShell requires multifactor authentication or additional claims. Run this command then retry the operation: Connect-AzAccount%s -ClaimsChallenge '%s'",
+ credNameAzurePowerShell,
+ tenantArg,
+ encoded,
+ )
+ }
+
+ // Inline script to handle Get-AzAccessToken differences between Az.Accounts versions with SecureString handling and minimum version requirement
+ script := fmt.Sprintf(`
+$ErrorActionPreference = 'Stop'
+[version]$minimumVersion = '2.2.0'
+
+$mod = Import-Module Az.Accounts -MinimumVersion $minimumVersion -PassThru -ErrorAction SilentlyContinue
+
+if (-not $mod) {
+ Write-Error '%s'
+}
+
+$params = @{
+ ResourceUrl = '%s'
+ WarningAction = 'Ignore'
+}
+
+# Only force AsSecureString for Az.Accounts versions > 2.17.0 and < 5.0.0 which return plain text token by default.
+# Newer Az.Accounts versions return SecureString token by default and no longer use AsSecureString parameter.
+if ($mod.Version -ge [version]'2.17.0' -and $mod.Version -lt [version]'5.0.0') {
+ $params['AsSecureString'] = $true
+}
+
+$tenantId = '%s'
+if ($tenantId.Length -gt 0) {
+ $params['TenantId'] = '%s'
+}
+
+$token = Get-AzAccessToken @params
+
+$customToken = New-Object -TypeName psobject
+
+# The following .NET interop pattern is supported in all PowerShell versions and safely converts SecureString to plain text.
+if ($token.Token -is [System.Security.SecureString]) {
+ $ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($token.Token)
+ try {
+ $plainToken = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
+ } finally {
+ [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
+ }
+ $customToken | Add-Member -MemberType NoteProperty -Name Token -Value $plainToken
+} else {
+ $customToken | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token
+}
+$customToken | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn.ToUnixTimeSeconds()
+
+$jsonToken = $customToken | ConvertTo-Json
+return $jsonToken
+`, noAzAccountModule, resource, tenant, tenant)
+
+ // Windows: prefer pwsh.exe (PowerShell Core), fallback to powershell.exe (Windows PowerShell)
+ // Unix: only support pwsh (PowerShell Core)
+ exe := "pwsh"
+ if runtime.GOOS == "windows" {
+ if _, err := exec.LookPath("pwsh.exe"); err == nil {
+ exe = "pwsh.exe"
+ } else {
+ exe = "powershell.exe"
+ }
+ }
+
+ command := exe + " -NoProfile -NonInteractive -OutputFormat Text -EncodedCommand " + base64EncodeUTF16LE(script)
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ b, err := c.opts.exec(ctx, credNameAzurePowerShell, command)
+ if err == nil {
+ at, err = c.createAccessToken(b)
+ }
+
+ if err != nil {
+ err = unavailableIfInDAC(err, c.opts.inDefaultChain)
+ return at, err
+ }
+
+ msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", credNameAzurePowerShell, strings.Join(opts.Scopes, ", "))
+ log.Write(EventAuthentication, msg)
+
+ return at, nil
+}
+
+func (c *AzurePowerShellCredential) createAccessToken(tk []byte) (azcore.AccessToken, error) {
+ t := struct {
+ Token string `json:"Token"`
+ ExpiresOn int64 `json:"ExpiresOn"`
+ }{}
+
+ err := json.Unmarshal(tk, &t)
+ if err != nil {
+ return azcore.AccessToken{}, err
+ }
+
+ converted := azcore.AccessToken{
+ Token: t.Token,
+ ExpiresOn: time.Unix(t.ExpiresOn, 0).UTC(),
+ }
+
+ return converted, nil
+}
+
+// Encodes a string to Base64 using UTF-16LE encoding
+func base64EncodeUTF16LE(text string) string {
+ u16 := utf16.Encode([]rune(text))
+ buf := make([]byte, len(u16)*2)
+ for i, v := range u16 {
+ binary.LittleEndian.PutUint16(buf[i*2:], v)
+ }
+ return base64.StdEncoding.EncodeToString(buf)
+}
+
+// Decodes a Base64 UTF-16LE string back to string
+func base64DecodeUTF16LE(encoded string) (string, error) {
+ data, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return "", err
+ }
+ u16 := make([]uint16, len(data)/2)
+ for i := range u16 {
+ u16[i] = binary.LittleEndian.Uint16(data[i*2:])
+ }
+ return string(utf16.Decode(u16)), nil
+}
+
+var _ azcore.TokenCredential = (*AzurePowerShellCredential)(nil)
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
index c041a52db..aaaabc5c2 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
@@ -26,6 +26,7 @@ const (
managedIdentity
az
azd
+ azurePowerShell
)
// DefaultAzureCredentialOptions contains optional parameters for DefaultAzureCredential.
@@ -71,6 +72,7 @@ type DefaultAzureCredentialOptions struct {
// - [ManagedIdentityCredential]
// - [AzureCLICredential]
// - [AzureDeveloperCLICredential]
+// - [AzurePowerShellCredential]
//
// Consult the documentation for these credential types for more information on how they authenticate.
// Once a credential has successfully authenticated, DefaultAzureCredential will use that credential for
@@ -83,7 +85,7 @@ type DefaultAzureCredentialOptions struct {
// Valid values for AZURE_TOKEN_CREDENTIALS are the name of any single type in the above chain, for example
// "EnvironmentCredential" or "AzureCLICredential", and these special values:
//
-// - "dev": try [AzureCLICredential] and [AzureDeveloperCLICredential], in that order
+// - "dev": try [AzureCLICredential], [AzureDeveloperCLICredential], and [AzurePowerShellCredential], in that order
// - "prod": try [EnvironmentCredential], [WorkloadIdentityCredential], and [ManagedIdentityCredential], in that order
//
// [DefaultAzureCredentialOptions].RequireAzureTokenCredentials controls whether AZURE_TOKEN_CREDENTIALS must be set.
@@ -104,13 +106,13 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
var (
creds []azcore.TokenCredential
errorMessages []string
- selected = env | workloadIdentity | managedIdentity | az | azd
+ selected = env | workloadIdentity | managedIdentity | az | azd | azurePowerShell
)
if atc, ok := os.LookupEnv(azureTokenCredentials); ok {
switch {
case atc == "dev":
- selected = az | azd
+ selected = az | azd | azurePowerShell
case atc == "prod":
selected = env | workloadIdentity | managedIdentity
case strings.EqualFold(atc, credNameEnvironment):
@@ -123,6 +125,8 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
selected = az
case strings.EqualFold(atc, credNameAzureDeveloperCLI):
selected = azd
+ case strings.EqualFold(atc, credNameAzurePowerShell):
+ selected = azurePowerShell
default:
return nil, fmt.Errorf(`invalid %s value %q. Valid values are "dev", "prod", or the name of any credential type in the default chain. See https://aka.ms/azsdk/go/identity/docs#DefaultAzureCredential for more information`, azureTokenCredentials, atc)
}
@@ -164,7 +168,11 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
}
}
if selected&managedIdentity != 0 {
- o := &ManagedIdentityCredentialOptions{ClientOptions: options.ClientOptions, dac: true}
+ o := &ManagedIdentityCredentialOptions{
+ ClientOptions: options.ClientOptions,
+ // enable special DefaultAzureCredential behavior (IMDS probing) only when the chain contains another credential
+ dac: selected^managedIdentity != 0,
+ }
if ID, ok := os.LookupEnv(azureClientID); ok {
o.ID = ClientID(ID)
}
@@ -202,6 +210,19 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
creds = append(creds, &defaultCredentialErrorReporter{credType: credNameAzureDeveloperCLI, err: err})
}
}
+ if selected&azurePowerShell != 0 {
+ azurePowerShellCred, err := NewAzurePowerShellCredential(&AzurePowerShellCredentialOptions{
+ AdditionallyAllowedTenants: additionalTenants,
+ TenantID: options.TenantID,
+ inDefaultChain: true,
+ })
+ if err == nil {
+ creds = append(creds, azurePowerShellCred)
+ } else {
+ errorMessages = append(errorMessages, credNameAzurePowerShell+": "+err.Error())
+ creds = append(creds, &defaultCredentialErrorReporter{credType: credNameAzurePowerShell, err: err})
+ }
+ }
if len(errorMessages) > 0 {
log.Writef(EventAuthentication, "NewDefaultAzureCredential failed to initialize some credentials:\n\t%s", strings.Join(errorMessages, "\n\t"))
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go
index 14f8a0312..cb7dbe2e4 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util.go
@@ -12,7 +12,6 @@ import (
"errors"
"os"
"os/exec"
- "runtime"
"strings"
"time"
)
@@ -30,17 +29,9 @@ var shellExec = func(ctx context.Context, credName, command string) ([]byte, err
ctx, cancel = context.WithTimeout(ctx, cliTimeout)
defer cancel()
}
- var cmd *exec.Cmd
- if runtime.GOOS == "windows" {
- dir := os.Getenv("SYSTEMROOT")
- if dir == "" {
- return nil, newCredentialUnavailableError(credName, `environment variable "SYSTEMROOT" has no value`)
- }
- cmd = exec.CommandContext(ctx, "cmd.exe", "/c", command)
- cmd.Dir = dir
- } else {
- cmd = exec.CommandContext(ctx, "/bin/sh", "-c", command)
- cmd.Dir = "/bin"
+ cmd, err := buildCmd(ctx, credName, command)
+ if err != nil {
+ return nil, err
}
cmd.Env = os.Environ()
stderr := bytes.Buffer{}
@@ -57,7 +48,15 @@ var shellExec = func(ctx context.Context, credName, command string) ([]byte, err
msg := stderr.String()
var exErr *exec.ExitError
if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.Contains(msg, "' is not recognized") {
- return nil, newCredentialUnavailableError(credName, "CLI executable not found on path")
+ return nil, newCredentialUnavailableError(credName, "executable not found on path")
+ }
+ if credName == credNameAzurePowerShell {
+ if strings.Contains(msg, "Connect-AzAccount") {
+ msg = `Please run "Connect-AzAccount" to set up an account`
+ }
+ if strings.Contains(msg, noAzAccountModule) {
+ msg = noAzAccountModule
+ }
}
if msg == "" {
msg = err.Error()
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go
new file mode 100644
index 000000000..681fcd0cf
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_nonwindows.go
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+//go:build !windows
+
+package azidentity
+
+import (
+ "context"
+ "os/exec"
+)
+
+func buildCmd(ctx context.Context, _, command string) (*exec.Cmd, error) {
+ cmd := exec.CommandContext(ctx, "/bin/sh", "-c", command)
+ cmd.Dir = "/bin"
+ return cmd, nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go
new file mode 100644
index 000000000..09c7a1a97
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/developer_credential_util_windows.go
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package azidentity
+
+import (
+ "context"
+ "os"
+ "os/exec"
+ "syscall"
+)
+
+func buildCmd(ctx context.Context, credName, command string) (*exec.Cmd, error) {
+ dir := os.Getenv("SYSTEMROOT")
+ if dir == "" {
+ return nil, newCredentialUnavailableError(credName, `environment variable "SYSTEMROOT" has no value`)
+ }
+ cmd := exec.CommandContext(ctx, "cmd.exe")
+ cmd.Dir = dir
+ cmd.SysProcAttr = &syscall.SysProcAttr{CmdLine: "/c " + command}
+ return cmd, nil
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go
index a6d7c6cbc..33cb63be0 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go
@@ -99,6 +99,8 @@ func (e *AuthenticationFailedError) Error() string {
anchor = "apc"
case credNameCert:
anchor = "client-cert"
+ case credNameAzurePowerShell:
+ anchor = "azure-pwsh"
case credNameSecret:
anchor = "client-secret"
case credNameManagedIdentity:
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go
index 4c8860536..041f11658 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go
@@ -14,5 +14,5 @@ const (
module = "github.com/Azure/azure-sdk-for-go/sdk/" + component
// Version is the semantic version (see http://semver.org) of this module.
- version = "v1.12.0"
+ version = "v1.13.1"
)
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go
index 549d68ab9..29c004320 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential/confidential.go
@@ -596,6 +596,11 @@ func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts
return AuthResult{}, errors.New("call another AcquireToken method to request a new token having these claims")
}
+ // For service principal scenarios, require WithSilentAccount for public API
+ if o.account.IsZero() {
+ return AuthResult{}, errors.New("WithSilentAccount option is required")
+ }
+
silentParameters := base.AcquireTokenSilentParameters{
Scopes: scopes,
Account: o.account,
@@ -604,8 +609,15 @@ func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts
IsAppCache: o.account.IsZero(),
TenantID: o.tenantID,
AuthnScheme: o.authnScheme,
+ Claims: o.claims,
}
+ return cca.acquireTokenSilentInternal(ctx, silentParameters)
+}
+
+// acquireTokenSilentInternal is the internal implementation shared by AcquireTokenSilent and AcquireTokenByCredential
+func (cca Client) acquireTokenSilentInternal(ctx context.Context, silentParameters base.AcquireTokenSilentParameters) (AuthResult, error) {
+
return cca.base.AcquireTokenSilent(ctx, silentParameters)
}
@@ -708,8 +720,10 @@ func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redir
// acquireTokenByCredentialOptions contains optional configuration for AcquireTokenByCredential
type acquireTokenByCredentialOptions struct {
- claims, tenantID string
- authnScheme AuthenticationScheme
+ claims, tenantID string
+ authnScheme AuthenticationScheme
+ extraBodyParameters map[string]string
+ cacheKeyComponents map[string]string
}
// AcquireByCredentialOption is implemented by options for AcquireTokenByCredential
@@ -719,7 +733,7 @@ type AcquireByCredentialOption interface {
// AcquireTokenByCredential acquires a security token from the authority, using the client credentials grant.
//
-// Options: [WithClaims], [WithTenantID]
+// Options: [WithClaims], [WithTenantID], [WithFMIPath], [WithAttribute]
func (cca Client) AcquireTokenByCredential(ctx context.Context, scopes []string, opts ...AcquireByCredentialOption) (AuthResult, error) {
o := acquireTokenByCredentialOptions{}
err := options.ApplyOptions(&o, opts)
@@ -736,6 +750,29 @@ func (cca Client) AcquireTokenByCredential(ctx context.Context, scopes []string,
if o.authnScheme != nil {
authParams.AuthnScheme = o.authnScheme
}
+ authParams.ExtraBodyParameters = o.extraBodyParameters
+ authParams.CacheKeyComponents = o.cacheKeyComponents
+ if o.claims == "" {
+ silentParameters := base.AcquireTokenSilentParameters{
+ Scopes: scopes,
+ Account: Account{}, // empty account for app token
+ RequestType: accesstokens.ATConfidential,
+ Credential: cca.cred,
+ IsAppCache: true,
+ TenantID: o.tenantID,
+ AuthnScheme: o.authnScheme,
+ Claims: o.claims,
+ ExtraBodyParameters: o.extraBodyParameters,
+ CacheKeyComponents: o.cacheKeyComponents,
+ }
+
+ // Use internal method with empty account (service principal scenario)
+ cache, err := cca.acquireTokenSilentInternal(ctx, silentParameters)
+ if err == nil {
+ return cache, nil
+ }
+ }
+
token, err := cca.base.Token.Credential(ctx, authParams, cca.cred)
if err != nil {
return AuthResult{}, err
@@ -781,3 +818,63 @@ func (cca Client) Account(ctx context.Context, accountID string) (Account, error
func (cca Client) RemoveAccount(ctx context.Context, account Account) error {
return cca.base.RemoveAccount(ctx, account)
}
+
+// WithFMIPath specifies the path to a federated managed identity.
+// The path should point to a valid FMI configuration file that contains the necessary
+// identity information for authentication.
+func WithFMIPath(path string) interface {
+ AcquireByCredentialOption
+ options.CallOption
+} {
+ return struct {
+ AcquireByCredentialOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenByCredentialOptions:
+ if t.extraBodyParameters == nil {
+ t.extraBodyParameters = make(map[string]string)
+ }
+ if t.cacheKeyComponents == nil {
+ t.cacheKeyComponents = make(map[string]string)
+ }
+ t.cacheKeyComponents["fmi_path"] = path
+ t.extraBodyParameters["fmi_path"] = path
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
+
+// WithAttribute specifies an identity attribute to include in the token request.
+// The attribute is sent as "attributes" in the request body and returned as "xmc_attr"
+// in the access token claims. This is sometimes used withFMIPath
+func WithAttribute(attrValue string) interface {
+ AcquireByCredentialOption
+ options.CallOption
+} {
+ return struct {
+ AcquireByCredentialOption
+ options.CallOption
+ }{
+ CallOption: options.NewCallOption(
+ func(a any) error {
+ switch t := a.(type) {
+ case *acquireTokenByCredentialOptions:
+ if t.extraBodyParameters == nil {
+ t.extraBodyParameters = make(map[string]string)
+ }
+ t.extraBodyParameters["attributes"] = attrValue
+ default:
+ return fmt.Errorf("unexpected options type %T", a)
+ }
+ return nil
+ },
+ ),
+ }
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
index 61c1c4cec..abf54f7e5 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
@@ -46,16 +46,18 @@ type accountManager interface {
// AcquireTokenSilentParameters contains the parameters to acquire a token silently (from cache).
type AcquireTokenSilentParameters struct {
- Scopes []string
- Account shared.Account
- RequestType accesstokens.AppType
- Credential *accesstokens.Credential
- IsAppCache bool
- TenantID string
- UserAssertion string
- AuthorizationType authority.AuthorizeType
- Claims string
- AuthnScheme authority.AuthenticationScheme
+ Scopes []string
+ Account shared.Account
+ RequestType accesstokens.AppType
+ Credential *accesstokens.Credential
+ IsAppCache bool
+ TenantID string
+ UserAssertion string
+ AuthorizationType authority.AuthorizeType
+ Claims string
+ AuthnScheme authority.AuthenticationScheme
+ ExtraBodyParameters map[string]string
+ CacheKeyComponents map[string]string
}
// AcquireTokenAuthCodeParameters contains the parameters required to acquire an access token using the auth code flow.
@@ -327,7 +329,12 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen
if silent.AuthnScheme != nil {
authParams.AuthnScheme = silent.AuthnScheme
}
-
+ if silent.CacheKeyComponents != nil {
+ authParams.CacheKeyComponents = silent.CacheKeyComponents
+ }
+ if silent.ExtraBodyParameters != nil {
+ authParams.ExtraBodyParameters = silent.ExtraBodyParameters
+ }
m := b.pmanager
if authParams.AuthorizationType != authority.ATOnBehalfOf {
authParams.AuthorizationType = authority.ATRefreshToken
@@ -367,8 +374,19 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen
// If the token is not same, we don't need to refresh it.
// Which means it refreshed.
if str, err := m.Read(ctx, authParams); err == nil && str.AccessToken.Secret == ar.AccessToken {
- if tr, er := b.Token.Credential(ctx, authParams, silent.Credential); er == nil {
- return b.AuthResultFromToken(ctx, authParams, tr)
+ switch silent.RequestType {
+ case accesstokens.ATConfidential:
+ if tr, er := b.Token.Credential(ctx, authParams, silent.Credential); er == nil {
+ return b.AuthResultFromToken(ctx, authParams, tr)
+ }
+ case accesstokens.ATPublic:
+ token, err := b.Token.Refresh(ctx, silent.RequestType, authParams, silent.Credential, storageTokenResponse.RefreshToken)
+ if err != nil {
+ return ar, err
+ }
+ return b.AuthResultFromToken(ctx, authParams, token)
+ case accesstokens.ATUnknown:
+ return ar, errors.New("silent request type cannot be ATUnknown")
}
}
}
@@ -446,6 +464,9 @@ func (b Client) AcquireTokenOnBehalfOf(ctx context.Context, onBehalfOfParams Acq
authParams.Claims = onBehalfOfParams.Claims
authParams.Scopes = onBehalfOfParams.Scopes
authParams.UserAssertion = onBehalfOfParams.UserAssertion
+ if authParams.ExtraBodyParameters != nil {
+ authParams.ExtraBodyParameters = silentParameters.ExtraBodyParameters
+ }
token, err := b.Token.OnBehalfOf(ctx, authParams, onBehalfOfParams.Credential)
if err == nil {
ar, err = b.AuthResultFromToken(ctx, authParams, token)
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go
index 7379e2233..b7d1a670b 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/items.go
@@ -79,6 +79,7 @@ type AccessToken struct {
UserAssertionHash string `json:"user_assertion_hash,omitempty"`
TokenType string `json:"token_type,omitempty"`
AuthnSchemeKeyID string `json:"keyid,omitempty"`
+ ExtCacheKey string `json:"ext_cache_key,omitempty"`
AdditionalFields map[string]interface{}
}
@@ -105,15 +106,21 @@ func NewAccessToken(homeID, env, realm, clientID string, cachedAt, refreshOn, ex
// Key outputs the key that can be used to uniquely look up this entry in a map.
func (a AccessToken) Key() string {
ks := []string{a.HomeAccountID, a.Environment, a.CredentialType, a.ClientID, a.Realm, a.Scopes}
- key := strings.Join(
- ks,
- shared.CacheKeySeparator,
- )
+
// add token type to key for new access tokens types. skip for bearer token type to
// preserve fwd and back compat between a common cache and msal clients
if !strings.EqualFold(a.TokenType, authority.AccessTokenTypeBearer) {
- key = strings.Join([]string{key, a.TokenType}, shared.CacheKeySeparator)
+ ks = append(ks, a.TokenType)
}
+ // add extra body param hash to key if present
+ if a.ExtCacheKey != "" {
+ ks[2] = "atext" // if the there is extra cache we add "atext" to the key replacing accesstoken
+ ks = append(ks, a.ExtCacheKey)
+ }
+ key := strings.Join(
+ ks,
+ shared.CacheKeySeparator,
+ )
return strings.ToLower(key)
}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go
index 84a234967..825d8a0f6 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage/storage.go
@@ -135,7 +135,8 @@ func (m *Manager) Read(ctx context.Context, authParameters authority.AuthParams)
aliases = metadata.Aliases
}
- accessToken := m.readAccessToken(homeAccountID, aliases, realm, clientID, scopes, tokenType, authnSchemeKeyID)
+ accessToken := m.readAccessToken(homeAccountID, aliases, realm, clientID, scopes, tokenType, authnSchemeKeyID, authParameters.CacheExtKeyGenerator())
+
tr.AccessToken = accessToken
if homeAccountID == "" {
@@ -203,6 +204,7 @@ func (m *Manager) Write(authParameters authority.AuthParams, tokenResponse acces
authnSchemeKeyID,
)
+ accessToken.ExtCacheKey = authParameters.CacheExtKeyGenerator()
// Since we have a valid access token, cache it before moving on.
if err := accessToken.Validate(); err == nil {
if err := m.writeAccessToken(accessToken); err != nil {
@@ -291,26 +293,49 @@ func (m *Manager) aadMetadata(ctx context.Context, authorityInfo authority.Info)
return m.aadCache[authorityInfo.Host], nil
}
-func (m *Manager) readAccessToken(homeID string, envAliases []string, realm, clientID string, scopes []string, tokenType, authnSchemeKeyID string) AccessToken {
+func (m *Manager) readAccessToken(homeID string, envAliases []string, realm, clientID string, scopes []string, tokenType, authnSchemeKeyID, extCacheKey string) AccessToken {
m.contractMu.RLock()
- // TODO: linear search (over a map no less) is slow for a large number (thousands) of tokens.
- // this shows up as the dominating node in a profile. for real-world scenarios this likely isn't
- // an issue, however if it does become a problem then we know where to look.
- for k, at := range m.contract.AccessTokens {
+
+ tokensToSearch := m.contract.AccessTokens
+
+ for k, at := range tokensToSearch {
+ // TODO: linear search (over a map no less) is slow for a large number (thousands) of tokens.
+ // this shows up as the dominating node in a profile. for real-world scenarios this likely isn't
+ // an issue, however if it does become a problem then we know where to look.
if at.HomeAccountID == homeID && at.Realm == realm && at.ClientID == clientID {
- if (strings.EqualFold(at.TokenType, tokenType) && at.AuthnSchemeKeyID == authnSchemeKeyID) || (at.TokenType == "" && (tokenType == "" || tokenType == "Bearer")) {
- if checkAlias(at.Environment, envAliases) && isMatchingScopes(scopes, at.Scopes) {
- m.contractMu.RUnlock()
- if needsUpgrade(k) {
- m.contractMu.Lock()
- defer m.contractMu.Unlock()
- at = upgrade(m.contract.AccessTokens, k)
+ // Match token type and authentication scheme
+ tokenTypeMatch := (strings.EqualFold(at.TokenType, tokenType) && at.AuthnSchemeKeyID == authnSchemeKeyID) ||
+ (at.TokenType == "" && (tokenType == "" || tokenType == "Bearer"))
+ environmentAndScopesMatch := checkAlias(at.Environment, envAliases) && isMatchingScopes(scopes, at.Scopes)
+
+ if tokenTypeMatch && environmentAndScopesMatch {
+ // For hashed tokens, check that the key contains the hash
+ if extCacheKey != "" {
+ if !strings.Contains(k, extCacheKey) {
+ continue // Skip this token if the key doesn't contain the hash
+ }
+ } else {
+ // If no extCacheKey is provided, only match tokens that also have no extCacheKey
+ if at.ExtCacheKey != "" {
+ continue // Skip tokens that require a hash when no hash is provided
}
+ }
+ // Handle token upgrade if needed
+ if needsUpgrade(k) {
+ m.contractMu.RUnlock()
+ m.contractMu.Lock()
+ at = upgrade(tokensToSearch, k)
+ m.contractMu.Unlock()
return at
}
+
+ m.contractMu.RUnlock()
+ return at
}
}
}
+
+ // No token found, unlock and return empty token
m.contractMu.RUnlock()
return AccessToken{}
}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
index d738c7591..481f9e434 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
@@ -281,6 +281,9 @@ func (c Client) FromClientSecret(ctx context.Context, authParameters authority.A
qv.Set(clientID, authParameters.ClientID)
addScopeQueryParam(qv, authParameters)
+ // Add extra body parameters if provided
+ addExtraBodyParameters(ctx, qv, authParameters)
+
return c.doTokenResp(ctx, authParameters, qv)
}
@@ -296,6 +299,9 @@ func (c Client) FromAssertion(ctx context.Context, authParameters authority.Auth
qv.Set(clientInfo, clientInfoVal)
addScopeQueryParam(qv, authParameters)
+ // Add extra body parameters if provided
+ addExtraBodyParameters(ctx, qv, authParameters)
+
return c.doTokenResp(ctx, authParameters, qv)
}
@@ -329,6 +335,8 @@ func (c Client) FromUserAssertionClientCertificate(ctx context.Context, authPara
qv.Set("requested_token_use", "on_behalf_of")
addScopeQueryParam(qv, authParameters)
+ // Add extra body parameters if provided
+ addExtraBodyParameters(ctx, qv, authParameters)
return c.doTokenResp(ctx, authParameters, qv)
}
@@ -466,3 +474,12 @@ func addScopeQueryParam(queryParams url.Values, authParameters authority.AuthPar
scopes := AppendDefaultScopes(authParameters)
queryParams.Set("scope", strings.Join(scopes, " "))
}
+
+// addExtraBodyParameters evaluates and adds extra body parameters to the request
+func addExtraBodyParameters(ctx context.Context, v url.Values, ap authority.AuthParams) {
+ for key, value := range ap.ExtraBodyParameters {
+ if value != "" {
+ v.Set(key, value)
+ }
+ }
+}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
index 3f4037464..debd465db 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority/authority.go
@@ -15,6 +15,7 @@ import (
"net/url"
"os"
"path"
+ "sort"
"strings"
"time"
@@ -47,6 +48,8 @@ type jsonCaller interface {
}
// For backward compatibility, accept both old and new China endpoints for a transition period.
+// This list is derived from the AAD instance discovery metadata and represents all known trusted hosts
+// across different Azure clouds (Public, China, Germany, US Government, etc.)
var aadTrustedHostList = map[string]bool{
"login.windows.net": true, // Microsoft Azure Worldwide - Used in validation scenarios where host is not this list
"login.partner.microsoftonline.cn": true, // Microsoft Azure China (new)
@@ -55,6 +58,9 @@ var aadTrustedHostList = map[string]bool{
"login-us.microsoftonline.com": true, // Microsoft Azure US Government - Legacy
"login.microsoftonline.us": true, // Microsoft Azure US Government
"login.microsoftonline.com": true, // Microsoft Azure Worldwide
+ "login.microsoft.com": true,
+ "sts.windows.net": true,
+ "login.usgovcloudapi.net": true,
}
// TrustedHost checks if an AAD host is trusted/valid.
@@ -103,36 +109,46 @@ func (r *TenantDiscoveryResponse) Validate() error {
// ValidateIssuerMatchesAuthority validates that the issuer in the TenantDiscoveryResponse matches the authority.
// This is used to identity security or configuration issues in authorities and the OIDC endpoint
func (r *TenantDiscoveryResponse) ValidateIssuerMatchesAuthority(authorityURI string, aliases map[string]bool) error {
-
if authorityURI == "" {
return errors.New("TenantDiscoveryResponse: empty authorityURI provided for validation")
}
+ if r.Issuer == "" {
+ return errors.New("TenantDiscoveryResponse: empty issuer in response")
+ }
- // Parse the issuer URL
issuerURL, err := url.Parse(r.Issuer)
if err != nil {
return fmt.Errorf("TenantDiscoveryResponse: failed to parse issuer URL: %w", err)
}
+ authorityURL, err := url.Parse(authorityURI)
+ if err != nil {
+ return fmt.Errorf("TenantDiscoveryResponse: failed to parse authority URL: %w", err)
+ }
+
+ // Fast path: exact scheme + host match
+ if issuerURL.Scheme == authorityURL.Scheme && issuerURL.Host == authorityURL.Host {
+ return nil
+ }
- // Even if it doesn't match the authority, issuers from known and trusted hosts are valid
+ // Alias-based acceptance
if aliases != nil && aliases[issuerURL.Host] {
return nil
}
- // Parse the authority URL for comparison
- authorityURL, err := url.Parse(authorityURI)
- if err != nil {
- return fmt.Errorf("TenantDiscoveryResponse: failed to parse authority URL: %w", err)
+ issuerHost := issuerURL.Host
+ authorityHost := authorityURL.Host
+
+ // Accept if issuer host is trusted
+ if TrustedHost(issuerHost) {
+ return nil
}
- // Check if the scheme and host match (paths can be ignored when validating the issuer)
- if issuerURL.Scheme == authorityURL.Scheme && issuerURL.Host == authorityURL.Host {
+ // Accept if authority is a regional variant ending with "."
+ if strings.HasSuffix(authorityHost, "."+issuerHost) {
return nil
}
- // If we get here, validation failed
- return fmt.Errorf("TenantDiscoveryResponse: issuer from OIDC discovery '%s' does not match authority '%s' or a known pattern",
- r.Issuer, authorityURI)
+ return fmt.Errorf("TenantDiscoveryResponse: issuer '%s' does not match authority '%s' or any trusted/alias rule", r.Issuer, authorityURI)
}
type InstanceDiscoveryMetadata struct {
@@ -256,6 +272,12 @@ type AuthParams struct {
DomainHint string
// AuthnScheme is an optional scheme for formatting access tokens
AuthnScheme AuthenticationScheme
+ // ExtraBodyParameters are additional parameters to include in token requests.
+ // The functions are evaluated at request time to get the parameter values.
+ // These parameters are also included in the cache key.
+ ExtraBodyParameters map[string]string
+ // CacheKeyComponents are additional components to include in the cache key.
+ CacheKeyComponents map[string]string
}
// NewAuthParams creates an authorization parameters object.
@@ -642,8 +664,42 @@ func (a *AuthParams) AssertionHash() string {
}
func (a *AuthParams) AppKey() string {
+ baseKey := a.ClientID + "_"
if a.AuthorityInfo.Tenant != "" {
- return fmt.Sprintf("%s_%s_AppTokenCache", a.ClientID, a.AuthorityInfo.Tenant)
+ baseKey += a.AuthorityInfo.Tenant
+ }
+
+ // Include extra body parameters in the cache key
+ paramHash := a.CacheExtKeyGenerator()
+ if paramHash != "" {
+ baseKey = fmt.Sprintf("%s_%s", baseKey, paramHash)
+ }
+
+ return baseKey + "_AppTokenCache"
+}
+
+// CacheExtKeyGenerator computes a hash of the Cache key components key and values
+// to include in the cache key. This ensures tokens acquired with different
+// parameters are cached separately.
+func (a *AuthParams) CacheExtKeyGenerator() string {
+ if len(a.CacheKeyComponents) == 0 {
+ return ""
+ }
+
+ // Sort keys to ensure consistent hashing
+ keys := make([]string, 0, len(a.CacheKeyComponents))
+ for k := range a.CacheKeyComponents {
+ keys = append(keys, k)
}
- return fmt.Sprintf("%s__AppTokenCache", a.ClientID)
+ sort.Strings(keys)
+
+ // Create a string by concatenating key+value pairs
+ keyStr := ""
+ for _, key := range keys {
+ // Append key followed by its value with no separator
+ keyStr += key + a.CacheKeyComponents[key]
+ }
+
+ hash := sha256.Sum256([]byte(keyStr))
+ return strings.ToLower(base64.RawURLEncoding.EncodeToString(hash[:]))
}
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
index 7beed2617..797c086cb 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
@@ -368,9 +368,9 @@ type AcquireByUsernamePasswordOption interface {
acquireByUsernamePasswordOption()
}
-// AcquireTokenByUsernamePassword acquires a security token from the authority, via Username/Password Authentication.
-// NOTE: this flow is NOT recommended.
+// Deprecated: This API will be removed in a future release. Use a more secure flow instead. Follow this migration guide: https://aka.ms/msal-ropc-migration
//
+// AcquireTokenByUsernamePassword acquires a security token from the authority, via Username/Password Authentication.
// Options: [WithClaims], [WithTenantID]
func (pca Client) AcquireTokenByUsernamePassword(ctx context.Context, scopes []string, username, password string, opts ...AcquireByUsernamePasswordOption) (AuthResult, error) {
o := acquireTokenByUsernamePasswordOptions{}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c7dacf05c..515c05929 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -10,7 +10,7 @@ dario.cat/mergo
# github.com/42wim/httpsig v1.2.3
## explicit; go 1.23.0
github.com/42wim/httpsig
-# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1
+# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0
## explicit; go 1.23.0
github.com/Azure/azure-sdk-for-go/sdk/azcore
github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource
@@ -31,7 +31,7 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore/policy
github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime
github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming
github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing
-# github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0
+# github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
## explicit; go 1.23.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity
github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal
@@ -48,7 +48,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal/uuid
## explicit; go 1.16
github.com/Azure/go-ansiterm
github.com/Azure/go-ansiterm/winterm
-# github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0
+# github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0
## explicit; go 1.18
github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache
github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential