Skip to content

Commit

Permalink
Use the Upstream header for scope impersonation
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
simo5 committed Feb 2, 2018
1 parent 413056b commit 6ef9312
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 46 deletions.
51 changes: 12 additions & 39 deletions pkg/client/impersonatingclient/impersonate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}

Expand Down
8 changes: 6 additions & 2 deletions pkg/cmd/server/origin/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
}
Expand Down
11 changes: 6 additions & 5 deletions test/integration/scopes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -105,17 +106,17 @@ 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)
}

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)
Expand Down

0 comments on commit 6ef9312

Please sign in to comment.