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 }