...

Source file src/k8s.io/kubernetes/pkg/serviceaccount/jwt_test.go

Documentation: k8s.io/kubernetes/pkg/serviceaccount

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     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 serviceaccount_test
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"encoding/json"
    23  	"fmt"
    24  	"reflect"
    25  	"strings"
    26  	"testing"
    27  
    28  	jose "gopkg.in/square/go-jose.v2"
    29  
    30  	v1 "k8s.io/api/core/v1"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/apiserver/pkg/authentication/authenticator"
    33  	clientset "k8s.io/client-go/kubernetes"
    34  	"k8s.io/client-go/kubernetes/fake"
    35  	typedv1core "k8s.io/client-go/kubernetes/typed/core/v1"
    36  	v1listers "k8s.io/client-go/listers/core/v1"
    37  	"k8s.io/client-go/tools/cache"
    38  	"k8s.io/client-go/util/keyutil"
    39  	serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
    40  	"k8s.io/kubernetes/pkg/serviceaccount"
    41  )
    42  
    43  const otherPublicKey = `-----BEGIN PUBLIC KEY-----
    44  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArXz0QkIG1B5Bj2/W69GH
    45  rsm5e+RC3kE+VTgocge0atqlLBek35tRqLgUi3AcIrBZ/0YctMSWDVcRt5fkhWwe
    46  Lqjj6qvAyNyOkrkBi1NFDpJBjYJtuKHgRhNxXbOzTSNpdSKXTfOkzqv56MwHOP25
    47  yP/NNAODUtr92D5ySI5QX8RbXW+uDn+ixul286PBW/BCrE4tuS88dA0tYJPf8LCu
    48  sqQOwlXYH/rNUg4Pyl9xxhR5DIJR0OzNNfChjw60zieRIt2LfM83fXhwk8IxRGkc
    49  gPZm7ZsipmfbZK2Tkhnpsa4QxDg7zHJPMsB5kxRXW0cQipXcC3baDyN9KBApNXa0
    50  PwIDAQAB
    51  -----END PUBLIC KEY-----`
    52  
    53  const rsaPublicKey = `-----BEGIN PUBLIC KEY-----
    54  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA249XwEo9k4tM8fMxV7zx
    55  OhcrP+WvXn917koM5Qr2ZXs4vo26e4ytdlrV0bQ9SlcLpQVSYjIxNfhTZdDt+ecI
    56  zshKuv1gKIxbbLQMOuK1eA/4HALyEkFgmS/tleLJrhc65tKPMGD+pKQ/xhmzRuCG
    57  51RoiMgbQxaCyYxGfNLpLAZK9L0Tctv9a0mJmGIYnIOQM4kC1A1I1n3EsXMWmeJU
    58  j7OTh/AjjCnMnkgvKT2tpKxYQ59PgDgU8Ssc7RDSmSkLxnrv+OrN80j6xrw0OjEi
    59  B4Ycr0PqfzZcvy8efTtFQ/Jnc4Bp1zUtFXt7+QeevePtQ2EcyELXE0i63T1CujRM
    60  WwIDAQAB
    61  -----END PUBLIC KEY-----
    62  `
    63  
    64  // Obtained by:
    65  //
    66  //  1. Serializing rsaPublicKey as DER
    67  //  2. Taking the SHA256 of the DER bytes
    68  //  3. URLSafe Base64-encoding the sha bytes
    69  const rsaKeyID = "JHJehTTTZlsspKHT-GaJxK7Kd1NQgZJu3fyK6K_QDYU"
    70  
    71  // Fake value for testing.
    72  const rsaPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
    73  MIIEowIBAAKCAQEA249XwEo9k4tM8fMxV7zxOhcrP+WvXn917koM5Qr2ZXs4vo26
    74  e4ytdlrV0bQ9SlcLpQVSYjIxNfhTZdDt+ecIzshKuv1gKIxbbLQMOuK1eA/4HALy
    75  EkFgmS/tleLJrhc65tKPMGD+pKQ/xhmzRuCG51RoiMgbQxaCyYxGfNLpLAZK9L0T
    76  ctv9a0mJmGIYnIOQM4kC1A1I1n3EsXMWmeJUj7OTh/AjjCnMnkgvKT2tpKxYQ59P
    77  gDgU8Ssc7RDSmSkLxnrv+OrN80j6xrw0OjEiB4Ycr0PqfzZcvy8efTtFQ/Jnc4Bp
    78  1zUtFXt7+QeevePtQ2EcyELXE0i63T1CujRMWwIDAQABAoIBAHJx8GqyCBDNbqk7
    79  e7/hI9iE1S10Wwol5GH2RWxqX28cYMKq+8aE2LI1vPiXO89xOgelk4DN6urX6xjK
    80  ZBF8RRIMQy/e/O2F4+3wl+Nl4vOXV1u6iVXMsD6JRg137mqJf1Fr9elg1bsaRofL
    81  Q7CxPoB8dhS+Qb+hj0DhlqhgA9zG345CQCAds0ZYAZe8fP7bkwrLqZpMn7Dz9WVm
    82  ++YgYYKjuE95kPuup/LtWfA9rJyE/Fws8/jGvRSpVn1XglMLSMKhLd27sE8ZUSV0
    83  2KUzbfRGE0+AnRULRrjpYaPu0XQ2JjdNvtkjBnv27RB89W9Gklxq821eH1Y8got8
    84  FZodjxECgYEA93pz7AQZ2xDs67d1XLCzpX84GxKzttirmyj3OIlxgzVHjEMsvw8v
    85  sjFiBU5xEEQDosrBdSknnlJqyiq1YwWG/WDckr13d8G2RQWoySN7JVmTQfXcLoTu
    86  YGRiiTuoEi3ab3ZqrgGrFgX7T/cHuasbYvzCvhM2b4VIR3aSxU2DTUMCgYEA4x7J
    87  T/ErP6GkU5nKstu/mIXwNzayEO1BJvPYsy7i7EsxTm3xe/b8/6cYOz5fvJLGH5mT
    88  Q8YvuLqBcMwZardrYcwokD55UvNLOyfADDFZ6l3WntIqbA640Ok2g1X4U8J09xIq
    89  ZLIWK1yWbbvi4QCeN5hvWq47e8sIj5QHjIIjRwkCgYEAyNqjltxFN9zmzPDa2d24
    90  EAvOt3pYTYBQ1t9KtqImdL0bUqV6fZ6PsWoPCgt+DBuHb+prVPGP7Bkr/uTmznU/
    91  +AlTO+12NsYLbr2HHagkXE31DEXE7CSLa8RNjN/UKtz4Ohq7vnowJvG35FCz/mb3
    92  FUHbtHTXa2+bGBUOTf/5Hw0CgYBxw0r9EwUhw1qnUYJ5op7OzFAtp+T7m4ul8kCa
    93  SCL8TxGsgl+SQ34opE775dtYfoBk9a0RJqVit3D8yg71KFjOTNAIqHJm/Vyyjc+h
    94  i9rJDSXiuczsAVfLtPVMRfS0J9QkqeG4PIfkQmVLI/CZ2ZBmsqEcX+eFs4ZfPLun
    95  Qsxe2QKBgGuPilIbLeIBDIaPiUI0FwU8v2j8CEQBYvoQn34c95hVQsig/o5z7zlo
    96  UsO0wlTngXKlWdOcCs1kqEhTLrstf48djDxAYAxkw40nzeJOt7q52ib/fvf4/UBy
    97  X024wzbiw1q07jFCyfQmODzURAx1VNT7QVUMdz/N8vy47/H40AZJ
    98  -----END RSA PRIVATE KEY-----
    99  `
   100  
   101  // openssl ecparam -name prime256v1 -genkey -noout -out ecdsa256.pem
   102  // Fake value for testing.
   103  const ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
   104  MHcCAQEEIEZmTmUhuanLjPA2CLquXivuwBDHTt5XYwgIr/kA1LtRoAoGCCqGSM49
   105  AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0
   106  /IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
   107  -----END EC PRIVATE KEY-----`
   108  
   109  // openssl ec -in ecdsa256.pem -pubout -out ecdsa256pub.pem
   110  const ecdsaPublicKey = `-----BEGIN PUBLIC KEY-----
   111  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPL
   112  X2i8uIp/C/ASqiIGUeeKQtX0/IR3qCXyThP/dbCiHrF3v1cuhBOHY8CLVg==
   113  -----END PUBLIC KEY-----`
   114  
   115  // Obtained by:
   116  //
   117  //  1. Serializing ecdsaPublicKey as DER
   118  //  2. Taking the SHA256 of the DER bytes
   119  //  3. URLSafe Base64-encoding the sha bytes
   120  const ecdsaKeyID = "SoABiieYuNx4UdqYvZRVeuC6SihxgLrhLy9peHMHpTc"
   121  
   122  func getPrivateKey(data string) interface{} {
   123  	key, err := keyutil.ParsePrivateKeyPEM([]byte(data))
   124  	if err != nil {
   125  		panic(fmt.Errorf("unexpected error parsing private key: %v", err))
   126  	}
   127  	return key
   128  }
   129  
   130  func getPublicKey(data string) interface{} {
   131  	keys, err := keyutil.ParsePublicKeysPEM([]byte(data))
   132  	if err != nil {
   133  		panic(fmt.Errorf("unexpected error parsing public key: %v", err))
   134  	}
   135  	return keys[0]
   136  }
   137  
   138  func TestTokenGenerateAndValidate(t *testing.T) {
   139  	expectedUserName := "system:serviceaccount:test:my-service-account"
   140  	expectedUserUID := "12345"
   141  
   142  	// Related API objects
   143  	serviceAccount := &v1.ServiceAccount{
   144  		ObjectMeta: metav1.ObjectMeta{
   145  			Name:      "my-service-account",
   146  			UID:       "12345",
   147  			Namespace: "test",
   148  		},
   149  	}
   150  	rsaSecret := &v1.Secret{
   151  		ObjectMeta: metav1.ObjectMeta{
   152  			Name:      "my-rsa-secret",
   153  			Namespace: "test",
   154  		},
   155  	}
   156  	invalidAutoSecret := &v1.Secret{
   157  		ObjectMeta: metav1.ObjectMeta{
   158  			Name:      "my-rsa-secret",
   159  			Namespace: "test",
   160  			Labels: map[string]string{
   161  				"kubernetes.io/legacy-token-invalid-since": "2022-12-20",
   162  			},
   163  		},
   164  	}
   165  	ecdsaSecret := &v1.Secret{
   166  		ObjectMeta: metav1.ObjectMeta{
   167  			Name:      "my-ecdsa-secret",
   168  			Namespace: "test",
   169  		},
   170  	}
   171  
   172  	// Generate the RSA token
   173  	rsaGenerator, err := serviceaccount.JWTTokenGenerator(serviceaccount.LegacyIssuer, getPrivateKey(rsaPrivateKey))
   174  	if err != nil {
   175  		t.Fatalf("error making generator: %v", err)
   176  	}
   177  	rsaToken, err := rsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
   178  	if err != nil {
   179  		t.Fatalf("error generating token: %v", err)
   180  	}
   181  	if len(rsaToken) == 0 {
   182  		t.Fatalf("no token generated")
   183  	}
   184  	rsaSecret.Data = map[string][]byte{
   185  		"token": []byte(rsaToken),
   186  	}
   187  
   188  	checkJSONWebSignatureHasKeyID(t, rsaToken, rsaKeyID)
   189  
   190  	// Generate RSA token with invalidAutoSecret
   191  	invalidAutoSecretToken, err := rsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *invalidAutoSecret))
   192  	if err != nil {
   193  		t.Fatalf("error generating token: %v", err)
   194  	}
   195  	if len(invalidAutoSecretToken) == 0 {
   196  		t.Fatalf("no token generated")
   197  	}
   198  	invalidAutoSecret.Data = map[string][]byte{
   199  		"token": []byte(invalidAutoSecretToken),
   200  	}
   201  
   202  	checkJSONWebSignatureHasKeyID(t, invalidAutoSecretToken, rsaKeyID)
   203  
   204  	// Generate the ECDSA token
   205  	ecdsaToken := generateECDSAToken(t, serviceaccount.LegacyIssuer, serviceAccount, ecdsaSecret)
   206  
   207  	ecdsaSecret.Data = map[string][]byte{
   208  		"token": []byte(ecdsaToken),
   209  	}
   210  
   211  	checkJSONWebSignatureHasKeyID(t, ecdsaToken, ecdsaKeyID)
   212  
   213  	ecdsaTokenMalformedIss := generateECDSATokenWithMalformedIss(t, serviceAccount, ecdsaSecret)
   214  
   215  	// Generate signer with same keys as RSA signer but different unrecognized issuer
   216  	badIssuerGenerator, err := serviceaccount.JWTTokenGenerator("foo", getPrivateKey(rsaPrivateKey))
   217  	if err != nil {
   218  		t.Fatalf("error making generator: %v", err)
   219  	}
   220  	badIssuerToken, err := badIssuerGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
   221  	if err != nil {
   222  		t.Fatalf("error generating token: %v", err)
   223  	}
   224  
   225  	// Generate signer with same keys as RSA signer but different recognized issuer
   226  	differentIssuerGenerator, err := serviceaccount.JWTTokenGenerator("bar", getPrivateKey(rsaPrivateKey))
   227  	if err != nil {
   228  		t.Fatalf("error making generator: %v", err)
   229  	}
   230  	differentIssuerToken, err := differentIssuerGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *rsaSecret))
   231  	if err != nil {
   232  		t.Fatalf("error generating token: %v", err)
   233  	}
   234  
   235  	testCases := map[string]struct {
   236  		Client clientset.Interface
   237  		Keys   []interface{}
   238  		Token  string
   239  
   240  		ExpectedErr      bool
   241  		ExpectedOK       bool
   242  		ExpectedUserName string
   243  		ExpectedUserUID  string
   244  		ExpectedGroups   []string
   245  	}{
   246  		"no keys": {
   247  			Token:       rsaToken,
   248  			Client:      nil,
   249  			Keys:        []interface{}{},
   250  			ExpectedErr: false,
   251  			ExpectedOK:  false,
   252  		},
   253  		"invalid keys (rsa)": {
   254  			Token:       rsaToken,
   255  			Client:      nil,
   256  			Keys:        []interface{}{getPublicKey(otherPublicKey), getPublicKey(ecdsaPublicKey)},
   257  			ExpectedErr: true,
   258  			ExpectedOK:  false,
   259  		},
   260  		"invalid keys (ecdsa)": {
   261  			Token:       ecdsaToken,
   262  			Client:      nil,
   263  			Keys:        []interface{}{getPublicKey(otherPublicKey), getPublicKey(rsaPublicKey)},
   264  			ExpectedErr: true,
   265  			ExpectedOK:  false,
   266  		},
   267  		"valid key (rsa)": {
   268  			Token:            rsaToken,
   269  			Client:           nil,
   270  			Keys:             []interface{}{getPublicKey(rsaPublicKey)},
   271  			ExpectedErr:      false,
   272  			ExpectedOK:       true,
   273  			ExpectedUserName: expectedUserName,
   274  			ExpectedUserUID:  expectedUserUID,
   275  			ExpectedGroups:   []string{"system:serviceaccounts", "system:serviceaccounts:test"},
   276  		},
   277  		"valid key, invalid issuer (rsa)": {
   278  			Token:       badIssuerToken,
   279  			Client:      nil,
   280  			Keys:        []interface{}{getPublicKey(rsaPublicKey)},
   281  			ExpectedErr: false,
   282  			ExpectedOK:  false,
   283  		},
   284  		"valid key, different issuer (rsa)": {
   285  			Token:            differentIssuerToken,
   286  			Client:           nil,
   287  			Keys:             []interface{}{getPublicKey(rsaPublicKey)},
   288  			ExpectedErr:      false,
   289  			ExpectedOK:       true,
   290  			ExpectedUserName: expectedUserName,
   291  			ExpectedUserUID:  expectedUserUID,
   292  			ExpectedGroups:   []string{"system:serviceaccounts", "system:serviceaccounts:test"},
   293  		},
   294  		"valid key (ecdsa)": {
   295  			Token:            ecdsaToken,
   296  			Client:           nil,
   297  			Keys:             []interface{}{getPublicKey(ecdsaPublicKey)},
   298  			ExpectedErr:      false,
   299  			ExpectedOK:       true,
   300  			ExpectedUserName: expectedUserName,
   301  			ExpectedUserUID:  expectedUserUID,
   302  			ExpectedGroups:   []string{"system:serviceaccounts", "system:serviceaccounts:test"},
   303  		},
   304  		"rotated keys (rsa)": {
   305  			Token:            rsaToken,
   306  			Client:           nil,
   307  			Keys:             []interface{}{getPublicKey(otherPublicKey), getPublicKey(ecdsaPublicKey), getPublicKey(rsaPublicKey)},
   308  			ExpectedErr:      false,
   309  			ExpectedOK:       true,
   310  			ExpectedUserName: expectedUserName,
   311  			ExpectedUserUID:  expectedUserUID,
   312  			ExpectedGroups:   []string{"system:serviceaccounts", "system:serviceaccounts:test"},
   313  		},
   314  		"rotated keys (ecdsa)": {
   315  			Token:            ecdsaToken,
   316  			Client:           nil,
   317  			Keys:             []interface{}{getPublicKey(otherPublicKey), getPublicKey(rsaPublicKey), getPublicKey(ecdsaPublicKey)},
   318  			ExpectedErr:      false,
   319  			ExpectedOK:       true,
   320  			ExpectedUserName: expectedUserName,
   321  			ExpectedUserUID:  expectedUserUID,
   322  			ExpectedGroups:   []string{"system:serviceaccounts", "system:serviceaccounts:test"},
   323  		},
   324  		"valid lookup": {
   325  			Token:            rsaToken,
   326  			Client:           fake.NewSimpleClientset(serviceAccount, rsaSecret, ecdsaSecret),
   327  			Keys:             []interface{}{getPublicKey(rsaPublicKey)},
   328  			ExpectedErr:      false,
   329  			ExpectedOK:       true,
   330  			ExpectedUserName: expectedUserName,
   331  			ExpectedUserUID:  expectedUserUID,
   332  			ExpectedGroups:   []string{"system:serviceaccounts", "system:serviceaccounts:test"},
   333  		},
   334  		"invalid secret lookup": {
   335  			Token:       rsaToken,
   336  			Client:      fake.NewSimpleClientset(serviceAccount),
   337  			Keys:        []interface{}{getPublicKey(rsaPublicKey)},
   338  			ExpectedErr: true,
   339  			ExpectedOK:  false,
   340  		},
   341  		"invalid serviceaccount lookup": {
   342  			Token:       rsaToken,
   343  			Client:      fake.NewSimpleClientset(rsaSecret, ecdsaSecret),
   344  			Keys:        []interface{}{getPublicKey(rsaPublicKey)},
   345  			ExpectedErr: true,
   346  			ExpectedOK:  false,
   347  		},
   348  		"secret is marked as invalid": {
   349  			Token:       invalidAutoSecretToken,
   350  			Client:      fake.NewSimpleClientset(serviceAccount, invalidAutoSecret),
   351  			Keys:        []interface{}{getPublicKey(rsaPublicKey)},
   352  			ExpectedErr: true,
   353  		},
   354  		"malformed iss": {
   355  			Token:       ecdsaTokenMalformedIss,
   356  			Client:      nil,
   357  			Keys:        []interface{}{getPublicKey(ecdsaPublicKey)},
   358  			ExpectedErr: false,
   359  			ExpectedOK:  false,
   360  		},
   361  	}
   362  
   363  	for k, tc := range testCases {
   364  		auds := authenticator.Audiences{"api"}
   365  		getter := serviceaccountcontroller.NewGetterFromClient(
   366  			tc.Client,
   367  			v1listers.NewSecretLister(newIndexer(func(namespace, name string) (interface{}, error) {
   368  				return tc.Client.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{})
   369  			})),
   370  			v1listers.NewServiceAccountLister(newIndexer(func(namespace, name string) (interface{}, error) {
   371  				return tc.Client.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), name, metav1.GetOptions{})
   372  			})),
   373  			v1listers.NewPodLister(newIndexer(func(namespace, name string) (interface{}, error) {
   374  				return tc.Client.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
   375  			})),
   376  			v1listers.NewNodeLister(newIndexer(func(_, name string) (interface{}, error) {
   377  				return tc.Client.CoreV1().Nodes().Get(context.TODO(), name, metav1.GetOptions{})
   378  			})),
   379  		)
   380  		var secretsWriter typedv1core.SecretsGetter
   381  		if tc.Client != nil {
   382  			secretsWriter = tc.Client.CoreV1()
   383  		}
   384  		validator, err := serviceaccount.NewLegacyValidator(tc.Client != nil, getter, secretsWriter)
   385  		if err != nil {
   386  			t.Fatalf("While creating legacy validator, err: %v", err)
   387  		}
   388  		authn := serviceaccount.JWTTokenAuthenticator([]string{serviceaccount.LegacyIssuer, "bar"}, tc.Keys, auds, validator)
   389  
   390  		// An invalid, non-JWT token should always fail
   391  		ctx := authenticator.WithAudiences(context.Background(), auds)
   392  		if _, ok, err := authn.AuthenticateToken(ctx, "invalid token"); err != nil || ok {
   393  			t.Errorf("%s: Expected err=nil, ok=false for non-JWT token", k)
   394  			continue
   395  		}
   396  
   397  		resp, ok, err := authn.AuthenticateToken(ctx, tc.Token)
   398  		if (err != nil) != tc.ExpectedErr {
   399  			t.Errorf("%s: Expected error=%v, got %v", k, tc.ExpectedErr, err)
   400  			continue
   401  		}
   402  
   403  		if ok != tc.ExpectedOK {
   404  			t.Errorf("%s: Expected ok=%v, got %v", k, tc.ExpectedOK, ok)
   405  			continue
   406  		}
   407  
   408  		if err != nil || !ok {
   409  			continue
   410  		}
   411  
   412  		if resp.User.GetName() != tc.ExpectedUserName {
   413  			t.Errorf("%s: Expected username=%v, got %v", k, tc.ExpectedUserName, resp.User.GetName())
   414  			continue
   415  		}
   416  		if resp.User.GetUID() != tc.ExpectedUserUID {
   417  			t.Errorf("%s: Expected userUID=%v, got %v", k, tc.ExpectedUserUID, resp.User.GetUID())
   418  			continue
   419  		}
   420  		if !reflect.DeepEqual(resp.User.GetGroups(), tc.ExpectedGroups) {
   421  			t.Errorf("%s: Expected groups=%v, got %v", k, tc.ExpectedGroups, resp.User.GetGroups())
   422  			continue
   423  		}
   424  	}
   425  }
   426  
   427  func checkJSONWebSignatureHasKeyID(t *testing.T, jwsString string, expectedKeyID string) {
   428  	jws, err := jose.ParseSigned(jwsString)
   429  	if err != nil {
   430  		t.Fatalf("Error checking for key ID: couldn't parse token: %v", err)
   431  	}
   432  
   433  	if jws.Signatures[0].Header.KeyID != expectedKeyID {
   434  		t.Errorf("Token %q has the wrong KeyID (got %q, want %q)", jwsString, jws.Signatures[0].Header.KeyID, expectedKeyID)
   435  	}
   436  }
   437  
   438  func newIndexer(get func(namespace, name string) (interface{}, error)) cache.Indexer {
   439  	return &fakeIndexer{get: get}
   440  }
   441  
   442  type fakeIndexer struct {
   443  	cache.Indexer
   444  	get func(namespace, name string) (interface{}, error)
   445  }
   446  
   447  func (f *fakeIndexer) GetByKey(key string) (interface{}, bool, error) {
   448  	parts := strings.SplitN(key, "/", 2)
   449  	namespace := parts[0]
   450  	name := ""
   451  	// implies the key does not contain a / (this is a cluster-scoped object)
   452  	if len(parts) == 1 {
   453  		name = parts[0]
   454  		namespace = ""
   455  	}
   456  	if len(parts) == 2 {
   457  		name = parts[1]
   458  	}
   459  	obj, err := f.get(namespace, name)
   460  	return obj, err == nil, err
   461  }
   462  
   463  func generateECDSAToken(t *testing.T, iss string, serviceAccount *v1.ServiceAccount, ecdsaSecret *v1.Secret) string {
   464  	t.Helper()
   465  
   466  	ecdsaGenerator, err := serviceaccount.JWTTokenGenerator(iss, getPrivateKey(ecdsaPrivateKey))
   467  	if err != nil {
   468  		t.Fatalf("error making generator: %v", err)
   469  	}
   470  	ecdsaToken, err := ecdsaGenerator.GenerateToken(serviceaccount.LegacyClaims(*serviceAccount, *ecdsaSecret))
   471  	if err != nil {
   472  		t.Fatalf("error generating token: %v", err)
   473  	}
   474  	if len(ecdsaToken) == 0 {
   475  		t.Fatalf("no token generated")
   476  	}
   477  
   478  	return ecdsaToken
   479  }
   480  
   481  func generateECDSATokenWithMalformedIss(t *testing.T, serviceAccount *v1.ServiceAccount, ecdsaSecret *v1.Secret) string {
   482  	t.Helper()
   483  
   484  	ecdsaToken := generateECDSAToken(t, "panda", serviceAccount, ecdsaSecret)
   485  
   486  	ecdsaTokenJWS, err := jose.ParseSigned(ecdsaToken)
   487  	if err != nil {
   488  		t.Fatal(err)
   489  	}
   490  
   491  	dataFullSerialize := map[string]any{}
   492  	if err := json.Unmarshal([]byte(ecdsaTokenJWS.FullSerialize()), &dataFullSerialize); err != nil {
   493  		t.Fatal(err)
   494  	}
   495  
   496  	dataFullSerialize["malformed_iss"] = "." + base64.RawURLEncoding.EncodeToString([]byte(`{"iss":"bar"}`)) + "."
   497  
   498  	out, err := json.Marshal(dataFullSerialize)
   499  	if err != nil {
   500  		t.Fatal(err)
   501  	}
   502  
   503  	return string(out)
   504  }
   505  

View as plain text