Commit bbcf0616 authored by deads2k's avatar deads2k

run update staging

parent ef19bf84
{
"ImportPath": "k8s.io/client-go",
"GoVersion": "go1.7",
"GodepVersion": "v75",
"GodepVersion": "v74",
"Packages": [
"./..."
],
......@@ -183,7 +183,7 @@
},
{
"ImportPath": "github.com/spf13/pflag",
"Rev": "5ccb023bc27df288a957c5e994cd44fd19619465"
"Rev": "c7e63cf4530bcd3ba943729cee0efeff2ebea63f"
},
{
"ImportPath": "github.com/stretchr/testify/assert",
......
# This is the official list of cloud authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as:
# Name or Organization <email address>
# The email address is not required for organizations.
Filippo Valsorda <hi@filippo.io>
Google Inc.
Ingo Oeser <nightlyone@googlemail.com>
Palm Stone Games, Inc.
Paweł Knap <pawelknap88@gmail.com>
Péter Szilágyi <peterke@gmail.com>
Tyler Treat <ttreat31@gmail.com>
# People who have agreed to one of the CLAs and can contribute patches.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# https://developers.google.com/open-source/cla/individual
# https://developers.google.com/open-source/cla/corporate
#
# Names should be added to this file as:
# Name <email address>
# Keep the list alphabetically sorted.
Andreas Litt <andreas.litt@gmail.com>
Andrew Gerrand <adg@golang.org>
Brad Fitzpatrick <bradfitz@golang.org>
Burcu Dogan <jbd@google.com>
Dave Day <djd@golang.org>
David Sansome <me@davidsansome.com>
David Symonds <dsymonds@golang.org>
Filippo Valsorda <hi@filippo.io>
Glenn Lewis <gmlewis@google.com>
Ingo Oeser <nightlyone@googlemail.com>
Johan Euphrosine <proppy@google.com>
Jonathan Amsterdam <jba@google.com>
Luna Duclos <luna.duclos@palmstonegames.com>
Michael McGreevy <mcgreevy@golang.org>
Omar Jarjur <ojarjur@google.com>
Paweł Knap <pawelknap88@gmail.com>
Péter Szilágyi <peterke@gmail.com>
Sarah Adams <shadams@google.com>
Toby Burress <kurin@google.com>
Tuo Shan <shantuo@google.com>
Tyler Treat <ttreat31@gmail.com>
Aaron Lehmann <aaron.lehmann@docker.com>
Aaron Vinson <avinson.public@gmail.com>
Adam Enger <adamenger@gmail.com>
Adrian Mouat <adrian.mouat@gmail.com>
Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
Alex Chan <alex.chan@metaswitch.com>
Alex Elman <aelman@indeed.com>
amitshukla <ashukla73@hotmail.com>
Amy Lindburg <amy.lindburg@docker.com>
Andrew Meredith <andymeredith@gmail.com>
Andrew T Nguyen <andrew.nguyen@docker.com>
Andrey Kostov <kostov.andrey@gmail.com>
Andy Goldstein <agoldste@redhat.com>
Anton Tiurin <noxiouz@yandex.ru>
Antonio Mercado <amercado@thinknode.com>
Antonio Murdaca <runcom@redhat.com>
Arnaud Porterie <arnaud.porterie@docker.com>
Arthur Baars <arthur@semmle.com>
Asuka Suzuki <hello@tanksuzuki.com>
Avi Miller <avi.miller@oracle.com>
Ayose Cazorla <ayosec@gmail.com>
BadZen <dave.trombley@gmail.com>
Ben Firshman <ben@firshman.co.uk>
bin liu <liubin0329@gmail.com>
Brian Bland <brian.bland@docker.com>
burnettk <burnettk@gmail.com>
Carson A <ca@carsonoid.net>
Chris Dillon <squarism@gmail.com>
Daisuke Fujita <dtanshi45@gmail.com>
Darren Shepherd <darren@rancher.com>
Dave Trombley <dave.trombley@gmail.com>
Dave Tucker <dt@docker.com>
David Lawrence <david.lawrence@docker.com>
David Verhasselt <david@crowdway.com>
David Xia <dxia@spotify.com>
davidli <wenquan.li@hp.com>
Dejan Golja <dejan@golja.org>
Derek McGowan <derek@mcgstyle.net>
Diogo Mónica <diogo.monica@gmail.com>
DJ Enriquez <dj.enriquez@infospace.com>
Donald Huang <don.hcd@gmail.com>
Doug Davis <dug@us.ibm.com>
Eric Yang <windfarer@gmail.com>
farmerworking <farmerworking@gmail.com>
Felix Yan <felixonmars@archlinux.org>
Florentin Raud <florentin.raud@gmail.com>
Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
gabriell nascimento <gabriell@bluesoft.com.br>
harche <p.harshal@gmail.com>
Henri Gomez <henri.gomez@gmail.com>
Hu Keping <hukeping@huawei.com>
Hua Wang <wanghua.humble@gmail.com>
HuKeping <hukeping@huawei.com>
Ian Babrou <ibobrik@gmail.com>
igayoso <igayoso@gmail.com>
Jack Griffin <jackpg14@gmail.com>
Jason Freidman <jason.freidman@gmail.com>
Jeff Nickoloff <jeff@allingeek.com>
Jessie Frazelle <jessie@docker.com>
Jianqing Wang <tsing@jianqing.org>
John Starks <jostarks@microsoft.com>
Jon Poler <jonathan.poler@apcera.com>
Jonathan Boulle <jonathanboulle@gmail.com>
Jordan Liggitt <jliggitt@redhat.com>
Josh Hawn <josh.hawn@docker.com>
Julien Fernandez <julien.fernandez@gmail.com>
Keerthan Mala <kmala@engineyard.com>
Kelsey Hightower <kelsey.hightower@gmail.com>
Kenneth Lim <kennethlimcp@gmail.com>
Kenny Leung <kleung@google.com>
Li Yi <denverdino@gmail.com>
Liu Hua <sdu.liu@huawei.com>
liuchang0812 <liuchang0812@gmail.com>
Louis Kottmann <louis.kottmann@gmail.com>
Luke Carpenter <x@rubynerd.net>
Mary Anthony <mary@docker.com>
Matt Bentley <mbentley@mbentley.net>
Matt Duch <matt@learnmetrics.com>
Matt Moore <mattmoor@google.com>
Matt Robenolt <matt@ydekproductions.com>
Michael Prokop <mika@grml.org>
Michal Minar <miminar@redhat.com>
Miquel Sabaté <msabate@suse.com>
Morgan Bauer <mbauer@us.ibm.com>
moxiegirl <mary@docker.com>
Nathan Sullivan <nathan@nightsys.net>
nevermosby <robolwq@qq.com>
Nghia Tran <tcnghia@gmail.com>
Nuutti Kotivuori <nuutti.kotivuori@poplatek.fi>
Oilbeater <liumengxinfly@gmail.com>
Olivier Gambier <olivier@docker.com>
Olivier Jacques <olivier.jacques@hp.com>
Omer Cohen <git@omer.io>
Patrick Devine <patrick.devine@docker.com>
Philip Misiowiec <philip@atlashealth.com>
Richard Scothern <richard.scothern@docker.com>
Rodolfo Carvalho <rhcarvalho@gmail.com>
Rusty Conover <rusty@luckydinosaur.com>
Sean Boran <Boran@users.noreply.github.com>
Sebastiaan van Stijn <github@gone.nl>
Sharif Nassar <sharif@mrwacky.com>
Shawn Falkner-Horine <dreadpirateshawn@gmail.com>
Shreyas Karnik <karnik.shreyas@gmail.com>
Simon Thulbourn <simon+github@thulbourn.com>
Spencer Rinehart <anubis@overthemonkey.com>
Stefan Weil <sw@weilnetz.de>
Stephen J Day <stephen.day@docker.com>
Sungho Moon <sungho.moon@navercorp.com>
Sven Dowideit <SvenDowideit@home.org.au>
Sylvain Baubeau <sbaubeau@redhat.com>
Ted Reed <ted.reed@gmail.com>
tgic <farmer1992@gmail.com>
Thomas Sjögren <konstruktoid@users.noreply.github.com>
Tianon Gravi <admwiggin@gmail.com>
Tibor Vass <teabee89@gmail.com>
Tonis Tiigi <tonistiigi@gmail.com>
Trevor Pounds <trevor.pounds@gmail.com>
Troels Thomsen <troels@thomsen.io>
Vincent Batts <vbatts@redhat.com>
Vincent Demeester <vincent@sbr.pm>
Vincent Giersch <vincent.giersch@ovh.net>
W. Trevor King <wking@tremily.us>
weiyuan.yl <weiyuan.yl@alibaba-inc.com>
xg.song <xg.song@venusource.com>
xiekeyang <xiekeyang@huawei.com>
Yann ROBERT <yann.robert@anantaplex.fr>
yuzou <zouyu7@huawei.com>
姜继忠 <jizhong.jiangjz@alibaba-inc.com>
Anton Povarov <anton.povarov@gmail.com>
Clayton Coleman <ccoleman@redhat.com>
Denis Smirnov <denis.smirnov.91@gmail.com>
DongYun Kang <ceram1000@gmail.com>
Dwayne Schultz <dschultz@pivotal.io>
Georg Apitz <gapitz@pivotal.io>
Gustav Paul <gustav.paul@gmail.com>
John Tuley <john@tuley.org>
Laurent <laurent@adyoulike.com>
Patrick Lee <patrick@dropbox.com>
Stephen J Day <stephen.day@docker.com>
Tamir Duberstein <tamird@gmail.com>
Todd Eisenberger <teisenberger@dropbox.com>
Tormod Erevik Lea <tormodlea@gmail.com>
Walter Schulze <awalterschulze@gmail.com>
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
......@@ -416,7 +416,7 @@ func Set(name, value string) error {
// otherwise, the default values of all defined flags in the set.
func (f *FlagSet) PrintDefaults() {
usages := f.FlagUsages()
fmt.Fprint(f.out(), usages)
fmt.Fprintf(f.out(), "%s", usages)
}
// defaultIsZeroValue returns true if the default value for this flag represents
......@@ -514,7 +514,7 @@ func (f *FlagSet) FlagUsages() string {
if len(flag.NoOptDefVal) > 0 {
switch flag.Value.Type() {
case "string":
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
line += fmt.Sprintf("[=%q]", flag.NoOptDefVal)
case "bool":
if flag.NoOptDefVal != "true" {
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
......@@ -534,7 +534,7 @@ func (f *FlagSet) FlagUsages() string {
line += usage
if !flag.defaultIsZeroValue() {
if flag.Value.Type() == "string" {
line += fmt.Sprintf(" (default \"%s\")", flag.DefValue)
line += fmt.Sprintf(" (default %q)", flag.DefValue)
} else {
line += fmt.Sprintf(" (default %s)", flag.DefValue)
}
......
......@@ -2,6 +2,7 @@ package pflag
import (
"fmt"
"strings"
)
var _ = fmt.Fprint
......@@ -39,7 +40,7 @@ func (s *stringArrayValue) String() string {
}
func stringArrayConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1]
sval = strings.Trim(sval, "[]")
// An empty string would cause a array with one (empty) string
if len(sval) == 0 {
return []string{}, nil
......
......@@ -66,7 +66,7 @@ func (s *stringSliceValue) String() string {
}
func stringSliceConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1]
sval = strings.Trim(sval, "[]")
// An empty string would cause a slice with one (empty) string
if len(sval) == 0 {
return []string{}, nil
......
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
......@@ -43,18 +43,26 @@ const (
dynamicKubeletConfig = "DynamicKubeletConfig"
dynamicVolumeProvisioning = "DynamicVolumeProvisioning"
streamingProxyRedirects = "StreamingProxyRedirects"
// experimentalHostUserNamespaceDefaulting Default userns=host for containers
// that are using other host namespaces, host mounts, the pod contains a privileged container,
// or specific non-namespaced capabilities
// (MKNOD, SYS_MODULE, SYS_TIME). This should only be enabled if user namespace remapping is enabled
// in the docker daemon.
experimentalHostUserNamespaceDefaultingGate = "ExperimentalHostUserNamespaceDefaulting"
)
var (
// Default values for recorded features. Every new feature gate should be
// represented here.
knownFeatures = map[string]featureSpec{
allAlphaGate: {false, alpha},
externalTrafficLocalOnly: {true, beta},
appArmor: {true, beta},
dynamicKubeletConfig: {false, alpha},
dynamicVolumeProvisioning: {true, alpha},
streamingProxyRedirects: {false, alpha},
allAlphaGate: {false, alpha},
externalTrafficLocalOnly: {true, beta},
appArmor: {true, beta},
dynamicKubeletConfig: {false, alpha},
dynamicVolumeProvisioning: {true, alpha},
streamingProxyRedirects: {false, alpha},
experimentalHostUserNamespaceDefaultingGate: {false, alpha},
}
// Special handling for a few gates.
......@@ -115,6 +123,10 @@ type FeatureGate interface {
// owner: timstclair
// alpha: v1.5
StreamingProxyRedirects() bool
// owner: @pweil-
// alpha: v1.5
ExperimentalHostUserNamespaceDefaulting() bool
}
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
......@@ -209,6 +221,11 @@ func (f *featureGate) StreamingProxyRedirects() bool {
return f.lookup(streamingProxyRedirects)
}
// ExperimentalHostUserNamespaceDefaulting returns value for experimentalHostUserNamespaceDefaulting
func (f *featureGate) ExperimentalHostUserNamespaceDefaulting() bool {
return f.lookup(experimentalHostUserNamespaceDefaultingGate)
}
func (f *featureGate) lookup(key string) bool {
defaultValue := f.known[key].enabled
if f.enabled != nil {
......
......@@ -23,6 +23,7 @@ import (
"net/http"
"os/exec"
"strings"
"sync"
"time"
"github.com/golang/glog"
......@@ -74,6 +75,7 @@ func (g *gcpAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper
func (g *gcpAuthProvider) Login() error { return nil }
type cachedTokenSource struct {
lk sync.Mutex
source oauth2.TokenSource
accessToken string
expiry time.Time
......@@ -99,11 +101,7 @@ func newCachedTokenSource(accessToken, expiry string, persister rest.AuthProvide
}
func (t *cachedTokenSource) Token() (*oauth2.Token, error) {
tok := &oauth2.Token{
AccessToken: t.accessToken,
TokenType: "Bearer",
Expiry: t.expiry,
}
tok := t.cachedToken()
if tok.Valid() && !tok.Expiry.IsZero() {
return tok, nil
}
......@@ -111,16 +109,39 @@ func (t *cachedTokenSource) Token() (*oauth2.Token, error) {
if err != nil {
return nil, err
}
cache := t.update(tok)
if t.persister != nil {
t.cache["access-token"] = tok.AccessToken
t.cache["expiry"] = tok.Expiry.Format(time.RFC3339Nano)
if err := t.persister.Persist(t.cache); err != nil {
if err := t.persister.Persist(cache); err != nil {
glog.V(4).Infof("Failed to persist token: %v", err)
}
}
return tok, nil
}
func (t *cachedTokenSource) cachedToken() *oauth2.Token {
t.lk.Lock()
defer t.lk.Unlock()
return &oauth2.Token{
AccessToken: t.accessToken,
TokenType: "Bearer",
Expiry: t.expiry,
}
}
func (t *cachedTokenSource) update(tok *oauth2.Token) map[string]string {
t.lk.Lock()
defer t.lk.Unlock()
t.accessToken = tok.AccessToken
t.expiry = tok.Expiry
ret := map[string]string{}
for k, v := range t.cache {
ret[k] = v
}
ret["access-token"] = t.accessToken
ret["expiry"] = t.expiry.Format(time.RFC3339Nano)
return ret
}
type commandTokenSource struct {
cmd string
args []string
......
......@@ -20,6 +20,7 @@ import (
"fmt"
"reflect"
"strings"
"sync"
"testing"
"time"
......@@ -141,3 +142,70 @@ func TestCmdTokenSource(t *testing.T) {
}
}
}
type fakePersister struct {
lk sync.Mutex
cache map[string]string
}
func (f *fakePersister) Persist(cache map[string]string) error {
f.lk.Lock()
defer f.lk.Unlock()
f.cache = map[string]string{}
for k, v := range cache {
f.cache[k] = v
}
return nil
}
func (f *fakePersister) read() map[string]string {
ret := map[string]string{}
f.lk.Lock()
for k, v := range f.cache {
ret[k] = v
}
return ret
}
type fakeTokenSource struct {
token *oauth2.Token
err error
}
func (f *fakeTokenSource) Token() (*oauth2.Token, error) {
return f.token, f.err
}
func TestCachedTokenSource(t *testing.T) {
tok := &oauth2.Token{AccessToken: "fakeaccesstoken"}
persister := &fakePersister{}
source := &fakeTokenSource{
token: tok,
err: nil,
}
cache := map[string]string{
"foo": "bar",
"baz": "bazinga",
}
ts, err := newCachedTokenSource("fakeaccesstoken", "", persister, source, cache)
if err != nil {
t.Fatal(err)
}
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
_, err := ts.Token()
if err != nil {
t.Errorf("unexpected error: %s", err)
}
wg.Done()
}()
}
wg.Wait()
cache["access-token"] = "fakeaccesstoken"
cache["expiry"] = tok.Expiry.Format(time.RFC3339Nano)
if got := persister.read(); !reflect.DeepEqual(got, cache) {
t.Errorf("got cache %v, want %v", got, cache)
}
}
......@@ -70,8 +70,8 @@ type Config struct {
// TODO: demonstrate an OAuth2 compatible client.
BearerToken string
// Impersonate is the username that this RESTClient will impersonate
Impersonate string
// Impersonate is the configuration that RESTClient will use for impersonation.
Impersonate ImpersonationConfig
// Server requires plugin-specified authentication.
AuthProvider *clientcmdapi.AuthProviderConfig
......@@ -118,6 +118,17 @@ type Config struct {
// Version string
}
// ImpersonationConfig has all the available impersonation options
type ImpersonationConfig struct {
// UserName is the username to impersonate on each request.
UserName string
// Groups are the groups to impersonate on each request.
Groups []string
// Extra is a free-form field which can be used to link some authentication information
// to authorization information. This field allows you to impersonate it.
Extra map[string][]string
}
// TLSClientConfig contains settings to enable transport layer security
type TLSClientConfig struct {
// Server requires TLS client certificate authentication
......
......@@ -205,7 +205,7 @@ func TestAnonymousConfig(t *testing.T) {
// this is the list of known security related fields, add to this list if a new field
// is added to Config, update AnonymousClientConfig to preserve the field otherwise.
expected.Impersonate = ""
expected.Impersonate = ImpersonationConfig{}
expected.BearerToken = ""
expected.Username = ""
expected.Password = ""
......
......@@ -89,6 +89,10 @@ func (c *Config) TransportConfig() (*transport.Config, error) {
Username: c.Username,
Password: c.Password,
BearerToken: c.BearerToken,
Impersonate: c.Impersonate,
Impersonate: transport.ImpersonationConfig{
UserName: c.Impersonate.UserName,
Groups: c.Impersonate.Groups,
Extra: c.Impersonate.Extra,
},
}, nil
}
......@@ -144,7 +144,7 @@ func (config *DirectClientConfig) ClientConfig() (*rest.Config, error) {
clientConfig.Host = u.String()
}
if len(configAuthInfo.Impersonate) > 0 {
clientConfig.Impersonate = configAuthInfo.Impersonate
clientConfig.Impersonate = rest.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
}
// only try to read the auth information if we are secure
......@@ -215,7 +215,7 @@ func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fa
mergedConfig.BearerToken = string(tokenBytes)
}
if len(configAuthInfo.Impersonate) > 0 {
mergedConfig.Impersonate = configAuthInfo.Impersonate
mergedConfig.Impersonate = rest.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
}
if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 {
mergedConfig.CertFile = configAuthInfo.ClientCertificate
......
......@@ -244,7 +244,9 @@ func (e *eventLogger) eventObserve(newEvent *v1.Event) (*v1.Event, []byte, error
newData, _ := json.Marshal(event)
oldData, _ := json.Marshal(eventCopy2)
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event)
// TODO: need to figure out if we need to let eventObserve() use the new behavior of StrategicMergePatch.
// Currently default to old behavior now. Ref: issue #35936
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event, strategicpatch.SMPatchVersion_1_0)
}
// record our new observation
......
......@@ -34,8 +34,8 @@ type Config struct {
// Bearer token for authentication
BearerToken string
// Impersonate is the username that this Config will impersonate
Impersonate string
// Impersonate is the config that this Config will impersonate using
Impersonate ImpersonationConfig
// Transport may be used for custom HTTP behavior. This attribute may
// not be specified with the TLS client certificate options. Use
......@@ -50,6 +50,16 @@ type Config struct {
WrapTransport func(rt http.RoundTripper) http.RoundTripper
}
// ImpersonationConfig has all the available impersonation options
type ImpersonationConfig struct {
// UserName matches user.Info.GetName()
UserName string
// Groups matches user.Info.GetGroups()
Groups []string
// Extra matches user.Info.GetExtra()
Extra map[string][]string
}
// HasCA returns whether the configuration has a certificate authority or not.
func (c *Config) HasCA() bool {
return len(c.TLS.CAData) > 0 || len(c.TLS.CAFile) > 0
......
......@@ -48,7 +48,9 @@ func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTrip
if len(config.UserAgent) > 0 {
rt = NewUserAgentRoundTripper(config.UserAgent, rt)
}
if len(config.Impersonate) > 0 {
if len(config.Impersonate.UserName) > 0 ||
len(config.Impersonate.Groups) > 0 ||
len(config.Impersonate.Extra) > 0 {
rt = NewImpersonatingRoundTripper(config.Impersonate, rt)
}
return rt, nil
......@@ -133,22 +135,53 @@ func (rt *basicAuthRoundTripper) CancelRequest(req *http.Request) {
func (rt *basicAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
// These correspond to the headers used in pkg/apis/authentication. We don't want the package dependency,
// but you must not change the values.
const (
// ImpersonateUserHeader is used to impersonate a particular user during an API server request
ImpersonateUserHeader = "Impersonate-User"
// ImpersonateGroupHeader is used to impersonate a particular group during an API server request.
// It can be repeated multiplied times for multiple groups.
ImpersonateGroupHeader = "Impersonate-Group"
// ImpersonateUserExtraHeaderPrefix is a prefix for a header used to impersonate an entry in the
// extra map[string][]string for user.Info. The key for the `extra` map is suffix.
// The same key can be repeated multiple times to have multiple elements in the slice under a single key.
// For instance:
// Impersonate-Extra-Foo: one
// Impersonate-Extra-Foo: two
// results in extra["Foo"] = []string{"one", "two"}
ImpersonateUserExtraHeaderPrefix = "Impersonate-Extra-"
)
type impersonatingRoundTripper struct {
impersonate string
impersonate ImpersonationConfig
delegate http.RoundTripper
}
// NewImpersonatingRoundTripper will add an Act-As header to a request unless it has already been set.
func NewImpersonatingRoundTripper(impersonate string, delegate http.RoundTripper) http.RoundTripper {
func NewImpersonatingRoundTripper(impersonate ImpersonationConfig, delegate http.RoundTripper) http.RoundTripper {
return &impersonatingRoundTripper{impersonate, delegate}
}
func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if len(req.Header.Get("Impersonate-User")) != 0 {
// use the user header as marker for the rest.
if len(req.Header.Get(ImpersonateUserHeader)) != 0 {
return rt.delegate.RoundTrip(req)
}
req = cloneRequest(req)
req.Header.Set("Impersonate-User", rt.impersonate)
req.Header.Set(ImpersonateUserHeader, rt.impersonate.UserName)
for _, group := range rt.impersonate.Groups {
req.Header.Add(ImpersonateGroupHeader, group)
}
for k, vv := range rt.impersonate.Extra {
for _, v := range vv {
req.Header.Add(ImpersonateUserExtraHeaderPrefix+k, v)
}
}
return rt.delegate.RoundTrip(req)
}
......
......@@ -18,6 +18,7 @@ package transport
import (
"net/http"
"reflect"
"testing"
)
......@@ -99,3 +100,58 @@ func TestUserAgentRoundTripper(t *testing.T) {
t.Errorf("unexpected user agent header: %#v", rt.Request)
}
}
func TestImpersonationRoundTripper(t *testing.T) {
tcs := []struct {
name string
impersonationConfig ImpersonationConfig
expected map[string][]string
}{
{
name: "all",
impersonationConfig: ImpersonationConfig{
UserName: "user",
Groups: []string{"one", "two"},
Extra: map[string][]string{
"first": {"A", "a"},
"second": {"B", "b"},
},
},
expected: map[string][]string{
ImpersonateUserHeader: {"user"},
ImpersonateGroupHeader: {"one", "two"},
ImpersonateUserExtraHeaderPrefix + "First": {"A", "a"},
ImpersonateUserExtraHeaderPrefix + "Second": {"B", "b"},
},
},
}
for _, tc := range tcs {
rt := &testRoundTripper{}
req := &http.Request{
Header: make(http.Header),
}
NewImpersonatingRoundTripper(tc.impersonationConfig, rt).RoundTrip(req)
for k, v := range rt.Request.Header {
expected, ok := tc.expected[k]
if !ok {
t.Errorf("%v missing %v=%v", tc.name, k, v)
continue
}
if !reflect.DeepEqual(expected, v) {
t.Errorf("%v expected %v: %v, got %v", tc.name, k, expected, v)
}
}
for k, v := range tc.expected {
expected, ok := rt.Request.Header[k]
if !ok {
t.Errorf("%v missing %v=%v", tc.name, k, v)
continue
}
if !reflect.DeepEqual(expected, v) {
t.Errorf("%v expected %v: %v, got %v", tc.name, k, expected, v)
}
}
}
}
......@@ -10834,6 +10834,7 @@ go_library(
deps = [
"//vendor:github.com/davecgh/go-spew/spew",
"//vendor:github.com/ghodss/yaml",
"//vendor:k8s.io/client-go/discovery",
"//vendor:k8s.io/client-go/pkg/third_party/forked/golang/json",
"//vendor:k8s.io/client-go/pkg/util/json",
],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment