diff --git a/internal/concierge/impersonator/impersonator.go b/internal/concierge/impersonator/impersonator.go index 710df348..2bd01574 100644 --- a/internal/concierge/impersonator/impersonator.go +++ b/internal/concierge/impersonator/impersonator.go @@ -88,6 +88,12 @@ func (p *proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { "method", r.Method, ) + if err := ensureNoImpersonationHeaders(r); err != nil { + log.Error(err, "impersonation header already exists") + http.Error(w, "impersonation header already exists", http.StatusBadRequest) + return + } + tokenCredentialReq, err := extractToken(r, p.jsonDecoder) if err != nil { log.Error(err, "invalid token encoding") @@ -120,6 +126,24 @@ func (p *proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { p.proxy.ServeHTTP(w, newR) } +func ensureNoImpersonationHeaders(r *http.Request) error { + if _, ok := r.Header[transport.ImpersonateUserHeader]; ok { + return fmt.Errorf("%q header already exists", transport.ImpersonateUserHeader) + } + + if _, ok := r.Header[transport.ImpersonateGroupHeader]; ok { + return fmt.Errorf("%q header already exists", transport.ImpersonateGroupHeader) + } + + for header := range r.Header { + if strings.HasPrefix(header, transport.ImpersonateUserExtraHeaderPrefix) { + return fmt.Errorf("%q header already exists", transport.ImpersonateUserExtraHeaderPrefix) + } + } + + return nil +} + func getProxyHeaders(userInfo user.Info, requestHeaders http.Header) http.Header { newHeaders := http.Header{} newHeaders.Set("Impersonate-User", userInfo.GetName()) diff --git a/internal/concierge/impersonator/impersonator_test.go b/internal/concierge/impersonator/impersonator_test.go index 94a46f28..e993538c 100644 --- a/internal/concierge/impersonator/impersonator_test.go +++ b/internal/concierge/impersonator/impersonator_test.go @@ -127,6 +127,30 @@ func TestImpersonator(t *testing.T) { }, wantCreationErr: "could not get in-cluster transport: using a custom transport with TLS certificate options or the insecure flag is not allowed", }, + { + name: "Impersonate-User header already in request", + getKubeconfig: func() (*rest.Config, error) { return &testServerKubeconfig, nil }, + request: newRequest(map[string][]string{"Impersonate-User": {"some-user"}}), + wantHTTPBody: "impersonation header already exists\n", + wantHTTPStatus: http.StatusBadRequest, + wantLogs: []string{"\"error\"=\"\\\"Impersonate-User\\\" header already exists\" \"msg\"=\"impersonation header already exists\" \"method\"=\"GET\" \"url\"=\"http://pinniped.dev/blah\""}, + }, + { + name: "Impersonate-Group header already in request", + getKubeconfig: func() (*rest.Config, error) { return &testServerKubeconfig, nil }, + request: newRequest(map[string][]string{"Impersonate-Group": {"some-group"}}), + wantHTTPBody: "impersonation header already exists\n", + wantHTTPStatus: http.StatusBadRequest, + wantLogs: []string{"\"error\"=\"\\\"Impersonate-Group\\\" header already exists\" \"msg\"=\"impersonation header already exists\" \"method\"=\"GET\" \"url\"=\"http://pinniped.dev/blah\""}, + }, + { + name: "Impersonate-Extra header already in request", + getKubeconfig: func() (*rest.Config, error) { return &testServerKubeconfig, nil }, + request: newRequest(map[string][]string{"Impersonate-Extra-something": {"something"}}), + wantHTTPBody: "impersonation header already exists\n", + wantHTTPStatus: http.StatusBadRequest, + wantLogs: []string{"\"error\"=\"\\\"Impersonate-Extra-\\\" header already exists\" \"msg\"=\"impersonation header already exists\" \"method\"=\"GET\" \"url\"=\"http://pinniped.dev/blah\""}, + }, { name: "missing authorization header", getKubeconfig: func() (*rest.Config, error) { return &testServerKubeconfig, nil },