pkg/dataplane/authenticator.go (63 lines of code) (raw):
package dataplane
import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"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/azcore/runtime"
"github.com/Azure/msi-dataplane/pkg/dataplane/internal/challenge"
)
var (
errInvalidAuthHeader = errors.New("could not parse the provided WWW-Authenticate header")
)
// Authenticating with MSI: https://eng.ms/docs/products/arm/rbac/managed_identities/msionboardinginteractionwithmsi .
func newAuthenticatorPolicy(cred azcore.TokenCredential, audience string) policy.Policy {
return runtime.NewBearerTokenPolicy(cred, nil, &policy.BearerTokenOptions{
AuthorizationHandler: policy.AuthorizationHandler{
// Make an unauthenticated request
OnRequest: func(*policy.Request, func(policy.TokenRequestOptions) error) error {
return nil
},
// Inspect WWW-Authenticate header returned from challenge
OnChallenge: func(req *policy.Request, resp *http.Response, authenticateAndAuthorize func(policy.TokenRequestOptions) error) error {
// we expect 'Bearer authorization="https://login.windows-ppe.net/5D929AE3-B37C-46AA-A3C8-C1558902F101"'
authParam, err := parseChallengeHeader(resp.Header)
if err != nil {
return err
}
u, err := url.Parse(authParam)
if err != nil {
return fmt.Errorf("%w: %w", errInvalidAuthHeader, err)
}
tenantID := strings.ToLower(strings.Trim(u.Path, "/"))
req.Raw().Context()
// Note: "In api versions prior to 2023-09-30, the audience is included in the bearer challenge, but we recommend that partners
// rely on hard-configuring the explicit values above for security reasons."
// Authenticate from tenantID and audience
return authenticateAndAuthorize(policy.TokenRequestOptions{
Scopes: []string{audience + "/.default"},
TenantID: tenantID,
})
},
},
})
}
func parseChallengeHeader(headers http.Header) (string, error) {
challenges, err := challenge.Parse(headers)
if err != nil {
return "", fmt.Errorf("%w: %w", errInvalidAuthHeader, err)
}
if len(challenges) == 0 {
return "", fmt.Errorf("%w: %s", errInvalidAuthHeader, "no challenges found")
}
var bearer *challenge.Challenge
for _, c := range challenges {
if c.Scheme == "Bearer" {
bearer = &c
}
}
if bearer == nil {
return "", fmt.Errorf("%w: %s", errInvalidAuthHeader, "no bearer challenge found")
}
authParam, provided := bearer.Parameters["authorization"]
if !provided {
return "", fmt.Errorf("%w: %s", errInvalidAuthHeader, "no authorization parameter in bearer challenge")
}
return authParam, nil
}