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 }