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  }