k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/serviceaccount/jwt_test.go (about) 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 }