github.com/enmand/kubernetes@v1.2.0-alpha.0/pkg/credentialprovider/gcp/metadata_test.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package gcp_credentials
    18  
    19  import (
    20  	"encoding/base64"
    21  	"encoding/json"
    22  	"fmt"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"net/url"
    26  	"reflect"
    27  	"strings"
    28  	"testing"
    29  
    30  	"k8s.io/kubernetes/pkg/credentialprovider"
    31  )
    32  
    33  func TestDockerKeyringFromGoogleDockerConfigMetadata(t *testing.T) {
    34  	registryUrl := "hello.kubernetes.io"
    35  	email := "foo@bar.baz"
    36  	username := "foo"
    37  	password := "bar"
    38  	auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
    39  	sampleDockerConfig := fmt.Sprintf(`{
    40     "https://%s": {
    41       "email": %q,
    42       "auth": %q
    43     }
    44  }`, registryUrl, email, auth)
    45  
    46  	const probeEndpoint = "/computeMetadata/v1/"
    47  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    48  		// Only serve the one metadata key.
    49  		if probeEndpoint == r.URL.Path {
    50  			w.WriteHeader(http.StatusOK)
    51  		} else if strings.HasSuffix(dockerConfigKey, r.URL.Path) {
    52  			w.WriteHeader(http.StatusOK)
    53  			w.Header().Set("Content-Type", "application/json")
    54  			fmt.Fprintln(w, sampleDockerConfig)
    55  		} else {
    56  			w.WriteHeader(http.StatusNotFound)
    57  		}
    58  	}))
    59  	defer server.Close()
    60  
    61  	// Make a transport that reroutes all traffic to the example server
    62  	transport := &http.Transport{
    63  		Proxy: func(req *http.Request) (*url.URL, error) {
    64  			return url.Parse(server.URL + req.URL.Path)
    65  		},
    66  	}
    67  
    68  	keyring := &credentialprovider.BasicDockerKeyring{}
    69  	provider := &dockerConfigKeyProvider{
    70  		metadataProvider{Client: &http.Client{Transport: transport}},
    71  	}
    72  
    73  	if !provider.Enabled() {
    74  		t.Errorf("Provider is unexpectedly disabled")
    75  	}
    76  
    77  	keyring.Add(provider.Provide())
    78  
    79  	creds, ok := keyring.Lookup(registryUrl)
    80  	if !ok {
    81  		t.Errorf("Didn't find expected URL: %s", registryUrl)
    82  		return
    83  	}
    84  	if len(creds) > 1 {
    85  		t.Errorf("Got more hits than expected: %s", creds)
    86  	}
    87  	val := creds[0]
    88  
    89  	if username != val.Username {
    90  		t.Errorf("Unexpected username value, want: %s, got: %s", username, val.Username)
    91  	}
    92  	if password != val.Password {
    93  		t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password)
    94  	}
    95  	if email != val.Email {
    96  		t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
    97  	}
    98  }
    99  
   100  func TestDockerKeyringFromGoogleDockerConfigMetadataUrl(t *testing.T) {
   101  	registryUrl := "hello.kubernetes.io"
   102  	email := "foo@bar.baz"
   103  	username := "foo"
   104  	password := "bar"
   105  	auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password)))
   106  	sampleDockerConfig := fmt.Sprintf(`{
   107     "https://%s": {
   108       "email": %q,
   109       "auth": %q
   110     }
   111  }`, registryUrl, email, auth)
   112  
   113  	const probeEndpoint = "/computeMetadata/v1/"
   114  	const valueEndpoint = "/my/value"
   115  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   116  		// Only serve the URL key and the value endpoint
   117  		if probeEndpoint == r.URL.Path {
   118  			w.WriteHeader(http.StatusOK)
   119  		} else if valueEndpoint == r.URL.Path {
   120  			w.WriteHeader(http.StatusOK)
   121  			w.Header().Set("Content-Type", "application/json")
   122  			fmt.Fprintln(w, sampleDockerConfig)
   123  		} else if strings.HasSuffix(dockerConfigUrlKey, r.URL.Path) {
   124  			w.WriteHeader(http.StatusOK)
   125  			w.Header().Set("Content-Type", "application/text")
   126  			fmt.Fprint(w, "http://foo.bar.com"+valueEndpoint)
   127  		} else {
   128  			w.WriteHeader(http.StatusNotFound)
   129  		}
   130  	}))
   131  	defer server.Close()
   132  
   133  	// Make a transport that reroutes all traffic to the example server
   134  	transport := &http.Transport{
   135  		Proxy: func(req *http.Request) (*url.URL, error) {
   136  			return url.Parse(server.URL + req.URL.Path)
   137  		},
   138  	}
   139  
   140  	keyring := &credentialprovider.BasicDockerKeyring{}
   141  	provider := &dockerConfigUrlKeyProvider{
   142  		metadataProvider{Client: &http.Client{Transport: transport}},
   143  	}
   144  
   145  	if !provider.Enabled() {
   146  		t.Errorf("Provider is unexpectedly disabled")
   147  	}
   148  
   149  	keyring.Add(provider.Provide())
   150  
   151  	creds, ok := keyring.Lookup(registryUrl)
   152  	if !ok {
   153  		t.Errorf("Didn't find expected URL: %s", registryUrl)
   154  		return
   155  	}
   156  	if len(creds) > 1 {
   157  		t.Errorf("Got more hits than expected: %s", creds)
   158  	}
   159  	val := creds[0]
   160  
   161  	if username != val.Username {
   162  		t.Errorf("Unexpected username value, want: %s, got: %s", username, val.Username)
   163  	}
   164  	if password != val.Password {
   165  		t.Errorf("Unexpected password value, want: %s, got: %s", password, val.Password)
   166  	}
   167  	if email != val.Email {
   168  		t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
   169  	}
   170  }
   171  
   172  func TestContainerRegistryBasics(t *testing.T) {
   173  	registryUrl := "container.cloud.google.com"
   174  	email := "1234@project.gserviceaccount.com"
   175  	token := &tokenBlob{AccessToken: "ya26.lots-of-indiscernible-garbage"}
   176  
   177  	const (
   178  		defaultEndpoint = "/computeMetadata/v1/instance/service-accounts/default/"
   179  		scopeEndpoint   = defaultEndpoint + "scopes"
   180  		emailEndpoint   = defaultEndpoint + "email"
   181  		tokenEndpoint   = defaultEndpoint + "token"
   182  	)
   183  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   184  		// Only serve the URL key and the value endpoint
   185  		if scopeEndpoint == r.URL.Path {
   186  			w.WriteHeader(http.StatusOK)
   187  			w.Header().Set("Content-Type", "application/json")
   188  			fmt.Fprintf(w, `["%s.read_write"]`, storageScopePrefix)
   189  		} else if emailEndpoint == r.URL.Path {
   190  			w.WriteHeader(http.StatusOK)
   191  			fmt.Fprint(w, email)
   192  		} else if tokenEndpoint == r.URL.Path {
   193  			w.WriteHeader(http.StatusOK)
   194  			w.Header().Set("Content-Type", "application/json")
   195  			bytes, err := json.Marshal(token)
   196  			if err != nil {
   197  				t.Fatalf("unexpected error: %v", err)
   198  			}
   199  			fmt.Fprintln(w, string(bytes))
   200  		} else {
   201  			w.WriteHeader(http.StatusNotFound)
   202  		}
   203  	}))
   204  	defer server.Close()
   205  
   206  	// Make a transport that reroutes all traffic to the example server
   207  	transport := &http.Transport{
   208  		Proxy: func(req *http.Request) (*url.URL, error) {
   209  			return url.Parse(server.URL + req.URL.Path)
   210  		},
   211  	}
   212  
   213  	keyring := &credentialprovider.BasicDockerKeyring{}
   214  	provider := &containerRegistryProvider{
   215  		metadataProvider{Client: &http.Client{Transport: transport}},
   216  	}
   217  
   218  	if !provider.Enabled() {
   219  		t.Errorf("Provider is unexpectedly disabled")
   220  	}
   221  
   222  	keyring.Add(provider.Provide())
   223  
   224  	creds, ok := keyring.Lookup(registryUrl)
   225  	if !ok {
   226  		t.Errorf("Didn't find expected URL: %s", registryUrl)
   227  		return
   228  	}
   229  	if len(creds) > 1 {
   230  		t.Errorf("Got more hits than expected: %s", creds)
   231  	}
   232  	val := creds[0]
   233  
   234  	if "_token" != val.Username {
   235  		t.Errorf("Unexpected username value, want: %s, got: %s", "_token", val.Username)
   236  	}
   237  	if token.AccessToken != val.Password {
   238  		t.Errorf("Unexpected password value, want: %s, got: %s", token.AccessToken, val.Password)
   239  	}
   240  	if email != val.Email {
   241  		t.Errorf("Unexpected email value, want: %s, got: %s", email, val.Email)
   242  	}
   243  }
   244  
   245  func TestContainerRegistryNoStorageScope(t *testing.T) {
   246  	const (
   247  		defaultEndpoint = "/computeMetadata/v1/instance/service-accounts/default/"
   248  		scopeEndpoint   = defaultEndpoint + "scopes"
   249  	)
   250  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   251  		// Only serve the URL key and the value endpoint
   252  		if scopeEndpoint == r.URL.Path {
   253  			w.WriteHeader(http.StatusOK)
   254  			w.Header().Set("Content-Type", "application/json")
   255  			fmt.Fprint(w, `["https://www.googleapis.com/auth/compute.read_write"]`)
   256  		} else {
   257  			w.WriteHeader(http.StatusNotFound)
   258  		}
   259  	}))
   260  	defer server.Close()
   261  
   262  	// Make a transport that reroutes all traffic to the example server
   263  	transport := &http.Transport{
   264  		Proxy: func(req *http.Request) (*url.URL, error) {
   265  			return url.Parse(server.URL + req.URL.Path)
   266  		},
   267  	}
   268  
   269  	provider := &containerRegistryProvider{
   270  		metadataProvider{Client: &http.Client{Transport: transport}},
   271  	}
   272  
   273  	if provider.Enabled() {
   274  		t.Errorf("Provider is unexpectedly enabled")
   275  	}
   276  }
   277  
   278  func TestComputePlatformScopeSubstitutesStorageScope(t *testing.T) {
   279  	const (
   280  		defaultEndpoint = "/computeMetadata/v1/instance/service-accounts/default/"
   281  		scopeEndpoint   = defaultEndpoint + "scopes"
   282  	)
   283  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   284  		// Only serve the URL key and the value endpoint
   285  		if scopeEndpoint == r.URL.Path {
   286  			w.WriteHeader(http.StatusOK)
   287  			w.Header().Set("Content-Type", "application/json")
   288  			fmt.Fprint(w, `["https://www.googleapis.com/auth/compute.read_write","https://www.googleapis.com/auth/cloud-platform.read-only"]`)
   289  		} else {
   290  			w.WriteHeader(http.StatusNotFound)
   291  		}
   292  	}))
   293  	defer server.Close()
   294  
   295  	// Make a transport that reroutes all traffic to the example server
   296  	transport := &http.Transport{
   297  		Proxy: func(req *http.Request) (*url.URL, error) {
   298  			return url.Parse(server.URL + req.URL.Path)
   299  		},
   300  	}
   301  
   302  	provider := &containerRegistryProvider{
   303  		metadataProvider{Client: &http.Client{Transport: transport}},
   304  	}
   305  
   306  	if !provider.Enabled() {
   307  		t.Errorf("Provider is unexpectedly disabled")
   308  	}
   309  }
   310  
   311  func TestAllProvidersNoMetadata(t *testing.T) {
   312  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   313  		w.WriteHeader(http.StatusNotFound)
   314  	}))
   315  	defer server.Close()
   316  
   317  	// Make a transport that reroutes all traffic to the example server
   318  	transport := &http.Transport{
   319  		Proxy: func(req *http.Request) (*url.URL, error) {
   320  			return url.Parse(server.URL + req.URL.Path)
   321  		},
   322  	}
   323  
   324  	providers := []credentialprovider.DockerConfigProvider{
   325  		&dockerConfigKeyProvider{
   326  			metadataProvider{Client: &http.Client{Transport: transport}},
   327  		},
   328  		&dockerConfigUrlKeyProvider{
   329  			metadataProvider{Client: &http.Client{Transport: transport}},
   330  		},
   331  		&containerRegistryProvider{
   332  			metadataProvider{Client: &http.Client{Transport: transport}},
   333  		},
   334  	}
   335  
   336  	for _, provider := range providers {
   337  		if provider.Enabled() {
   338  			t.Errorf("Provider %s is unexpectedly enabled", reflect.TypeOf(provider).String())
   339  		}
   340  	}
   341  }