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 }