123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /*
- Copyright 2017 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 auth
- import (
- "bytes"
- "fmt"
- "io/ioutil"
- "net/http"
- "testing"
- "time"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apiserver/pkg/authentication/request/bearertoken"
- bootstrapapi "k8s.io/cluster-bootstrap/token/api"
- "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
- bootstraputil "k8s.io/kubernetes/test/e2e/lifecycle/bootstrap"
- "k8s.io/kubernetes/test/integration"
- "k8s.io/kubernetes/test/integration/framework"
- )
- type bootstrapSecrets []*corev1.Secret
- func (b bootstrapSecrets) List(selector labels.Selector) (ret []*corev1.Secret, err error) {
- return b, nil
- }
- func (b bootstrapSecrets) Get(name string) (*corev1.Secret, error) {
- return b[0], nil
- }
- // TestBootstrapTokenAuth tests the bootstrap token auth provider
- func TestBootstrapTokenAuth(t *testing.T) {
- tokenID, err := bootstraputil.GenerateTokenID()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- secret, err := bootstraputil.GenerateTokenSecret()
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- var bootstrapSecretValid = &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: metav1.NamespaceSystem,
- Name: bootstrapapi.BootstrapTokenSecretPrefix,
- },
- Type: corev1.SecretTypeBootstrapToken,
- Data: map[string][]byte{
- bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
- bootstrapapi.BootstrapTokenSecretKey: []byte(secret),
- bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
- },
- }
- var bootstrapSecretInvalid = &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: metav1.NamespaceSystem,
- Name: bootstrapapi.BootstrapTokenSecretPrefix,
- },
- Type: corev1.SecretTypeBootstrapToken,
- Data: map[string][]byte{
- bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
- bootstrapapi.BootstrapTokenSecretKey: []byte("invalid"),
- bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
- },
- }
- var expiredBootstrapToken = &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: metav1.NamespaceSystem,
- Name: bootstrapapi.BootstrapTokenSecretPrefix,
- },
- Type: corev1.SecretTypeBootstrapToken,
- Data: map[string][]byte{
- bootstrapapi.BootstrapTokenIDKey: []byte(tokenID),
- bootstrapapi.BootstrapTokenSecretKey: []byte("invalid"),
- bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
- bootstrapapi.BootstrapTokenExpirationKey: []byte(bootstraputil.TimeStringFromNow(-time.Hour)),
- },
- }
- type request struct {
- verb string
- URL string
- body string
- statusCodes map[int]bool // Set of expected resp.StatusCode if all goes well.
- }
- tests := []struct {
- name string
- request request
- secret *corev1.Secret
- }{
- {
- name: "valid token",
- request: request{verb: "GET", URL: path("pods", "", ""), body: "", statusCodes: integration.Code200},
- secret: bootstrapSecretValid,
- },
- {
- name: "invalid token format",
- request: request{verb: "GET", URL: path("pods", "", ""), body: "", statusCodes: integration.Code401},
- secret: bootstrapSecretInvalid,
- },
- {
- name: "invalid token expired",
- request: request{verb: "GET", URL: path("pods", "", ""), body: "", statusCodes: integration.Code401},
- secret: expiredBootstrapToken,
- },
- }
- for _, test := range tests {
- authenticator := bearertoken.New(bootstrap.NewTokenAuthenticator(bootstrapSecrets{test.secret}))
- // Set up a master
- masterConfig := framework.NewIntegrationTestMasterConfig()
- masterConfig.GenericConfig.Authentication.Authenticator = authenticator
- _, s, closeFn := framework.RunAMaster(masterConfig)
- defer closeFn()
- ns := framework.CreateTestingNamespace("auth-bootstrap-token", s, t)
- defer framework.DeleteTestingNamespace(ns, s, t)
- previousResourceVersion := make(map[string]float64)
- transport := http.DefaultTransport
- token := tokenID + "." + secret
- var bodyStr string
- if test.request.body != "" {
- sub := ""
- if test.request.verb == "PUT" {
- // For update operations, insert previous resource version
- if resVersion := previousResourceVersion[getPreviousResourceVersionKey(test.request.URL, "")]; resVersion != 0 {
- sub += fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion)
- }
- sub += fmt.Sprintf(",\r\n\"namespace\": %q", ns.Name)
- }
- bodyStr = fmt.Sprintf(test.request.body, sub)
- }
- test.request.body = bodyStr
- bodyBytes := bytes.NewReader([]byte(bodyStr))
- req, err := http.NewRequest(test.request.verb, s.URL+test.request.URL, bodyBytes)
- if err != nil {
- t.Fatalf("unexpected error: %v", err)
- }
- req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
- if test.request.verb == "PATCH" {
- req.Header.Set("Content-Type", "application/merge-patch+json")
- }
- func() {
- resp, err := transport.RoundTrip(req)
- if err != nil {
- t.Logf("case %v", test.name)
- t.Fatalf("unexpected error: %v", err)
- }
- defer resp.Body.Close()
- b, _ := ioutil.ReadAll(resp.Body)
- if _, ok := test.request.statusCodes[resp.StatusCode]; !ok {
- t.Logf("case %v", test.name)
- t.Errorf("Expected status one of %v, but got %v", test.request.statusCodes, resp.StatusCode)
- t.Errorf("Body: %v", string(b))
- } else {
- if test.request.verb == "POST" {
- // For successful create operations, extract resourceVersion
- id, currentResourceVersion, err := parseResourceVersion(b)
- if err == nil {
- key := getPreviousResourceVersionKey(test.request.URL, id)
- previousResourceVersion[key] = currentResourceVersion
- }
- }
- }
- }()
- }
- }
|