Use simpler prefix matching for impersonation headers.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
Matt Moyer 2021-03-08 14:36:29 -06:00
parent 6efbd81f75
commit 8fd6a71312
No known key found for this signature in database
GPG Key ID: EAE88AD172C5AE2D

View File

@ -10,7 +10,6 @@ import (
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"net/url" "net/url"
"regexp"
"strings" "strings"
"time" "time"
@ -28,8 +27,6 @@ import (
"go.pinniped.dev/internal/kubeclient" "go.pinniped.dev/internal/kubeclient"
) )
var impersonateHeaderRegex = regexp.MustCompile("Impersonate-.*")
type proxy struct { type proxy struct {
cache *authncache.Cache cache *authncache.Cache
jsonDecoder runtime.Decoder jsonDecoder runtime.Decoder
@ -150,11 +147,10 @@ func (e *httpError) Error() string { return e.message }
func ensureNoImpersonationHeaders(r *http.Request) error { func ensureNoImpersonationHeaders(r *http.Request) error {
for key := range r.Header { for key := range r.Header {
if impersonateHeaderRegex.MatchString(key) { if isImpersonationHeader(key) {
return fmt.Errorf("%q header already exists", key) return fmt.Errorf("%q header already exists", key)
} }
} }
return nil return nil
} }
@ -163,7 +159,9 @@ type roundTripperFunc func(*http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) } func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }
func getProxyHeaders(userInfo user.Info, requestHeaders http.Header) http.Header { func getProxyHeaders(userInfo user.Info, requestHeaders http.Header) http.Header {
newHeaders := http.Header{} // Copy over all headers except the Authorization header from the original request to the new request.
newHeaders := requestHeaders.Clone()
newHeaders.Del("Authorization")
// Leverage client-go's impersonation RoundTripper to set impersonation headers for us in the new // Leverage client-go's impersonation RoundTripper to set impersonation headers for us in the new
// request. The client-go RoundTripper not only sets all of the impersonation headers for us, but // request. The client-go RoundTripper not only sets all of the impersonation headers for us, but
@ -176,12 +174,8 @@ func getProxyHeaders(userInfo user.Info, requestHeaders http.Header) http.Header
Extra: userInfo.GetExtra(), Extra: userInfo.GetExtra(),
} }
impersonateHeaderSpy := roundTripperFunc(func(r *http.Request) (*http.Response, error) { impersonateHeaderSpy := roundTripperFunc(func(r *http.Request) (*http.Response, error) {
newHeaders.Set(transport.ImpersonateUserHeader, r.Header.Get(transport.ImpersonateUserHeader))
for _, groupHeaderValue := range r.Header.Values(transport.ImpersonateGroupHeader) {
newHeaders.Add(transport.ImpersonateGroupHeader, groupHeaderValue)
}
for headerKey, headerValues := range r.Header { for headerKey, headerValues := range r.Header {
if strings.HasPrefix(headerKey, transport.ImpersonateUserExtraHeaderPrefix) { if isImpersonationHeader(headerKey) {
for _, headerValue := range headerValues { for _, headerValue := range headerValues {
newHeaders.Add(headerKey, headerValue) newHeaders.Add(headerKey, headerValue)
} }
@ -192,19 +186,13 @@ func getProxyHeaders(userInfo user.Info, requestHeaders http.Header) http.Header
fakeReq, _ := http.NewRequestWithContext(context.Background(), "", "", nil) fakeReq, _ := http.NewRequestWithContext(context.Background(), "", "", nil)
//nolint:bodyclose // We return a nil http.Response above, so there is nothing to close. //nolint:bodyclose // We return a nil http.Response above, so there is nothing to close.
_, _ = transport.NewImpersonatingRoundTripper(impersonateConfig, impersonateHeaderSpy).RoundTrip(fakeReq) _, _ = transport.NewImpersonatingRoundTripper(impersonateConfig, impersonateHeaderSpy).RoundTrip(fakeReq)
// Copy over all headers except the Authorization header from the original request to the new request.
for key := range requestHeaders {
if key != "Authorization" {
for _, val := range requestHeaders.Values(key) {
newHeaders.Add(key, val)
}
}
}
return newHeaders return newHeaders
} }
func isImpersonationHeader(header string) bool {
return strings.HasPrefix(http.CanonicalHeaderKey(header), "Impersonate")
}
func extractToken(token string, jsonDecoder runtime.Decoder) (*login.TokenCredentialRequest, error) { func extractToken(token string, jsonDecoder runtime.Decoder) (*login.TokenCredentialRequest, error) {
tokenCredentialRequestJSON, err := base64.StdEncoding.DecodeString(token) tokenCredentialRequestJSON, err := base64.StdEncoding.DecodeString(token)
if err != nil { if err != nil {