mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
add auth proxy roundtripper
This commit is contained in:
parent
be5d1724f5
commit
61b5585bac
@ -19,6 +19,7 @@ package transport
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
@ -76,6 +77,66 @@ type requestCanceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
|
||||
type authProxyRoundTripper struct {
|
||||
username string
|
||||
groups []string
|
||||
extra map[string][]string
|
||||
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
// NewAuthProxyRoundTripper provides a roundtripper which will add auth proxy fields to requests for
|
||||
// authentication terminating proxy cases
|
||||
// assuming you pull the user from the context:
|
||||
// username is the user.Info.GetName() of the user
|
||||
// groups is the user.Info.GetGroups() of the user
|
||||
// extra is the user.Info.GetExtra() of the user
|
||||
// extra can contain any additional information that the authenticator
|
||||
// thought was interesting, for example authorization scopes.
|
||||
// In order to faithfully round-trip through an impersonation flow, these keys
|
||||
// MUST be lowercase.
|
||||
func NewAuthProxyRoundTripper(username string, groups []string, extra map[string][]string, rt http.RoundTripper) http.RoundTripper {
|
||||
return &authProxyRoundTripper{
|
||||
username: username,
|
||||
groups: groups,
|
||||
extra: extra,
|
||||
rt: rt,
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *authProxyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = cloneRequest(req)
|
||||
req.Header.Del("X-Remote-User")
|
||||
req.Header.Del("X-Remote-Group")
|
||||
for key := range req.Header {
|
||||
if strings.HasPrefix(strings.ToLower(key), strings.ToLower("X-Remote-Extra-")) {
|
||||
req.Header.Del(key)
|
||||
}
|
||||
}
|
||||
|
||||
req.Header.Set("X-Remote-User", rt.username)
|
||||
for _, group := range rt.groups {
|
||||
req.Header.Add("X-Remote-Group", group)
|
||||
}
|
||||
for key, values := range rt.extra {
|
||||
for _, value := range values {
|
||||
req.Header.Add("X-Remote-Extra-"+key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return rt.rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *authProxyRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.rt.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *authProxyRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
type userAgentRoundTripper struct {
|
||||
agent string
|
||||
rt http.RoundTripper
|
||||
|
@ -19,6 +19,7 @@ package transport
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -155,3 +156,63 @@ func TestImpersonationRoundTripper(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthProxyRoundTripper(t *testing.T) {
|
||||
for n, tc := range map[string]struct {
|
||||
username string
|
||||
groups []string
|
||||
extra map[string][]string
|
||||
}{
|
||||
"allfields": {
|
||||
username: "user",
|
||||
groups: []string{"groupA", "groupB"},
|
||||
extra: map[string][]string{
|
||||
"one": {"alpha", "bravo"},
|
||||
"two": {"charlie", "delta"},
|
||||
},
|
||||
},
|
||||
} {
|
||||
rt := &testRoundTripper{}
|
||||
req := &http.Request{}
|
||||
NewAuthProxyRoundTripper(tc.username, tc.groups, tc.extra, rt).RoundTrip(req)
|
||||
if rt.Request == nil {
|
||||
t.Errorf("%s: unexpected nil request: %v", n, rt)
|
||||
continue
|
||||
}
|
||||
if rt.Request == req {
|
||||
t.Errorf("%s: round tripper should have copied request object: %#v", n, rt.Request)
|
||||
continue
|
||||
}
|
||||
|
||||
actualUsernames, ok := rt.Request.Header["X-Remote-User"]
|
||||
if !ok {
|
||||
t.Errorf("%s missing value", n)
|
||||
continue
|
||||
}
|
||||
if e, a := []string{tc.username}, actualUsernames; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s expected %v, got %v", n, e, a)
|
||||
continue
|
||||
}
|
||||
actualGroups, ok := rt.Request.Header["X-Remote-Group"]
|
||||
if !ok {
|
||||
t.Errorf("%s missing value", n)
|
||||
continue
|
||||
}
|
||||
if e, a := tc.groups, actualGroups; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s expected %v, got %v", n, e, a)
|
||||
continue
|
||||
}
|
||||
|
||||
actualExtra := map[string][]string{}
|
||||
for key, values := range rt.Request.Header {
|
||||
if strings.HasPrefix(strings.ToLower(key), strings.ToLower("X-Remote-Extra-")) {
|
||||
extraKey := strings.ToLower(key[len("X-Remote-Extra-"):])
|
||||
actualExtra[extraKey] = append(actualExtra[key], values...)
|
||||
}
|
||||
}
|
||||
if e, a := tc.extra, actualExtra; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s expected %v, got %v", n, e, a)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user