github.com/nats-io/jwt/v2@v2.5.6/types_test.go (about)

     1  /*
     2   * Copyright 2018 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  	"crypto/rand"
    20  	"os"
    21  	"regexp"
    22  	"strings"
    23  	"testing"
    24  )
    25  
    26  func TestVersion(t *testing.T) {
    27  	// Semantic versioning
    28  	verRe := regexp.MustCompile(`\d+.\d+.\d+(-\S+)?`)
    29  	if !verRe.MatchString(Version) {
    30  		t.Fatalf("Version not compatible with semantic versioning: %q", Version)
    31  	}
    32  }
    33  
    34  func TestVersionMatchesTag(t *testing.T) {
    35  	tag := os.Getenv("TRAVIS_TAG")
    36  	if tag == "" {
    37  		t.SkipNow()
    38  	}
    39  	// We expect a tag of the form vX.Y.Z. If that's not the case,
    40  	// we need someone to have a look. So fail if first letter is not
    41  	// a `v`
    42  	if len(tag) < 2 || tag[0] != 'v' {
    43  		t.Fatalf("Expect tag to start with `v`, tag is: %s", tag)
    44  	}
    45  	// Look only at tag from current 'v', that is v1 for this file.
    46  	if tag[1] != '2' {
    47  		// Ignore, it is not a v2 tag.
    48  		return
    49  	}
    50  	// Strip the `v` from the tag for the version comparison.
    51  	if Version != tag[1:] {
    52  		t.Fatalf("Version (%s) does not match tag (%s)", Version, tag[1:])
    53  	}
    54  }
    55  
    56  func TestTimeRangeValidation(t *testing.T) {
    57  	tr := TimeRange{
    58  		Start: "hello",
    59  		End:   "03:15:00",
    60  	}
    61  
    62  	vr := CreateValidationResults()
    63  	tr.Validate(vr)
    64  
    65  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
    66  		t.Error("bad start should be invalid")
    67  	}
    68  
    69  	if !strings.Contains(vr.Issues[0].Error(), tr.Start) {
    70  		t.Error("error should contain the faulty value")
    71  	}
    72  
    73  	tr = TimeRange{
    74  		Start: "15:43:22",
    75  		End:   "27:11:11",
    76  	}
    77  
    78  	vr = CreateValidationResults()
    79  	tr.Validate(vr)
    80  
    81  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
    82  		t.Error("bad end should be invalid")
    83  	}
    84  
    85  	if !strings.Contains(vr.Issues[0].Error(), tr.End) {
    86  		t.Error("error should contain the faulty value")
    87  	}
    88  
    89  	tr = TimeRange{
    90  		Start: "",
    91  		End:   "03:15:00",
    92  	}
    93  
    94  	vr = CreateValidationResults()
    95  	tr.Validate(vr)
    96  
    97  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
    98  		t.Error("bad start should be invalid")
    99  	}
   100  
   101  	tr = TimeRange{
   102  		Start: "15:43:22",
   103  		End:   "",
   104  	}
   105  
   106  	vr = CreateValidationResults()
   107  	tr.Validate(vr)
   108  
   109  	if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) {
   110  		t.Error("bad end should be invalid")
   111  	}
   112  }
   113  
   114  func TestTagList(t *testing.T) {
   115  	tags := TagList{}
   116  
   117  	tags.Add("one")
   118  
   119  	AssertEquals(true, tags.Contains("one"), t)
   120  	AssertEquals(true, tags.Contains("ONE"), t)
   121  	AssertEquals("one", tags[0], t)
   122  
   123  	tags.Add("TWO")
   124  
   125  	AssertEquals(true, tags.Contains("two"), t)
   126  	AssertEquals(true, tags.Contains("TWO"), t)
   127  	AssertEquals("two", tags[1], t)
   128  
   129  	tags.Remove("ONE")
   130  	AssertEquals("two", tags[0], t)
   131  	AssertEquals(false, tags.Contains("one"), t)
   132  	AssertEquals(false, tags.Contains("ONE"), t)
   133  }
   134  
   135  func TestStringList(t *testing.T) {
   136  	slist := StringList{}
   137  
   138  	slist.Add("one")
   139  
   140  	AssertEquals(true, slist.Contains("one"), t)
   141  	AssertEquals(false, slist.Contains("ONE"), t)
   142  	AssertEquals("one", slist[0], t)
   143  
   144  	slist.Add("TWO")
   145  
   146  	AssertEquals(false, slist.Contains("two"), t)
   147  	AssertEquals(true, slist.Contains("TWO"), t)
   148  	AssertEquals("TWO", slist[1], t)
   149  
   150  	slist.Remove("ONE")
   151  	AssertEquals("one", slist[0], t)
   152  	AssertEquals(true, slist.Contains("one"), t)
   153  	AssertEquals(false, slist.Contains("ONE"), t)
   154  
   155  	slist.Add("ONE")
   156  	AssertEquals(true, slist.Contains("one"), t)
   157  	AssertEquals(true, slist.Contains("ONE"), t)
   158  	AssertEquals(3, len(slist), t)
   159  
   160  	slist.Remove("one")
   161  	AssertEquals("TWO", slist[0], t)
   162  	AssertEquals(false, slist.Contains("one"), t)
   163  	AssertEquals(true, slist.Contains("ONE"), t)
   164  }
   165  
   166  func TestSubjectValid(t *testing.T) {
   167  	var s Subject
   168  
   169  	vr := CreateValidationResults()
   170  	s.Validate(vr)
   171  	if !vr.IsBlocking(false) {
   172  		t.Fatalf("Empty string is not a valid subjects")
   173  	}
   174  
   175  	s = "has spaces"
   176  	vr = CreateValidationResults()
   177  	s.Validate(vr)
   178  	if !vr.IsBlocking(false) {
   179  		t.Fatalf("Subjects cannot contain spaces")
   180  	}
   181  
   182  	s = "has.spa ces.and.tokens"
   183  	vr = CreateValidationResults()
   184  	s.Validate(vr)
   185  	if !vr.IsBlocking(false) {
   186  		t.Fatalf("Subjects cannot have spaces")
   187  	}
   188  
   189  	s = ".start.with.dot"
   190  	vr = CreateValidationResults()
   191  	s.Validate(vr)
   192  	if vr.IsEmpty() || !strings.Contains(vr.Issues[0].Description, "start or end with a `.`") {
   193  		t.Fatalf("Did not get expected failure: %+v", vr.Issues)
   194  	}
   195  
   196  	s = "end.with.dot."
   197  	vr = CreateValidationResults()
   198  	s.Validate(vr)
   199  	if vr.IsEmpty() || !strings.Contains(vr.Issues[0].Description, "start or end with a `.`") {
   200  		t.Fatalf("Did not get expected failure: %+v", vr.Issues)
   201  	}
   202  
   203  	s = "consecutive..dot"
   204  	vr = CreateValidationResults()
   205  	s.Validate(vr)
   206  	if vr.IsEmpty() || !strings.Contains(vr.Issues[0].Description, "consecutive `.`") {
   207  		t.Fatalf("Did not get expected failure: %+v", vr.Issues)
   208  	}
   209  
   210  	s = "one"
   211  	vr = CreateValidationResults()
   212  	s.Validate(vr)
   213  	if !vr.IsEmpty() {
   214  		t.Fatalf("%s is a valid subject", s)
   215  	}
   216  
   217  	s = "one.two.three"
   218  	vr = CreateValidationResults()
   219  	s.Validate(vr)
   220  	if !vr.IsEmpty() {
   221  		t.Fatalf("%s is a valid subject", s)
   222  	}
   223  }
   224  
   225  func TestSubjectHasWildCards(t *testing.T) {
   226  	s := Subject("one")
   227  	AssertEquals(false, s.HasWildCards(), t)
   228  
   229  	s = "one.two.three"
   230  	AssertEquals(false, s.HasWildCards(), t)
   231  
   232  	s = "*"
   233  	AssertEquals(true, s.HasWildCards(), t)
   234  
   235  	s = "one.*.three"
   236  	AssertEquals(true, s.HasWildCards(), t)
   237  
   238  	s = "*.two.three"
   239  	AssertEquals(true, s.HasWildCards(), t)
   240  
   241  	s = "one.two.*"
   242  	AssertEquals(true, s.HasWildCards(), t)
   243  
   244  	s = "one.>"
   245  	AssertEquals(true, s.HasWildCards(), t)
   246  
   247  	s = "one.two.>"
   248  	AssertEquals(true, s.HasWildCards(), t)
   249  
   250  	s = ">"
   251  	AssertEquals(true, s.HasWildCards(), t)
   252  }
   253  
   254  func TestSubjectContainment(t *testing.T) {
   255  	var s Subject
   256  	var o Subject
   257  
   258  	s = "one.two.three"
   259  	o = "one.*.three"
   260  	AssertEquals(true, s.IsContainedIn(o), t)
   261  
   262  	s = "one.*.three"
   263  	o = "one.*.three"
   264  	AssertEquals(true, s.IsContainedIn(o), t)
   265  
   266  	s = "one.*.three"
   267  	o = "one.two.three"
   268  	AssertEquals(false, s.IsContainedIn(o), t)
   269  
   270  	s = "one.two.three"
   271  	o = "one.two.*"
   272  	AssertEquals(true, s.IsContainedIn(o), t)
   273  
   274  	s = "one.two.three"
   275  	o = "one.*.three"
   276  	AssertEquals(true, s.IsContainedIn(o), t)
   277  
   278  	s = "one.two.three"
   279  	o = "*.two.three"
   280  	AssertEquals(true, s.IsContainedIn(o), t)
   281  
   282  	s = "one.two.three"
   283  	o = "one.two.>"
   284  	AssertEquals(true, s.IsContainedIn(o), t)
   285  
   286  	s = "one.two.three"
   287  	o = "one.>"
   288  	AssertEquals(true, s.IsContainedIn(o), t)
   289  
   290  	s = "one.two.three"
   291  	o = ">"
   292  	AssertEquals(true, s.IsContainedIn(o), t)
   293  
   294  	s = "one.two.three"
   295  	o = "one.two"
   296  	AssertEquals(false, s.IsContainedIn(o), t)
   297  
   298  	s = "one"
   299  	o = "one.two"
   300  	AssertEquals(false, s.IsContainedIn(o), t)
   301  }
   302  
   303  func TestPermissions_Validate(t *testing.T) {
   304  	p := Permissions{
   305  		Pub:  Permission{},
   306  		Sub:  Permission{},
   307  		Resp: nil,
   308  	}
   309  	vr := ValidationResults{}
   310  	resetAndValidate := func() {
   311  		vr = ValidationResults{}
   312  		p.Validate(&vr)
   313  	}
   314  	resetAndValidate()
   315  	AssertTrue(vr.IsEmpty(), t)
   316  
   317  	p.Resp = &ResponsePermission{
   318  		MaxMsgs: 0,
   319  		Expires: 0,
   320  	}
   321  	resetAndValidate()
   322  	AssertTrue(vr.IsEmpty(), t)
   323  
   324  	p.Pub.Allow.Add("foo")
   325  	p.Pub.Deny.Add("bar")
   326  	resetAndValidate()
   327  	AssertTrue(vr.IsEmpty(), t)
   328  
   329  	p.Pub.Allow.Add("foo queue")
   330  	p.Pub.Deny.Add("bar queue")
   331  	resetAndValidate()
   332  	AssertTrue(!vr.IsEmpty(), t)
   333  	AssertTrue(vr.IsBlocking(false), t)
   334  	AssertTrue(len(vr.Errors()) == 2, t)
   335  
   336  	p.Pub = Permission{}
   337  
   338  	p.Sub.Allow.Add("1")
   339  	p.Sub.Deny.Add("2")
   340  	resetAndValidate()
   341  	AssertTrue(vr.IsEmpty(), t)
   342  
   343  	p.Sub.Allow.Add("3 queue")
   344  	p.Sub.Deny.Add("4 queue")
   345  	resetAndValidate()
   346  	AssertTrue(vr.IsEmpty(), t)
   347  
   348  	p.Sub.Allow.Add("5.* queue.*.foo")
   349  	p.Sub.Deny.Add("6.* queue.*.bar")
   350  	resetAndValidate()
   351  	AssertTrue(vr.IsEmpty(), t)
   352  
   353  	p.Sub.Allow.Add("7.> queue.>")
   354  	p.Sub.Deny.Add("8.> queue.>")
   355  	resetAndValidate()
   356  	AssertTrue(vr.IsEmpty(), t)
   357  
   358  	p.Sub.Allow.Add("9 too many spaces")
   359  	p.Sub.Deny.Add("0 too many spaces")
   360  	resetAndValidate()
   361  	AssertTrue(!vr.IsEmpty(), t)
   362  	AssertTrue(vr.IsBlocking(false), t)
   363  	AssertTrue(len(vr.Errors()) == 2, t)
   364  }
   365  
   366  func TestRenamingSubject_ToSubject(t *testing.T) {
   367  	AssertEquals(RenamingSubject("foo.$2.$1.bar").ToSubject(), Subject("foo.*.*.bar"), t)
   368  	AssertEquals(RenamingSubject("foo.*.bar").ToSubject(), Subject("foo.*.bar"), t)
   369  	AssertEquals(RenamingSubject("foo.$2.*.bar").ToSubject(), Subject("foo.*.*.bar"), t)
   370  }
   371  
   372  func TestRenamigSubject_Validate(t *testing.T) {
   373  	for from, to := range map[string]string{
   374  		"foo":      ">",
   375  		"bar":      "*",
   376  		"foo.*":    "*.*",
   377  		"foo.>":    "*.*",
   378  		"bar.>":    "*.>",
   379  		"bar.*.*>": "*.>",
   380  		"*.bar":    "$2",
   381  	} {
   382  		vr := ValidationResults{}
   383  		RenamingSubject(to).Validate(Subject(from), &vr)
   384  		if !vr.IsBlocking(false) {
   385  			t.Fatalf("expected blocking issue %q:%q", to, from)
   386  		}
   387  	}
   388  	for from, to := range map[string]string{
   389  		"foo":     "bar",
   390  		"foo.bar": "baz",
   391  		"x":       "x.y.z",
   392  		">":       "foo.>",
   393  		"*":       "$1.foo",
   394  		"*.*":     "$1.foo.$2",
   395  		"*.bar":   "$1",
   396  	} {
   397  		vr := ValidationResults{}
   398  		RenamingSubject(to).Validate(Subject(from), &vr)
   399  		if !vr.IsEmpty() {
   400  			t.Fatalf("expected no issue %q:%q got: %v", to, from, vr.Issues)
   401  		}
   402  	}
   403  }
   404  
   405  func TestInvalidInfo(t *testing.T) {
   406  	tooLong := [MaxInfoLength + 21]byte{}
   407  	rand.Read(tooLong[:])
   408  	for _, info := range []Info{{
   409  		Description: "",
   410  		InfoURL:     "/bad",
   411  	}, {
   412  		Description: string(tooLong[:]),
   413  		InfoURL:     "http://localhost/foo/bar",
   414  	}, {
   415  		Description: "",
   416  		InfoURL: `http://1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901
   417  234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901
   418  23456789012345678901234567890123456789012345678901234567890123456789012345678901234567890`,
   419  	}} {
   420  		vr := CreateValidationResults()
   421  		info.Validate(vr)
   422  		if vr.IsEmpty() {
   423  			t.Errorf("info should not validate cleanly")
   424  		}
   425  		if !vr.IsBlocking(true) {
   426  			t.Errorf("invalid info needs to be blocking")
   427  		}
   428  	}
   429  }