From 6ef93123325649417f185de10dccf6ae0c07c1f6 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 31 Jan 2018 16:42:18 -0500 Subject: [PATCH] Use the Upstream header for scope impersonation Note: the upstream function does not forcibliy remove potential existing impersonation headers, and it also uses the existing ones ignoring any new headers we may be setting. This i ok, because we do not depend nor probably want to allow multiple levels of impersonation. Signed-off-by: Simo Sorce --- pkg/client/impersonatingclient/impersonate.go | 51 +++++-------------- pkg/cmd/server/origin/handlers.go | 8 ++- test/integration/scopes_test.go | 11 ++-- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/pkg/client/impersonatingclient/impersonate.go b/pkg/client/impersonatingclient/impersonate.go index ffc83c012980..7b558b34da16 100644 --- a/pkg/client/impersonatingclient/impersonate.go +++ b/pkg/client/impersonatingclient/impersonate.go @@ -5,52 +5,23 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authentication/user" restclient "k8s.io/client-go/rest" + "k8s.io/client-go/transport" "k8s.io/client-go/util/flowcontrol" kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" -) - -const ( - ImpersonateUserHeader = "Impersonate-User" - ImpersonateGroupHeader = "Impersonate-Group" - ImpersonateUserScopeHeader = "Impersonate-User-Scope" ) -type impersonatingRoundTripper struct { - user user.Info - delegate http.RoundTripper -} - -// newImpersonatingRoundTripper will add headers to impersonate a user, including user, groups, and scopes -func newImpersonatingRoundTripper(user user.Info, delegate http.RoundTripper) http.RoundTripper { - return &impersonatingRoundTripper{user: user, delegate: delegate} -} - -func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - req = utilnet.CloneRequest(req) - req.Header.Del(ImpersonateUserHeader) - req.Header.Del(ImpersonateGroupHeader) - req.Header.Del(ImpersonateUserScopeHeader) - - req.Header.Set(ImpersonateUserHeader, rt.user.GetName()) - for _, group := range rt.user.GetGroups() { - req.Header.Add(ImpersonateGroupHeader, group) - } - for _, scope := range rt.user.GetExtra()[authorizationapi.ScopesKey] { - req.Header.Add(ImpersonateUserScopeHeader, scope) - } - return rt.delegate.RoundTrip(req) -} - // NewImpersonatingConfig wraps the config's transport to impersonate a user, including user, groups, and scopes func NewImpersonatingConfig(user user.Info, config restclient.Config) restclient.Config { oldWrapTransport := config.WrapTransport config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { - return newImpersonatingRoundTripper(user, oldWrapTransport(rt)) + newConfig := transport.ImpersonationConfig{ + UserName: user.GetName(), + Groups: user.GetGroups(), + Extra: user.GetExtra(), + } + return transport.NewImpersonatingRoundTripper(newConfig, oldWrapTransport(rt)) } return config } @@ -73,9 +44,11 @@ func NewImpersonatingRESTClient(user user.Info, client restclient.Interface) res // Verb does the impersonation per request by setting the proper headers func (c impersonatingRESTClient) impersonate(req *restclient.Request) *restclient.Request { - req.SetHeader(ImpersonateUserHeader, c.user.GetName()) - req.SetHeader(ImpersonateGroupHeader, c.user.GetGroups()...) - req.SetHeader(ImpersonateUserScopeHeader, c.user.GetExtra()[authorizationapi.ScopesKey]...) + req.SetHeader(transport.ImpersonateUserHeader, c.user.GetName()) + req.SetHeader(transport.ImpersonateGroupHeader, c.user.GetGroups()...) + for k, vv := range c.user.GetExtra() { + req.SetHeader(transport.ImpersonateUserExtraHeaderPrefix+k, vv...) + } return req } diff --git a/pkg/cmd/server/origin/handlers.go b/pkg/cmd/server/origin/handlers.go index 3631eb430f48..238a2323af0e 100644 --- a/pkg/cmd/server/origin/handlers.go +++ b/pkg/cmd/server/origin/handlers.go @@ -23,7 +23,6 @@ import ( coreapi "k8s.io/kubernetes/pkg/apis/core" authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - "github.com/openshift/origin/pkg/client/impersonatingclient" configapi "github.com/openshift/origin/pkg/cmd/server/api" ) @@ -155,10 +154,15 @@ func (c *MasterConfig) versionSkewFilter(handler http.Handler, contextMapper api }) } +// legacyImpersonateUserScopeHeader is the header name older servers were using +// just for scopes, so we need to translate it from clients that may still be +// using it. +const legacyImpersonateUserScopeHeader = "Impersonate-User-Scope" + // translateLegacyScopeImpersonation is a filter that will translates user scope impersonation for openshift into the equivalent kube headers. func translateLegacyScopeImpersonation(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - for _, scope := range req.Header[impersonatingclient.ImpersonateUserScopeHeader] { + for _, scope := range req.Header[legacyImpersonateUserScopeHeader] { req.Header[authenticationv1.ImpersonateUserExtraHeaderPrefix+authorizationapi.ScopesKey] = append(req.Header[authenticationv1.ImpersonateUserExtraHeaderPrefix+authorizationapi.ScopesKey], scope) } diff --git a/test/integration/scopes_test.go b/test/integration/scopes_test.go index 21c5da3b37fb..26ca902dfb1a 100644 --- a/test/integration/scopes_test.go +++ b/test/integration/scopes_test.go @@ -3,16 +3,17 @@ package integration import ( "testing" + authenticationv1 "k8s.io/api/authentication/v1" kapierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount" "k8s.io/client-go/rest" kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" "github.com/openshift/origin/pkg/authorization/authorizer/scope" buildapi "github.com/openshift/origin/pkg/build/apis/build" buildclient "github.com/openshift/origin/pkg/build/generated/internalclientset" - "github.com/openshift/origin/pkg/client/impersonatingclient" oauthapi "github.com/openshift/origin/pkg/oauth/apis/oauth" oauthclient "github.com/openshift/origin/pkg/oauth/generated/internalclientset/typed/oauth/internalversion" "github.com/openshift/origin/pkg/oauthserver/oauthserver" @@ -105,8 +106,8 @@ func TestScopedImpersonation(t *testing.T) { } err = clusterAdminBuildClient.Build().RESTClient().Get(). - SetHeader(impersonatingclient.ImpersonateUserHeader, "harold"). - SetHeader(impersonatingclient.ImpersonateUserScopeHeader, "user:info"). + SetHeader(authenticationv1.ImpersonateUserHeader, "harold"). + SetHeader(authenticationv1.ImpersonateUserExtraHeaderPrefix+authorizationapi.ScopesKey, "user:info"). Namespace(projectName).Resource("builds").Name("name").Do().Into(&buildapi.Build{}) if !kapierrors.IsForbidden(err) { t.Fatalf("unexpected error: %v", err) @@ -114,8 +115,8 @@ func TestScopedImpersonation(t *testing.T) { user := &userapi.User{} err = userclient.NewForConfigOrDie(clusterAdminClientConfig).RESTClient().Get(). - SetHeader(impersonatingclient.ImpersonateUserHeader, "harold"). - SetHeader(impersonatingclient.ImpersonateUserScopeHeader, "user:info"). + SetHeader(authenticationv1.ImpersonateUserHeader, "harold"). + SetHeader(authenticationv1.ImpersonateUserExtraHeaderPrefix+authorizationapi.ScopesKey, "user:info"). Resource("users").Name("~").Do().Into(user) if err != nil { t.Fatalf("unexpected error: %v", err)