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