mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			312 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2016 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package restclient
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
 | 
						|
)
 | 
						|
 | 
						|
func TestAuthPluginWrapTransport(t *testing.T) {
 | 
						|
	if err := RegisterAuthProviderPlugin("pluginA", pluginAProvider); err != nil {
 | 
						|
		t.Errorf("Unexpected error: failed to register pluginA: %v", err)
 | 
						|
	}
 | 
						|
	if err := RegisterAuthProviderPlugin("pluginB", pluginBProvider); err != nil {
 | 
						|
		t.Errorf("Unexpected error: failed to register pluginB: %v", err)
 | 
						|
	}
 | 
						|
	if err := RegisterAuthProviderPlugin("pluginFail", pluginFailProvider); err != nil {
 | 
						|
		t.Errorf("Unexpected error: failed to register pluginFail: %v", err)
 | 
						|
	}
 | 
						|
	testCases := []struct {
 | 
						|
		useWrapTransport bool
 | 
						|
		plugin           string
 | 
						|
		expectErr        bool
 | 
						|
		expectPluginA    bool
 | 
						|
		expectPluginB    bool
 | 
						|
	}{
 | 
						|
		{false, "", false, false, false},
 | 
						|
		{false, "pluginA", false, true, false},
 | 
						|
		{false, "pluginB", false, false, true},
 | 
						|
		{false, "pluginFail", true, false, false},
 | 
						|
		{false, "pluginUnknown", true, false, false},
 | 
						|
	}
 | 
						|
	for i, tc := range testCases {
 | 
						|
		c := Config{}
 | 
						|
		if tc.useWrapTransport {
 | 
						|
			// Specify an existing WrapTransport in the config to make sure that
 | 
						|
			// plugins play nicely.
 | 
						|
			c.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
 | 
						|
				return &wrapTransport{rt}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if len(tc.plugin) != 0 {
 | 
						|
			c.AuthProvider = &clientcmdapi.AuthProviderConfig{Name: tc.plugin}
 | 
						|
		}
 | 
						|
		tConfig, err := c.TransportConfig()
 | 
						|
		if err != nil {
 | 
						|
			// Unknown/bad plugins are expected to fail here.
 | 
						|
			if !tc.expectErr {
 | 
						|
				t.Errorf("%d. Did not expect errors loading Auth Plugin: %q. Got: %v", i, tc.plugin, err)
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		var fullyWrappedTransport http.RoundTripper
 | 
						|
		fullyWrappedTransport = &emptyTransport{}
 | 
						|
		if tConfig.WrapTransport != nil {
 | 
						|
			fullyWrappedTransport = tConfig.WrapTransport(&emptyTransport{})
 | 
						|
		}
 | 
						|
		res, err := fullyWrappedTransport.RoundTrip(&http.Request{})
 | 
						|
		if err != nil {
 | 
						|
			t.Errorf("%d. Unexpected error in RoundTrip: %v", i, err)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		hasWrapTransport := res.Header.Get("wrapTransport") == "Y"
 | 
						|
		hasPluginA := res.Header.Get("pluginA") == "Y"
 | 
						|
		hasPluginB := res.Header.Get("pluginB") == "Y"
 | 
						|
		if hasWrapTransport != tc.useWrapTransport {
 | 
						|
			t.Errorf("%d. Expected Existing config.WrapTransport: %t; Got: %t", i, tc.useWrapTransport, hasWrapTransport)
 | 
						|
		}
 | 
						|
		if hasPluginA != tc.expectPluginA {
 | 
						|
			t.Errorf("%d. Expected Plugin A: %t; Got: %t", i, tc.expectPluginA, hasPluginA)
 | 
						|
		}
 | 
						|
		if hasPluginB != tc.expectPluginB {
 | 
						|
			t.Errorf("%d. Expected Plugin B: %t; Got: %t", i, tc.expectPluginB, hasPluginB)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestAuthPluginPersist(t *testing.T) {
 | 
						|
	// register pluginA by a different name so we don't collide across tests.
 | 
						|
	if err := RegisterAuthProviderPlugin("pluginA2", pluginAProvider); err != nil {
 | 
						|
		t.Errorf("Unexpected error: failed to register pluginA: %v", err)
 | 
						|
	}
 | 
						|
	if err := RegisterAuthProviderPlugin("pluginPersist", pluginPersistProvider); err != nil {
 | 
						|
		t.Errorf("Unexpected error: failed to register pluginPersist: %v", err)
 | 
						|
	}
 | 
						|
	fooBarConfig := map[string]string{"foo": "bar"}
 | 
						|
	testCases := []struct {
 | 
						|
		plugin                       string
 | 
						|
		startingConfig               map[string]string
 | 
						|
		expectedConfigAfterLogin     map[string]string
 | 
						|
		expectedConfigAfterRoundTrip map[string]string
 | 
						|
	}{
 | 
						|
		// non-persisting plugins should work fine without modifying config.
 | 
						|
		{"pluginA2", map[string]string{}, map[string]string{}, map[string]string{}},
 | 
						|
		{"pluginA2", fooBarConfig, fooBarConfig, fooBarConfig},
 | 
						|
		// plugins that persist config should be able to persist when they want.
 | 
						|
		{
 | 
						|
			"pluginPersist",
 | 
						|
			map[string]string{},
 | 
						|
			map[string]string{
 | 
						|
				"login": "Y",
 | 
						|
			},
 | 
						|
			map[string]string{
 | 
						|
				"login":      "Y",
 | 
						|
				"roundTrips": "1",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"pluginPersist",
 | 
						|
			map[string]string{
 | 
						|
				"login":      "Y",
 | 
						|
				"roundTrips": "123",
 | 
						|
			},
 | 
						|
			map[string]string{
 | 
						|
				"login":      "Y",
 | 
						|
				"roundTrips": "123",
 | 
						|
			},
 | 
						|
			map[string]string{
 | 
						|
				"login":      "Y",
 | 
						|
				"roundTrips": "124",
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for i, tc := range testCases {
 | 
						|
		cfg := &clientcmdapi.AuthProviderConfig{
 | 
						|
			Name:   tc.plugin,
 | 
						|
			Config: tc.startingConfig,
 | 
						|
		}
 | 
						|
		persister := &inMemoryPersister{make(map[string]string)}
 | 
						|
		persister.Persist(tc.startingConfig)
 | 
						|
		plugin, err := GetAuthProvider("127.0.0.1", cfg, persister)
 | 
						|
		if err != nil {
 | 
						|
			t.Errorf("%d. Unexpected error: failed to get plugin %q: %v", i, tc.plugin, err)
 | 
						|
		}
 | 
						|
		if err := plugin.Login(); err != nil {
 | 
						|
			t.Errorf("%d. Unexpected error calling Login() w/ plugin %q: %v", i, tc.plugin, err)
 | 
						|
		}
 | 
						|
		// Make sure the plugin persisted what we expect after Login().
 | 
						|
		if !reflect.DeepEqual(persister.savedConfig, tc.expectedConfigAfterLogin) {
 | 
						|
			t.Errorf("%d. Unexpected persisted config after calling %s.Login(): \nGot:\n%v\nExpected:\n%v",
 | 
						|
				i, tc.plugin, persister.savedConfig, tc.expectedConfigAfterLogin)
 | 
						|
		}
 | 
						|
		if _, err := plugin.WrapTransport(&emptyTransport{}).RoundTrip(&http.Request{}); err != nil {
 | 
						|
			t.Errorf("%d. Unexpected error round-tripping w/ plugin %q: %v", i, tc.plugin, err)
 | 
						|
		}
 | 
						|
		// Make sure the plugin persisted what we expect after RoundTrip().
 | 
						|
		if !reflect.DeepEqual(persister.savedConfig, tc.expectedConfigAfterRoundTrip) {
 | 
						|
			t.Errorf("%d. Unexpected persisted config after calling %s.WrapTransport.RoundTrip(): \nGot:\n%v\nExpected:\n%v",
 | 
						|
				i, tc.plugin, persister.savedConfig, tc.expectedConfigAfterLogin)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
// emptyTransport provides an empty http.Response with an initialized header
 | 
						|
// to allow wrapping RoundTrippers to set header values.
 | 
						|
type emptyTransport struct{}
 | 
						|
 | 
						|
func (*emptyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
						|
	res := &http.Response{
 | 
						|
		Header: make(map[string][]string),
 | 
						|
	}
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
// wrapTransport sets "wrapTransport" = "Y" on the response.
 | 
						|
type wrapTransport struct {
 | 
						|
	rt http.RoundTripper
 | 
						|
}
 | 
						|
 | 
						|
func (w *wrapTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
						|
	res, err := w.rt.RoundTrip(req)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	res.Header.Add("wrapTransport", "Y")
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
// wrapTransportA sets "pluginA" = "Y" on the response.
 | 
						|
type wrapTransportA struct {
 | 
						|
	rt http.RoundTripper
 | 
						|
}
 | 
						|
 | 
						|
func (w *wrapTransportA) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
						|
	res, err := w.rt.RoundTrip(req)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	res.Header.Add("pluginA", "Y")
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
type pluginA struct{}
 | 
						|
 | 
						|
func (*pluginA) WrapTransport(rt http.RoundTripper) http.RoundTripper {
 | 
						|
	return &wrapTransportA{rt}
 | 
						|
}
 | 
						|
 | 
						|
func (*pluginA) Login() error { return nil }
 | 
						|
 | 
						|
func pluginAProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) {
 | 
						|
	return &pluginA{}, nil
 | 
						|
}
 | 
						|
 | 
						|
// wrapTransportB sets "pluginB" = "Y" on the response.
 | 
						|
type wrapTransportB struct {
 | 
						|
	rt http.RoundTripper
 | 
						|
}
 | 
						|
 | 
						|
func (w *wrapTransportB) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
						|
	res, err := w.rt.RoundTrip(req)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	res.Header.Add("pluginB", "Y")
 | 
						|
	return res, nil
 | 
						|
}
 | 
						|
 | 
						|
type pluginB struct{}
 | 
						|
 | 
						|
func (*pluginB) WrapTransport(rt http.RoundTripper) http.RoundTripper {
 | 
						|
	return &wrapTransportB{rt}
 | 
						|
}
 | 
						|
 | 
						|
func (*pluginB) Login() error { return nil }
 | 
						|
 | 
						|
func pluginBProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) {
 | 
						|
	return &pluginB{}, nil
 | 
						|
}
 | 
						|
 | 
						|
// pluginFailProvider simulates a registered AuthPlugin that fails to load.
 | 
						|
func pluginFailProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) {
 | 
						|
	return nil, fmt.Errorf("Failed to load AuthProvider")
 | 
						|
}
 | 
						|
 | 
						|
type inMemoryPersister struct {
 | 
						|
	savedConfig map[string]string
 | 
						|
}
 | 
						|
 | 
						|
func (i *inMemoryPersister) Persist(config map[string]string) error {
 | 
						|
	i.savedConfig = make(map[string]string)
 | 
						|
	for k, v := range config {
 | 
						|
		i.savedConfig[k] = v
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// wrapTransportPersist increments the "roundTrips" entry from the config when
 | 
						|
// roundTrip is called.
 | 
						|
type wrapTransportPersist struct {
 | 
						|
	rt        http.RoundTripper
 | 
						|
	config    map[string]string
 | 
						|
	persister AuthProviderConfigPersister
 | 
						|
}
 | 
						|
 | 
						|
func (w *wrapTransportPersist) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
						|
	roundTrips := 0
 | 
						|
	if rtVal, ok := w.config["roundTrips"]; ok {
 | 
						|
		var err error
 | 
						|
		roundTrips, err = strconv.Atoi(rtVal)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	roundTrips++
 | 
						|
	w.config["roundTrips"] = fmt.Sprintf("%d", roundTrips)
 | 
						|
	if err := w.persister.Persist(w.config); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return w.rt.RoundTrip(req)
 | 
						|
}
 | 
						|
 | 
						|
type pluginPersist struct {
 | 
						|
	config    map[string]string
 | 
						|
	persister AuthProviderConfigPersister
 | 
						|
}
 | 
						|
 | 
						|
func (p *pluginPersist) WrapTransport(rt http.RoundTripper) http.RoundTripper {
 | 
						|
	return &wrapTransportPersist{rt, p.config, p.persister}
 | 
						|
}
 | 
						|
 | 
						|
// Login sets the config entry "login" to "Y".
 | 
						|
func (p *pluginPersist) Login() error {
 | 
						|
	p.config["login"] = "Y"
 | 
						|
	p.persister.Persist(p.config)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func pluginPersistProvider(_ string, config map[string]string, persister AuthProviderConfigPersister) (AuthProvider, error) {
 | 
						|
	return &pluginPersist{config, persister}, nil
 | 
						|
}
 |