github.com/nats-io/jwt/v2@v2.5.6/v1compat/activation_claims_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  	"testing"
    20  	"time"
    21  
    22  	"github.com/nats-io/nkeys"
    23  )
    24  
    25  func TestNewActivationClaims(t *testing.T) {
    26  	okp := createOperatorNKey(t)
    27  	akp := createAccountNKey(t)
    28  	apk := publicKey(akp, t)
    29  
    30  	activation := NewActivationClaims(apk)
    31  	activation.Max = 1024 * 1024
    32  	activation.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
    33  	activation.Limits.Max = 10
    34  	activation.Limits.Payload = 10
    35  	activation.Limits.Src = "192.0.2.0/24"
    36  
    37  	activation.ImportSubject = "foo"
    38  	activation.Name = "Foo"
    39  	activation.ImportType = Stream
    40  
    41  	vr := CreateValidationResults()
    42  	activation.Validate(vr)
    43  
    44  	if !vr.IsEmpty() || vr.IsBlocking(true) {
    45  		t.Error("valid activation should pass validation")
    46  	}
    47  
    48  	actJwt := encode(activation, okp, t)
    49  
    50  	activation2, err := DecodeActivationClaims(actJwt)
    51  	if err != nil {
    52  		t.Fatal("failed to decode activation", err)
    53  	}
    54  
    55  	AssertEquals(activation.String(), activation2.String(), t)
    56  
    57  	AssertEquals(activation.Claims() != nil, true, t)
    58  	AssertEquals(activation.Payload() != nil, true, t)
    59  }
    60  
    61  func TestInvalidActivationTargets(t *testing.T) {
    62  	type kpInputs struct {
    63  		name string
    64  		kp   nkeys.KeyPair
    65  		ok   bool
    66  	}
    67  
    68  	inputs := []kpInputs{
    69  		{"account", createAccountNKey(t), true},
    70  		{"cluster", createClusterNKey(t), false},
    71  		{"operator", createOperatorNKey(t), false},
    72  		{"server", createServerNKey(t), false},
    73  		{"user", createUserNKey(t), false},
    74  	}
    75  
    76  	for _, i := range inputs {
    77  		c := NewActivationClaims(publicKey(i.kp, t))
    78  		_, err := c.Encode(createOperatorNKey(t))
    79  		if i.ok && err != nil {
    80  			t.Fatalf("unexpected error for %q: %v", i.name, err)
    81  		}
    82  		if !i.ok && err == nil {
    83  			t.Logf("should have failed to encode user with with %q subject", i.name)
    84  			t.Fail()
    85  		}
    86  	}
    87  }
    88  
    89  func TestInvalidActivationClaimIssuer(t *testing.T) {
    90  	akp := createAccountNKey(t)
    91  	ac := NewActivationClaims(publicKey(akp, t))
    92  	ac.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
    93  	aJwt := encode(ac, akp, t)
    94  
    95  	temp, err := DecodeGeneric(aJwt)
    96  	if err != nil {
    97  		t.Fatal("failed to decode", err)
    98  	}
    99  
   100  	type kpInputs struct {
   101  		name string
   102  		kp   nkeys.KeyPair
   103  		ok   bool
   104  	}
   105  
   106  	inputs := []kpInputs{
   107  		{"account", createAccountNKey(t), true},
   108  		{"user", createUserNKey(t), false},
   109  		{"operator", createOperatorNKey(t), true},
   110  		{"server", createServerNKey(t), false},
   111  		{"cluster", createClusterNKey(t), false},
   112  	}
   113  
   114  	for _, i := range inputs {
   115  		bad := encode(temp, i.kp, t)
   116  		_, err = DecodeActivationClaims(bad)
   117  		if i.ok && err != nil {
   118  			t.Fatalf("unexpected error for %q: %v", i.name, err)
   119  		}
   120  		if !i.ok && err == nil {
   121  			t.Logf("should have failed to decode account signed by %q", i.name)
   122  			t.Fail()
   123  		}
   124  	}
   125  }
   126  
   127  func TestPublicIsNotValid(t *testing.T) {
   128  	c := NewActivationClaims("public")
   129  	_, err := c.Encode(createOperatorNKey(t))
   130  	if err == nil {
   131  		t.Fatal("should not have encoded public activation anymore")
   132  	}
   133  }
   134  
   135  func TestNilActivationClaim(t *testing.T) {
   136  	v := NewActivationClaims("")
   137  	if v != nil {
   138  		t.Fatal("expected nil user claim")
   139  	}
   140  }
   141  
   142  func TestActivationImportSubjectValidation(t *testing.T) {
   143  	akp := createAccountNKey(t)
   144  	apk := publicKey(akp, t)
   145  	akp2 := createAccountNKey(t)
   146  	apk2 := publicKey(akp2, t)
   147  
   148  	activation := NewActivationClaims(apk)
   149  	activation.Issuer = apk
   150  	activation.Subject = apk2
   151  
   152  	activation.ImportSubject = "foo"
   153  	activation.Name = "Foo"
   154  	activation.ImportType = Stream
   155  
   156  	vr := CreateValidationResults()
   157  	activation.Validate(vr)
   158  
   159  	if !vr.IsEmpty() || vr.IsBlocking(true) {
   160  		t.Error("valid activation should pass validation")
   161  	}
   162  
   163  	activation.ImportType = Service
   164  
   165  	vr = CreateValidationResults()
   166  	activation.Validate(vr)
   167  
   168  	if !vr.IsEmpty() || vr.IsBlocking(true) {
   169  		t.Error("valid activation should pass validation")
   170  	}
   171  
   172  	activation.ImportSubject = "foo.*" // wildcards are bad
   173  
   174  	vr = CreateValidationResults()
   175  	activation.Validate(vr)
   176  
   177  	if vr.IsEmpty() || !vr.IsBlocking(true) {
   178  		t.Error("wildcard service activation should not pass validation")
   179  	}
   180  
   181  	activation.ImportType = Stream // Stream is ok with wildcards
   182  	vr = CreateValidationResults()
   183  	activation.Validate(vr)
   184  
   185  	if !vr.IsEmpty() || vr.IsBlocking(true) {
   186  		t.Error("valid activation should pass validation")
   187  	}
   188  
   189  	activation.ImportSubject = "" // empty strings are bad
   190  
   191  	vr = CreateValidationResults()
   192  	activation.Validate(vr)
   193  
   194  	if vr.IsEmpty() || !vr.IsBlocking(true) {
   195  		t.Error("empty activation should not pass validation")
   196  	}
   197  
   198  	activation.ImportSubject = "foo bar" // spaces are bad
   199  
   200  	vr = CreateValidationResults()
   201  	activation.Validate(vr)
   202  
   203  	if vr.IsEmpty() || !vr.IsBlocking(true) {
   204  		t.Error("spaces in activation should not pass validation")
   205  	}
   206  }
   207  
   208  func TestActivationValidation(t *testing.T) {
   209  	akp := createAccountNKey(t)
   210  	apk := publicKey(akp, t)
   211  	akp2 := createAccountNKey(t)
   212  	apk2 := publicKey(akp2, t)
   213  
   214  	activation := NewActivationClaims(apk)
   215  	activation.Issuer = apk
   216  	activation.Subject = apk2
   217  	activation.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
   218  
   219  	activation.ImportSubject = "foo"
   220  	activation.Name = "Foo"
   221  	activation.ImportType = Stream
   222  
   223  	activation.Limits.Max = 10
   224  	activation.Limits.Payload = 10
   225  	activation.Limits.Src = "192.0.2.0/24"
   226  	activation.Limits.Times = []TimeRange{
   227  		{
   228  			Start: "01:15:00",
   229  			End:   "03:15:00",
   230  		},
   231  		{
   232  			Start: "06:15:00",
   233  			End:   "09:15:00",
   234  		},
   235  	}
   236  
   237  	vr := CreateValidationResults()
   238  	activation.Validate(vr)
   239  
   240  	if !vr.IsEmpty() || vr.IsBlocking(true) {
   241  		t.Error("valid activation should pass validation")
   242  	}
   243  
   244  	activation.ImportSubject = "times.*"
   245  	activation.ImportType = Stream
   246  	activation.Name = "times"
   247  
   248  	vr = CreateValidationResults()
   249  	activation.Validate(vr)
   250  
   251  	if !vr.IsEmpty() || vr.IsBlocking(true) {
   252  		t.Error("valid activation should pass validation")
   253  	}
   254  
   255  	activation.ImportSubject = "other.*"
   256  	activation.ImportType = Stream
   257  	activation.Name = "other"
   258  
   259  	activation.Limits.Max = -1
   260  	vr = CreateValidationResults()
   261  	activation.Validate(vr)
   262  
   263  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
   264  		t.Error("bad limit should be invalid")
   265  	}
   266  
   267  	activation.Limits.Max = 10
   268  	activation.Limits.Payload = -1
   269  	vr = CreateValidationResults()
   270  	activation.Validate(vr)
   271  
   272  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
   273  		t.Error("bad limit should be invalid")
   274  	}
   275  
   276  	activation.Limits.Payload = 10
   277  	activation.Limits.Src = "hello world"
   278  	vr = CreateValidationResults()
   279  	activation.Validate(vr)
   280  
   281  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
   282  		t.Error("bad limit should be invalid")
   283  	}
   284  
   285  	activation.Limits.Payload = 10
   286  	activation.Limits.Src = "hello world"
   287  	vr = CreateValidationResults()
   288  	activation.Validate(vr)
   289  
   290  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
   291  		t.Error("bad limit should be invalid")
   292  	}
   293  
   294  	tr := TimeRange{
   295  		Start: "hello",
   296  		End:   "03:15:00",
   297  	}
   298  	activation.Limits.Src = "192.0.2.0/24"
   299  	activation.Limits.Times = append(activation.Limits.Times, tr)
   300  	vr = CreateValidationResults()
   301  	activation.Validate(vr)
   302  
   303  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
   304  		t.Error("bad limit should be invalid")
   305  	}
   306  }
   307  
   308  func TestActivationHashIDLimits(t *testing.T) {
   309  	akp := createAccountNKey(t)
   310  	apk := publicKey(akp, t)
   311  	akp2 := createAccountNKey(t)
   312  	apk2 := publicKey(akp2, t)
   313  
   314  	activation := NewActivationClaims(apk)
   315  	activation.Issuer = apk
   316  	activation.Subject = apk2
   317  
   318  	_, err := activation.HashID()
   319  	if err == nil {
   320  		t.Fatal("activation without subject should fail to hash")
   321  	}
   322  
   323  	activation.ImportSubject = "times.*"
   324  	activation.ImportType = Stream
   325  	activation.Name = "times"
   326  
   327  	hash, err := activation.HashID()
   328  	if err != nil {
   329  		t.Fatalf("activation with subject should hash %v", err)
   330  	}
   331  
   332  	activation2 := NewActivationClaims(apk)
   333  	activation2.Issuer = apk
   334  	activation2.Subject = apk2
   335  	activation2.ImportSubject = "times.*.bar"
   336  	activation2.ImportType = Stream
   337  	activation2.Name = "times"
   338  
   339  	hash2, err := activation2.HashID()
   340  	if err != nil {
   341  		t.Fatalf("activation with subject should hash %v", err)
   342  	}
   343  
   344  	if hash != hash2 {
   345  		t.Fatal("subjects should be stripped to create hash")
   346  	}
   347  }
   348  
   349  func TestActivationClaimAccountIDValidation(t *testing.T) {
   350  	issuerAccountKP := createAccountNKey(t)
   351  	issuerAccountPK := publicKey(issuerAccountKP, t)
   352  
   353  	issuerKP := createAccountNKey(t)
   354  	issuerPK := publicKey(issuerKP, t)
   355  
   356  	account := NewAccountClaims(issuerAccountPK)
   357  	account.SigningKeys.Add(issuerPK)
   358  	token, err := account.Encode(issuerAccountKP)
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	account, err = DecodeAccountClaims(token)
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  
   367  	importerKP := createAccountNKey(t)
   368  	importerPK := publicKey(importerKP, t)
   369  
   370  	ac := NewActivationClaims(importerPK)
   371  	ac.IssuerAccount = issuerAccountPK
   372  	ac.Name = "foo.bar"
   373  	ac.Activation.ImportSubject = Subject("foo.bar")
   374  	ac.Activation.ImportType = Stream
   375  
   376  	var vr ValidationResults
   377  	ac.Validate(&vr)
   378  	if len(vr.Issues) != 0 {
   379  		t.Fatalf("expected no validation errors: %v", vr.Issues[0].Error())
   380  	}
   381  	token, err = ac.Encode(issuerKP)
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  	ac, err = DecodeActivationClaims(token)
   386  	if err != nil {
   387  		t.Fatal(err)
   388  	}
   389  	if ac.Issuer != issuerPK {
   390  		t.Fatal("expected activation subject to be different")
   391  	}
   392  	if ac.IssuerAccount != issuerAccountPK {
   393  		t.Fatal("expected activation account id to be different")
   394  	}
   395  
   396  	if !account.DidSign(ac) {
   397  		t.Fatal("expected account to have signed activation")
   398  	}
   399  
   400  	ac.IssuerAccount = publicKey(createUserNKey(t), t)
   401  	ac.Validate(&vr)
   402  	if len(vr.Issues) != 1 {
   403  		t.Fatal("expected validation error")
   404  	}
   405  }
   406  
   407  func TestCleanSubject(t *testing.T) {
   408  	input := [][]string{
   409  		{"foo", "foo"},
   410  		{"*", "_"},
   411  		{">", "_"},
   412  		{"foo.*", "foo"},
   413  		{"foo.bar.>", "foo.bar"},
   414  		{"foo.*.bar", "foo"},
   415  		{"bam.boom.blat.*", "bam.boom.blat"},
   416  		{"*.blam", "_"},
   417  	}
   418  
   419  	for _, pair := range input {
   420  		clean := cleanSubject(pair[0])
   421  		if pair[1] != clean {
   422  			t.Errorf("Expected %s but got %s", pair[1], clean)
   423  		}
   424  	}
   425  }
   426  
   427  func TestActivationClaimRevocation(t *testing.T) {
   428  	akp := createAccountNKey(t)
   429  	apk := publicKey(akp, t)
   430  	account := NewAccountClaims(apk)
   431  	e := &Export{Subject: "q.>", Type: Service, TokenReq: true}
   432  	account.Exports.Add(e)
   433  
   434  	a := publicKey(createAccountNKey(t), t)
   435  	aminAgo := time.Now().Add(-time.Minute)
   436  
   437  	if account.Exports[0].Revocations.IsRevoked(a, aminAgo) {
   438  		t.Fatal("should not be revoked")
   439  	}
   440  	e.RevokeAt(a, aminAgo)
   441  	if !account.Exports[0].Revocations.IsRevoked(a, aminAgo) {
   442  		t.Fatal("should be revoked")
   443  	}
   444  
   445  	a2 := publicKey(createAccountNKey(t), t)
   446  	if account.Exports[0].Revocations.IsRevoked(a2, aminAgo) {
   447  		t.Fatal("should not be revoked")
   448  	}
   449  	e.RevokeAt("*", aminAgo)
   450  	if !account.Exports[0].Revocations.IsRevoked(a2, time.Now().Add(-time.Hour)) {
   451  		t.Fatal("should be revoked")
   452  	}
   453  
   454  	vr := ValidationResults{}
   455  	account.Validate(&vr)
   456  	if !vr.IsEmpty() {
   457  		t.Fatal("account validation shouldn't have failed")
   458  	}
   459  }