github.com/nats-io/jwt/v2@v2.5.6/imports_test.go (about) 1 /* 2 * Copyright 2018-2020 The NATS Authors 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package jwt 17 18 import ( 19 "sort" 20 "strings" 21 "testing" 22 "time" 23 ) 24 25 func TestImportValidation(t *testing.T) { 26 ak := createAccountNKey(t) 27 ak2 := createAccountNKey(t) 28 akp := publicKey(ak, t) 29 akp2 := publicKey(ak2, t) 30 i := &Import{Subject: "test", Account: akp2, LocalSubject: "bar", Type: Stream} 31 32 vr := CreateValidationResults() 33 i.Validate("", vr) 34 35 if !vr.IsEmpty() { 36 t.Errorf("imports should not generate an issue") 37 } 38 39 vr = CreateValidationResults() 40 i.Validate("", vr) 41 42 if !vr.IsEmpty() { 43 t.Errorf("imports should not generate an issue") 44 } 45 46 activation := NewActivationClaims(akp) 47 activation.Expires = time.Now().Add(time.Hour).UTC().Unix() 48 49 activation.ImportSubject = "test" 50 activation.ImportType = Stream 51 actJWT := encode(activation, ak2, t) 52 53 i.Token = actJWT 54 vr = CreateValidationResults() 55 i.Validate(akp, vr) 56 57 if !vr.IsEmpty() { 58 t.Errorf("imports with token should be valid") 59 } 60 } 61 62 func TestImportValidationExpiredToken(t *testing.T) { 63 ak := createAccountNKey(t) 64 ak2 := createAccountNKey(t) 65 akp := publicKey(ak, t) 66 akp2 := publicKey(ak2, t) 67 i := &Import{Subject: "test", Account: akp2, LocalSubject: "bar", Type: Stream} 68 // test success, expiration is not checked 69 activation := NewActivationClaims(akp) 70 activation.Expires = time.Now().Add(-time.Hour).UTC().Unix() 71 activation.ImportSubject = "test" 72 activation.ImportType = Stream 73 i.Token = encode(activation, ak2, t) 74 vr := CreateValidationResults() 75 i.Validate(akp, vr) 76 if !vr.IsEmpty() { 77 t.Errorf("Expired token should not trigger a validation issue") 78 } 79 // test failure, different issuer 80 ak3 := createAccountNKey(t) 81 activation = NewActivationClaims(akp) 82 activation.Expires = time.Now().Add(-time.Hour).UTC().Unix() 83 activation.ImportSubject = "test" 84 activation.ImportType = Stream 85 i.Token = encode(activation, ak3, t) 86 vr = CreateValidationResults() 87 i.Validate(akp, vr) 88 if vr.IsEmpty() { 89 t.Errorf("Issuer mismatch must trigger a validation issue") 90 } 91 } 92 93 func TestImportValidationDifferentAccount(t *testing.T) { 94 ak := createAccountNKey(t) 95 ak2 := createAccountNKey(t) 96 akp := publicKey(ak, t) 97 akp2 := publicKey(ak2, t) 98 otherAccount := publicKey(createAccountNKey(t), t) 99 i := &Import{Subject: "test", Account: akp2, To: "bar", Type: Stream} 100 101 activation := NewActivationClaims(otherAccount) 102 activation.Expires = time.Now().Add(-time.Hour).UTC().Unix() 103 activation.ImportSubject = "test" 104 activation.ImportType = Stream 105 i.Token = encode(activation, ak2, t) 106 vr := CreateValidationResults() 107 i.Validate(akp, vr) 108 if vr.IsEmpty() || !vr.IsBlocking(false) { 109 t.Errorf("Expired import needs to result in a time check error") 110 } 111 } 112 113 func TestImportValidationSigningKey(t *testing.T) { 114 ak := createAccountNKey(t) 115 ak2 := createAccountNKey(t) 116 ak2Sk := createAccountNKey(t) 117 akp := publicKey(ak, t) 118 akp2 := publicKey(ak2, t) 119 i := &Import{Subject: "test", Account: akp2, LocalSubject: "bar", Type: Stream} 120 121 activation := NewActivationClaims(akp) 122 activation.Expires = time.Now().Add(time.Hour).UTC().Unix() 123 activation.ImportSubject = "test" 124 activation.ImportType = Stream 125 activation.IssuerAccount = akp2 126 i.Token = encode(activation, ak2Sk, t) 127 vr := CreateValidationResults() 128 i.Validate(akp, vr) 129 if !vr.IsEmpty() { 130 t.Errorf("Expired import needs to not result in an error") 131 } 132 } 133 134 func TestInvalidImportType(t *testing.T) { 135 ak := createAccountNKey(t) 136 akp := publicKey(ak, t) 137 i := &Import{Subject: "foo", Account: akp, To: "bar", Type: Unknown} 138 139 vr := CreateValidationResults() 140 i.Validate("", vr) 141 142 if vr.IsEmpty() { 143 t.Errorf("imports without token or url should warn the caller") 144 } 145 146 if !vr.IsBlocking(true) { 147 t.Errorf("invalid type is blocking") 148 } 149 } 150 151 func TestInvalidImportToken(t *testing.T) { 152 ak := createAccountNKey(t) 153 akp := publicKey(ak, t) 154 i := &Import{Subject: "foo", Account: akp, Token: "bad token", To: "bar", Type: Stream} 155 156 vr := CreateValidationResults() 157 i.Validate("", vr) 158 159 if vr.IsEmpty() { 160 t.Errorf("imports with a bad token or url should cause an error") 161 } 162 163 if !vr.IsBlocking(false) { 164 t.Errorf("invalid type should be blocking") 165 } 166 } 167 168 func TestInvalidImportURL(t *testing.T) { 169 ak := createAccountNKey(t) 170 akp := publicKey(ak, t) 171 i := &Import{Subject: "foo", Account: akp, Token: "foo://bad-token-url", To: "bar", Type: Stream} 172 173 vr := CreateValidationResults() 174 i.Validate("", vr) 175 176 if vr.IsEmpty() { 177 t.Errorf("imports with a bad token or url should warn the caller") 178 } 179 180 if !vr.IsBlocking(true) { 181 t.Errorf("invalid type should be blocking") 182 } 183 } 184 185 func TestInvalidImportTokenValuesValidation(t *testing.T) { 186 ak := createAccountNKey(t) 187 ak2 := createAccountNKey(t) 188 akp := publicKey(ak, t) 189 akp2 := publicKey(ak2, t) 190 i := &Import{Subject: "test", Account: akp2, LocalSubject: "bar", Type: Service} 191 192 vr := CreateValidationResults() 193 i.Validate("", vr) 194 195 if !vr.IsEmpty() { 196 t.Errorf("imports should not generate an issue") 197 } 198 199 i.Type = Service 200 vr = CreateValidationResults() 201 i.Validate("", vr) 202 203 if !vr.IsEmpty() { 204 t.Errorf("imports should not generate an issue") 205 } 206 207 activation := NewActivationClaims(akp) 208 activation.Expires = time.Now().Add(time.Hour).UTC().Unix() 209 210 activation.ImportSubject = "test" 211 activation.ImportType = Service 212 actJWT := encode(activation, ak2, t) 213 214 i.Token = actJWT 215 vr = CreateValidationResults() 216 i.Validate(akp, vr) 217 218 if !vr.IsEmpty() { 219 t.Errorf("imports with token should be valid") 220 } 221 222 actJWT = encode(activation, ak, t) // wrong issuer 223 i.Token = actJWT 224 vr = CreateValidationResults() 225 i.Validate(akp, vr) 226 227 if vr.IsEmpty() { 228 t.Errorf("imports with wrong issuer") 229 } 230 231 activation.Subject = akp2 // wrong subject 232 actJWT = encode(activation, ak2, t) // right issuer 233 i.Token = actJWT 234 vr = CreateValidationResults() 235 i.Validate(akp, vr) 236 237 if vr.IsEmpty() { 238 t.Errorf("imports with wrong issuer") 239 } 240 } 241 func TestMissingAccountInImport(t *testing.T) { 242 i := &Import{Subject: "foo", LocalSubject: "bar", Type: Stream} 243 244 vr := CreateValidationResults() 245 i.Validate("", vr) 246 247 if len(vr.Issues) != 1 { 248 t.Errorf("expected only one issue") 249 } 250 251 if !vr.IsBlocking(true) { 252 t.Errorf("Missing Account is blocking") 253 } 254 } 255 256 func TestServiceImportWithWildcard(t *testing.T) { 257 i := &Import{Subject: "foo.>", Account: publicKey(createAccountNKey(t), t), LocalSubject: "bar.>", Type: Service} 258 259 vr := CreateValidationResults() 260 i.Validate("", vr) 261 262 if !vr.IsEmpty() { 263 t.Errorf("expected no issue") 264 } 265 266 i.Subject = ">" 267 vr = CreateValidationResults() 268 i.Validate("", vr) 269 270 if !vr.IsEmpty() { 271 t.Errorf("expected no issue") 272 } 273 } 274 275 func TestStreamImportWithWildcardPrefix(t *testing.T) { 276 i := &Import{Subject: "foo.>", Account: publicKey(createAccountNKey(t), t), LocalSubject: "bar.>", Type: Stream} 277 278 vr := CreateValidationResults() 279 i.Validate("", vr) 280 281 if !vr.IsEmpty() { 282 t.Errorf("expected no issue") 283 } 284 285 i.Subject = ">" 286 vr = CreateValidationResults() 287 i.Validate("", vr) 288 289 if !vr.IsEmpty() { 290 t.Errorf("expected no issue") 291 } 292 } 293 294 func TestStreamImportInformationSharing(t *testing.T) { 295 ak := createAccountNKey(t) 296 akp := publicKey(ak, t) 297 // broken import share won't work with streams 298 i := &Import{Subject: "foo", Account: akp, Type: Stream, Share: true} 299 vr := CreateValidationResults() 300 i.Validate("", vr) 301 302 if len(vr.Issues) != 1 { 303 t.Errorf("should have registered 1 issues with this import, got %d", len(vr.Issues)) 304 } 305 if !vr.IsBlocking(true) { 306 t.Fatalf("issue is expected to be blocking") 307 } 308 // import share will work with service 309 i.Type = Service 310 vr = CreateValidationResults() 311 i.Validate("", vr) 312 313 if len(vr.Issues) != 0 { 314 t.Errorf("should have registered 0 issues with this import, got %d", len(vr.Issues)) 315 } 316 } 317 318 func TestImportsValidation(t *testing.T) { 319 ak := createAccountNKey(t) 320 akp := publicKey(ak, t) 321 i := &Import{Subject: "foo", Account: akp, LocalSubject: "bar", Type: Stream} 322 i2 := &Import{Subject: "foo.*", Account: akp, LocalSubject: "bar.*", Type: Service} 323 324 imports := &Imports{} 325 imports.Add(i, i2) 326 327 vr := CreateValidationResults() 328 imports.Validate("", vr) 329 330 if !vr.IsEmpty() { 331 t.Errorf("no issues expected") 332 } 333 } 334 335 func TestImportsLocalSubjectExclusiveTo(t *testing.T) { 336 ak := createAccountNKey(t) 337 akp := publicKey(ak, t) 338 i := &Import{Subject: "foo", Account: akp, LocalSubject: "bar", Type: Stream} 339 i2 := &Import{Subject: "foo", Account: akp, LocalSubject: "bar", Type: Service} 340 341 imports := &Imports{} 342 imports.Add(i, i2) 343 344 vr := CreateValidationResults() 345 imports.Validate("", vr) 346 347 if !vr.IsEmpty() { 348 t.Errorf("no issues expected") 349 } 350 351 i.To = "bar" 352 i2.To = "bar" 353 imports = &Imports{} 354 imports.Add(i, i2) 355 356 vr = CreateValidationResults() 357 imports.Validate("", vr) 358 359 if vr.IsEmpty() { 360 t.Errorf("issues expected") 361 } 362 if !vr.IsBlocking(false) { 363 t.Errorf("issues expected to be blocking") 364 } 365 } 366 367 func TestImportsLocalSubjectVariants(t *testing.T) { 368 ak := createAccountNKey(t) 369 akp := publicKey(ak, t) 370 imports := &Imports{} 371 imports.Add( 372 &Import{Subject: "foo.*.bar.*.>", Account: akp, LocalSubject: "my.$2.$1.>", Type: Stream}, 373 &Import{Subject: "baz.*.bar.*.>", Account: akp, LocalSubject: "bar.*.*.>", Type: Service}, 374 &Import{Subject: "baz.*", Account: akp, LocalSubject: "my.$1", Type: Stream}, 375 &Import{Subject: "bar.*", Account: akp, LocalSubject: "baz.*", Type: Service}, 376 &Import{Subject: "biz.*.*.*", Account: akp, LocalSubject: "buz.*.*.*", Type: Service}) 377 vr := CreateValidationResults() 378 imports.Validate("", vr) 379 if !vr.IsEmpty() { 380 t.Errorf("no issues expected") 381 } 382 } 383 384 func TestImportSubjectValidation(t *testing.T) { 385 ak := createAccountNKey(t) 386 akp := publicKey(ak, t) 387 activation := NewActivationClaims(akp) 388 activation.Expires = time.Now().Add(time.Hour).UTC().Unix() 389 activation.ImportSubject = "one.*" 390 activation.ImportType = Stream 391 392 ak2 := createAccountNKey(t) 393 akp2 := publicKey(ak2, t) 394 i := &Import{Subject: "one.two", Account: akp2, LocalSubject: "bar", Type: Stream} 395 396 i.Token = encode(activation, ak2, t) 397 vr := CreateValidationResults() 398 i.Validate(akp, vr) 399 400 if !vr.IsEmpty() { 401 t.Log(vr.Issues[0].Description) 402 t.Errorf("imports with valid contains subject should be valid") 403 } 404 405 activation.ImportSubject = "two" 406 activation.ImportType = Stream 407 i.Token = encode(activation, ak2, t) 408 vr = CreateValidationResults() 409 i.Validate(akp, vr) 410 411 if vr.IsEmpty() { 412 t.Errorf("imports with non-contains subject should be not valid") 413 } 414 415 activation.ImportSubject = ">" 416 activation.ImportType = Stream 417 i.Token = encode(activation, ak2, t) 418 vr = CreateValidationResults() 419 i.Validate(akp, vr) 420 421 if !vr.IsEmpty() { 422 t.Errorf("imports with valid contains subject should be valid") 423 } 424 } 425 426 func TestImportServiceDoubleToSubjectsValidation(t *testing.T) { 427 akp := createAccountNKey(t) 428 akp2 := createAccountNKey(t) 429 apk := publicKey(akp, t) 430 apk2 := publicKey(akp2, t) 431 432 account := NewAccountClaims(apk) 433 434 i := &Import{Subject: "one.two", Account: apk2, To: "foo.bar", Type: Service} 435 account.Imports.Add(i) 436 437 vr := CreateValidationResults() 438 account.Validate(vr) 439 440 if vr.IsBlocking(true) { 441 t.Fatalf("Expected no blocking validation errors") 442 } 443 444 i2 := &Import{Subject: "two.three", Account: apk2, To: "foo.bar", Type: Service} 445 account.Imports.Add(i2) 446 447 vr = CreateValidationResults() 448 account.Validate(vr) 449 450 if !vr.IsBlocking(true) { 451 t.Fatalf("Expected multiple import 'to' subjects to produce an error") 452 } 453 } 454 455 func TestWildcard(t *testing.T) { 456 account := NewAccountClaims(publicKey(createAccountNKey(t), t)) 457 458 i := &Import{Subject: ">", Account: publicKey(createAccountNKey(t), t), To: "foo.bar", Type: Service} 459 account.Imports.Add(i) 460 461 vr := CreateValidationResults() 462 account.Validate(vr) 463 464 if vr.IsBlocking(true) { 465 t.Fatalf("Expected no blocking validation errors") 466 } 467 } 468 469 func TestImport_Sorting(t *testing.T) { 470 var imports Imports 471 pk := publicKey(createAccountNKey(t), t) 472 imports.Add(&Import{Subject: "x", Type: Service, Account: pk}) 473 imports.Add(&Import{Subject: "z", Type: Service, Account: pk}) 474 imports.Add(&Import{Subject: "y", Type: Service, Account: pk}) 475 if imports[0].Subject != "x" { 476 t.Fatal("added import not in expected order") 477 } 478 sort.Sort(imports) 479 if imports[0].Subject != "x" && imports[1].Subject != "y" && imports[2].Subject != "z" { 480 t.Fatal("imports not sorted") 481 } 482 } 483 484 func TestImports_Validate(t *testing.T) { 485 var imports Imports 486 pk := publicKey(createAccountNKey(t), t) 487 imports.Add(&Import{Subject: "x", LocalSubject: "foo", Type: Service, Account: pk}) 488 imports.Add(&Import{Subject: "z.*", LocalSubject: "*", Type: Service, Account: pk}) 489 imports.Add(&Import{Subject: "y.>", LocalSubject: ">", Type: Service, Account: pk}) 490 vr := ValidationResults{} 491 imports.Validate("", &vr) 492 if len(vr.Issues) != 3 || !vr.IsBlocking(false) { 493 t.Fatal("expected 3 blocking issues") 494 } 495 for _, v := range vr.Issues { 496 if !strings.HasPrefix(v.Description, "overlapping subject namespace") { 497 t.Fatalf("Expected every error to contain: overlapping subject namespace") 498 } 499 } 500 } 501 502 func TestImportAllowTrace(t *testing.T) { 503 ak2 := createAccountNKey(t) 504 akp2 := publicKey(ak2, t) 505 506 // AllowTrace is only applicable to StreamImport 507 i := &Import{Subject: "foo", Account: akp2, Type: Service, AllowTrace: true} 508 vr := CreateValidationResults() 509 i.Validate("", vr) 510 if vr.IsEmpty() { 511 t.Fatalf("AllowTrace on service should have an validation issue") 512 } 513 issue := vr.Issues[0] 514 if !strings.Contains(issue.Description, "AllowTrace only valid for stream import") { 515 t.Fatalf("AllowTrace should be valid only for stream import, got %q", issue.Description) 516 } 517 518 i.Type = Stream 519 vr = CreateValidationResults() 520 i.Validate("", vr) 521 if !vr.IsEmpty() { 522 t.Fatalf("validation should have been ok, got %+v", vr.Issues) 523 } 524 }