get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/auth_callout_test.go (about) 1 // Copyright 2022-2023 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package server 15 16 import ( 17 "bytes" 18 "crypto/x509" 19 "encoding/json" 20 "encoding/pem" 21 "errors" 22 "fmt" 23 "reflect" 24 "sort" 25 "strings" 26 "sync/atomic" 27 "testing" 28 "time" 29 30 "github.com/nats-io/jwt/v2" 31 "github.com/nats-io/nats.go" 32 "github.com/nats-io/nkeys" 33 ) 34 35 // Helper function to decode an auth request. 36 func decodeAuthRequest(t *testing.T, ejwt []byte) (string, *jwt.ServerID, *jwt.ClientInformation, *jwt.ConnectOptions, *jwt.ClientTLS) { 37 t.Helper() 38 ac, err := jwt.DecodeAuthorizationRequestClaims(string(ejwt)) 39 require_NoError(t, err) 40 return ac.UserNkey, &ac.Server, &ac.ClientInformation, &ac.ConnectOptions, ac.TLS 41 } 42 43 const ( 44 authCalloutPub = "UBO2MQV67TQTVIRV3XFTEZOACM4WLOCMCDMAWN5QVN5PI2N6JHTVDRON" 45 authCalloutSeed = "SUAP277QP7U4JMFFPVZHLJYEQJ2UHOTYVEIZJYAWRJXQLP4FRSEHYZJJOU" 46 authCalloutIssuer = "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 47 authCalloutIssuerSeed = "SAANDLKMXL6CUS3CP52WIXBEDN6YJ545GDKC65U5JZPPV6WH6ESWUA6YAI" 48 authCalloutIssuerSK = "SAAE46BB675HKZKSVJEUZAKKWIV6BJJO6XYE46Z3ZHO7TCI647M3V42IJE" 49 ) 50 51 func serviceResponse(t *testing.T, userID string, serverID string, uJwt string, errMsg string, expires time.Duration) []byte { 52 cr := jwt.NewAuthorizationResponseClaims(userID) 53 cr.Audience = serverID 54 cr.Error = errMsg 55 cr.Jwt = uJwt 56 if expires != 0 { 57 cr.Expires = time.Now().Add(expires).Unix() 58 } 59 aa, err := nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 60 require_NoError(t, err) 61 token, err := cr.Encode(aa) 62 require_NoError(t, err) 63 return []byte(token) 64 } 65 66 func newScopedRole(t *testing.T, role string, pub []string, sub []string, allowResponses bool) (*jwt.UserScope, nkeys.KeyPair) { 67 akp, pk := createKey(t) 68 r := jwt.NewUserScope() 69 r.Key = pk 70 r.Template.Sub.Allow.Add(sub...) 71 r.Template.Pub.Allow.Add(pub...) 72 if allowResponses { 73 r.Template.Resp = &jwt.ResponsePermission{ 74 MaxMsgs: 1, 75 Expires: time.Second * 3, 76 } 77 } 78 r.Role = role 79 return r, akp 80 } 81 82 // Will create a signed user jwt as an authorized user. 83 func createAuthUser(t *testing.T, user, name, account, issuerAccount string, akp nkeys.KeyPair, expires time.Duration, limits *jwt.UserPermissionLimits) string { 84 t.Helper() 85 86 if akp == nil { 87 var err error 88 akp, err = nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 89 require_NoError(t, err) 90 } 91 92 uc := jwt.NewUserClaims(user) 93 if issuerAccount != "" { 94 if _, err := nkeys.FromPublicKey(issuerAccount); err != nil { 95 t.Fatalf("issuer account is not a public key: %v", err) 96 } 97 uc.IssuerAccount = issuerAccount 98 } 99 // The callout uses the audience as the target account 100 // only if in non-operator mode, otherwise the user JWT has 101 // correct attribution - issuer or issuer_account 102 if _, err := nkeys.FromPublicKey(account); err != nil { 103 // if it is not a public key, set the audience 104 uc.Audience = account 105 } 106 107 if name != _EMPTY_ { 108 uc.Name = name 109 } 110 if expires != 0 { 111 uc.Expires = time.Now().Add(expires).Unix() 112 } 113 if limits != nil { 114 uc.UserPermissionLimits = *limits 115 } 116 117 vr := jwt.CreateValidationResults() 118 uc.Validate(vr) 119 require_Len(t, len(vr.Errors()), 0) 120 121 tok, err := uc.Encode(akp) 122 require_NoError(t, err) 123 124 return tok 125 } 126 127 type authTest struct { 128 t *testing.T 129 srv *Server 130 conf string 131 authClient *nats.Conn 132 clients []*nats.Conn 133 } 134 135 func NewAuthTest(t *testing.T, config string, authHandler nats.MsgHandler, clientOptions ...nats.Option) *authTest { 136 a := &authTest{t: t} 137 a.conf = createConfFile(t, []byte(config)) 138 a.srv, _ = RunServerWithConfig(a.conf) 139 140 var err error 141 a.authClient = a.ConnectCallout(clientOptions...) 142 _, err = a.authClient.Subscribe(AuthCalloutSubject, authHandler) 143 require_NoError(t, err) 144 return a 145 } 146 147 func (at *authTest) NewClient(clientOptions ...nats.Option) (*nats.Conn, error) { 148 conn, err := nats.Connect(at.srv.ClientURL(), clientOptions...) 149 if err != nil { 150 return nil, err 151 } 152 at.clients = append(at.clients, conn) 153 return conn, nil 154 } 155 156 func (at *authTest) ConnectCallout(clientOptions ...nats.Option) *nats.Conn { 157 conn, err := at.NewClient(clientOptions...) 158 if err != nil { 159 err = fmt.Errorf("callout client failed: %w", err) 160 } 161 require_NoError(at.t, err) 162 return conn 163 } 164 165 func (at *authTest) Connect(clientOptions ...nats.Option) *nats.Conn { 166 conn, err := at.NewClient(clientOptions...) 167 require_NoError(at.t, err) 168 return conn 169 } 170 171 func (at *authTest) WSNewClient(clientOptions ...nats.Option) (*nats.Conn, error) { 172 pi := at.srv.PortsInfo(10 * time.Millisecond) 173 require_False(at.t, pi == nil) 174 175 // test cert is SAN to DNS localhost, not local IPs returned by server in test environments 176 wssUrl := strings.Replace(pi.WebSocket[0], "127.0.0.1", "localhost", 1) 177 178 // Seeing 127.0.1.1 in some test environments... 179 wssUrl = strings.Replace(wssUrl, "127.0.1.1", "localhost", 1) 180 181 conn, err := nats.Connect(wssUrl, clientOptions...) 182 if err != nil { 183 return nil, err 184 } 185 at.clients = append(at.clients, conn) 186 return conn, nil 187 } 188 189 func (at *authTest) WSConnect(clientOptions ...nats.Option) *nats.Conn { 190 conn, err := at.WSNewClient(clientOptions...) 191 require_NoError(at.t, err) 192 return conn 193 } 194 195 func (at *authTest) RequireConnectError(clientOptions ...nats.Option) { 196 _, err := at.NewClient(clientOptions...) 197 require_Error(at.t, err) 198 } 199 200 func (at *authTest) Cleanup() { 201 if at.authClient != nil { 202 at.authClient.Close() 203 } 204 if at.srv != nil { 205 at.srv.Shutdown() 206 removeFile(at.t, at.conf) 207 } 208 } 209 210 func TestAuthCalloutBasics(t *testing.T) { 211 conf := ` 212 listen: "127.0.0.1:-1" 213 server_name: A 214 authorization { 215 timeout: 1s 216 users: [ { user: "auth", password: "pwd" } ] 217 auth_callout { 218 # Needs to be a public account nkey, will work for both server config and operator mode. 219 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 220 # users that will power the auth callout service. 221 auth_users: [ auth ] 222 } 223 } 224 ` 225 callouts := uint32(0) 226 handler := func(m *nats.Msg) { 227 atomic.AddUint32(&callouts, 1) 228 user, si, ci, opts, _ := decodeAuthRequest(t, m.Data) 229 require_True(t, si.Name == "A") 230 require_True(t, ci.Host == "127.0.0.1") 231 // Allow dlc user. 232 if opts.Username == "dlc" && opts.Password == "zzz" { 233 var j jwt.UserPermissionLimits 234 j.Pub.Allow.Add("$SYS.>") 235 j.Payload = 1024 236 ujwt := createAuthUser(t, user, _EMPTY_, globalAccountName, "", nil, 10*time.Minute, &j) 237 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 238 } else { 239 // Nil response signals no authentication. 240 m.Respond(nil) 241 } 242 } 243 at := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 244 defer at.Cleanup() 245 246 // This one should fail since bad password. 247 at.RequireConnectError(nats.UserInfo("dlc", "xxx")) 248 249 // This one will use callout since not defined in server config. 250 nc := at.Connect(nats.UserInfo("dlc", "zzz")) 251 252 resp, err := nc.Request(userDirectInfoSubj, nil, time.Second) 253 require_NoError(t, err) 254 response := ServerAPIResponse{Data: &UserInfo{}} 255 err = json.Unmarshal(resp.Data, &response) 256 require_NoError(t, err) 257 258 userInfo := response.Data.(*UserInfo) 259 260 dlc := &UserInfo{ 261 UserID: "dlc", 262 Account: globalAccountName, 263 Permissions: &Permissions{ 264 Publish: &SubjectPermission{ 265 Allow: []string{"$SYS.>"}, 266 Deny: []string{AuthCalloutSubject}, // Will be auto-added since in auth account. 267 }, 268 Subscribe: &SubjectPermission{}, 269 }, 270 } 271 expires := userInfo.Expires 272 userInfo.Expires = 0 273 if !reflect.DeepEqual(dlc, userInfo) { 274 t.Fatalf("User info for %q did not match", "dlc") 275 } 276 if expires > 10*time.Minute || expires < (10*time.Minute-5*time.Second) { 277 t.Fatalf("Expected expires of ~%v, got %v", 10*time.Minute, expires) 278 } 279 } 280 281 func TestAuthCalloutMultiAccounts(t *testing.T) { 282 conf := ` 283 listen: "127.0.0.1:-1" 284 server_name: ZZ 285 accounts { 286 AUTH { users [ {user: "auth", password: "pwd"} ] } 287 FOO {} 288 BAR {} 289 BAZ {} 290 } 291 authorization { 292 timeout: 1s 293 auth_callout { 294 # Needs to be a public account nkey, will work for both server config and operator mode. 295 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 296 account: AUTH 297 auth_users: [ auth ] 298 } 299 } 300 ` 301 handler := func(m *nats.Msg) { 302 user, si, ci, opts, _ := decodeAuthRequest(t, m.Data) 303 require_True(t, si.Name == "ZZ") 304 require_True(t, ci.Host == "127.0.0.1") 305 // Allow dlc user and map to the BAZ account. 306 if opts.Username == "dlc" && opts.Password == "zzz" { 307 ujwt := createAuthUser(t, user, _EMPTY_, "BAZ", "", nil, 0, nil) 308 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 309 } else { 310 // Nil response signals no authentication. 311 m.Respond(nil) 312 } 313 } 314 315 at := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 316 defer at.Cleanup() 317 318 // This one will use callout since not defined in server config. 319 nc := at.Connect(nats.UserInfo("dlc", "zzz")) 320 321 resp, err := nc.Request(userDirectInfoSubj, nil, time.Second) 322 require_NoError(t, err) 323 response := ServerAPIResponse{Data: &UserInfo{}} 324 err = json.Unmarshal(resp.Data, &response) 325 require_NoError(t, err) 326 userInfo := response.Data.(*UserInfo) 327 328 require_True(t, userInfo.UserID == "dlc") 329 require_True(t, userInfo.Account == "BAZ") 330 } 331 332 func TestAuthCalloutClientTLSCerts(t *testing.T) { 333 conf := ` 334 listen: "localhost:-1" 335 server_name: T 336 337 tls { 338 cert_file = "../test/configs/certs/tlsauth/server.pem" 339 key_file = "../test/configs/certs/tlsauth/server-key.pem" 340 ca_file = "../test/configs/certs/tlsauth/ca.pem" 341 verify = true 342 } 343 344 accounts { 345 AUTH { users [ {user: "auth", password: "pwd"} ] } 346 FOO {} 347 } 348 authorization { 349 timeout: 1s 350 auth_callout { 351 # Needs to be a public account nkey, will work for both server config and operator mode. 352 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 353 account: AUTH 354 auth_users: [ auth ] 355 } 356 } 357 ` 358 handler := func(m *nats.Msg) { 359 user, si, ci, _, ctls := decodeAuthRequest(t, m.Data) 360 require_True(t, si.Name == "T") 361 require_True(t, ci.Host == "127.0.0.1") 362 require_True(t, ctls != nil) 363 // Zero since we are verified and will be under verified chains. 364 require_True(t, len(ctls.Certs) == 0) 365 require_True(t, len(ctls.VerifiedChains) == 1) 366 // Since we have a CA. 367 require_True(t, len(ctls.VerifiedChains[0]) == 2) 368 blk, _ := pem.Decode([]byte(ctls.VerifiedChains[0][0])) 369 cert, err := x509.ParseCertificate(blk.Bytes) 370 require_NoError(t, err) 371 if strings.HasPrefix(cert.Subject.String(), "CN=example.com") { 372 // Override blank name here, server will substitute. 373 ujwt := createAuthUser(t, user, "dlc", "FOO", "", nil, 0, nil) 374 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 375 } 376 } 377 378 ac := NewAuthTest(t, conf, handler, 379 nats.UserInfo("auth", "pwd"), 380 nats.ClientCert("../test/configs/certs/tlsauth/client2.pem", "../test/configs/certs/tlsauth/client2-key.pem"), 381 nats.RootCAs("../test/configs/certs/tlsauth/ca.pem")) 382 defer ac.Cleanup() 383 384 // Will use client cert to determine user. 385 nc := ac.Connect( 386 nats.ClientCert("../test/configs/certs/tlsauth/client2.pem", "../test/configs/certs/tlsauth/client2-key.pem"), 387 nats.RootCAs("../test/configs/certs/tlsauth/ca.pem"), 388 ) 389 390 resp, err := nc.Request(userDirectInfoSubj, nil, time.Second) 391 require_NoError(t, err) 392 response := ServerAPIResponse{Data: &UserInfo{}} 393 err = json.Unmarshal(resp.Data, &response) 394 require_NoError(t, err) 395 userInfo := response.Data.(*UserInfo) 396 397 require_True(t, userInfo.UserID == "dlc") 398 require_True(t, userInfo.Account == "FOO") 399 } 400 401 func TestAuthCalloutVerifiedUserCalloutsWithSig(t *testing.T) { 402 conf := ` 403 listen: "127.0.0.1:-1" 404 server_name: A 405 authorization { 406 timeout: 1s 407 users: [ 408 { user: "auth", password: "pwd" } 409 { nkey: "UBO2MQV67TQTVIRV3XFTEZOACM4WLOCMCDMAWN5QVN5PI2N6JHTVDRON" } 410 ] 411 auth_callout { 412 # Needs to be a public account nkey, will work for both server config and operator mode. 413 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 414 # users that will power the auth callout service. 415 auth_users: [ auth ] 416 } 417 } 418 ` 419 callouts := uint32(0) 420 handler := func(m *nats.Msg) { 421 atomic.AddUint32(&callouts, 1) 422 user, si, ci, opts, _ := decodeAuthRequest(t, m.Data) 423 require_True(t, si.Name == "A") 424 require_True(t, ci.Host == "127.0.0.1") 425 require_True(t, opts.SignedNonce != _EMPTY_) 426 require_True(t, ci.Nonce != _EMPTY_) 427 ujwt := createAuthUser(t, user, _EMPTY_, globalAccountName, "", nil, 0, nil) 428 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 429 } 430 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 431 defer ac.Cleanup() 432 433 seedFile := createTempFile(t, _EMPTY_) 434 defer removeFile(t, seedFile.Name()) 435 seedFile.WriteString(authCalloutSeed) 436 nkeyOpt, err := nats.NkeyOptionFromSeed(seedFile.Name()) 437 require_NoError(t, err) 438 439 nc := ac.Connect(nkeyOpt) 440 441 // Make sure that the callout was called. 442 if atomic.LoadUint32(&callouts) != 1 { 443 t.Fatalf("Expected callout to be called") 444 } 445 446 resp, err := nc.Request(userDirectInfoSubj, nil, time.Second) 447 require_NoError(t, err) 448 response := ServerAPIResponse{Data: &UserInfo{}} 449 err = json.Unmarshal(resp.Data, &response) 450 require_NoError(t, err) 451 452 userInfo := response.Data.(*UserInfo) 453 454 dlc := &UserInfo{ 455 UserID: "UBO2MQV67TQTVIRV3XFTEZOACM4WLOCMCDMAWN5QVN5PI2N6JHTVDRON", 456 Account: globalAccountName, 457 Permissions: &Permissions{ 458 Publish: &SubjectPermission{ 459 Deny: []string{AuthCalloutSubject}, // Will be auto-added since in auth account. 460 }, 461 Subscribe: &SubjectPermission{}, 462 }, 463 } 464 if !reflect.DeepEqual(dlc, userInfo) { 465 t.Fatalf("User info for %q did not match", "dlc") 466 } 467 } 468 469 // For creating the authorized users in operator mode. 470 func createAuthServiceUser(t *testing.T, accKp nkeys.KeyPair) (pub, creds string) { 471 t.Helper() 472 ukp, _ := nkeys.CreateUser() 473 seed, _ := ukp.Seed() 474 upub, _ := ukp.PublicKey() 475 uclaim := newJWTTestUserClaims() 476 uclaim.Name = "auth-service" 477 uclaim.Subject = upub 478 vr := jwt.ValidationResults{} 479 uclaim.Validate(&vr) 480 require_Len(t, len(vr.Errors()), 0) 481 ujwt, err := uclaim.Encode(accKp) 482 require_NoError(t, err) 483 return upub, genCredsFile(t, ujwt, seed) 484 } 485 486 func createBasicAccountUser(t *testing.T, accKp nkeys.KeyPair) (creds string) { 487 t.Helper() 488 ukp, _ := nkeys.CreateUser() 489 seed, _ := ukp.Seed() 490 upub, _ := ukp.PublicKey() 491 uclaim := newJWTTestUserClaims() 492 uclaim.Subject = upub 493 uclaim.Name = "auth-client" 494 // For these deny all permission 495 uclaim.Permissions.Pub.Deny.Add(">") 496 uclaim.Permissions.Sub.Deny.Add(">") 497 vr := jwt.ValidationResults{} 498 uclaim.Validate(&vr) 499 require_Len(t, len(vr.Errors()), 0) 500 ujwt, err := uclaim.Encode(accKp) 501 require_NoError(t, err) 502 return genCredsFile(t, ujwt, seed) 503 } 504 505 func createScopedUser(t *testing.T, accKp nkeys.KeyPair, sk nkeys.KeyPair) (creds string) { 506 t.Helper() 507 ukp, _ := nkeys.CreateUser() 508 seed, _ := ukp.Seed() 509 upub, _ := ukp.PublicKey() 510 uclaim := newJWTTestUserClaims() 511 apk, _ := accKp.PublicKey() 512 uclaim.IssuerAccount = apk 513 uclaim.Subject = upub 514 uclaim.Name = "scoped-user" 515 uclaim.SetScoped(true) 516 517 // Uncomment this to set the sub limits 518 // uclaim.Limits.Subs = 0 519 vr := jwt.ValidationResults{} 520 uclaim.Validate(&vr) 521 require_Len(t, len(vr.Errors()), 0) 522 ujwt, err := uclaim.Encode(sk) 523 require_NoError(t, err) 524 return genCredsFile(t, ujwt, seed) 525 } 526 527 func TestAuthCalloutOperatorNoServerConfigCalloutAllowed(t *testing.T) { 528 conf := createConfFile(t, []byte(fmt.Sprintf(` 529 listen: 127.0.0.1:-1 530 operator: %s 531 resolver: MEM 532 authorization { 533 auth_callout { 534 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 535 auth_users: [ auth ] 536 } 537 } 538 `, ojwt))) 539 defer removeFile(t, conf) 540 541 opts := LoadConfig(conf) 542 _, err := NewServer(opts) 543 require_Error(t, err, errors.New("operators do not allow authorization callouts to be configured directly")) 544 } 545 546 func TestAuthCalloutOperatorModeBasics(t *testing.T) { 547 _, spub := createKey(t) 548 sysClaim := jwt.NewAccountClaims(spub) 549 sysClaim.Name = "$SYS" 550 sysJwt, err := sysClaim.Encode(oKp) 551 require_NoError(t, err) 552 553 // TEST account. 554 tkp, tpub := createKey(t) 555 tSigningKp, tSigningPub := createKey(t) 556 accClaim := jwt.NewAccountClaims(tpub) 557 accClaim.Name = "TEST" 558 accClaim.SigningKeys.Add(tSigningPub) 559 scope, scopedKp := newScopedRole(t, "foo", []string{"foo.>", "$SYS.REQ.USER.INFO"}, []string{"foo.>", "_INBOX.>"}, false) 560 accClaim.SigningKeys.AddScopedSigner(scope) 561 accJwt, err := accClaim.Encode(oKp) 562 require_NoError(t, err) 563 564 // AUTH service account. 565 akp, err := nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 566 require_NoError(t, err) 567 568 apub, err := akp.PublicKey() 569 require_NoError(t, err) 570 571 // The authorized user for the service. 572 upub, creds := createAuthServiceUser(t, akp) 573 defer removeFile(t, creds) 574 575 authClaim := jwt.NewAccountClaims(apub) 576 authClaim.Name = "AUTH" 577 authClaim.EnableExternalAuthorization(upub) 578 authClaim.Authorization.AllowedAccounts.Add(tpub) 579 authJwt, err := authClaim.Encode(oKp) 580 require_NoError(t, err) 581 582 conf := fmt.Sprintf(` 583 listen: 127.0.0.1:-1 584 operator: %s 585 system_account: %s 586 resolver: MEM 587 resolver_preload: { 588 %s: %s 589 %s: %s 590 %s: %s 591 } 592 `, ojwt, spub, apub, authJwt, tpub, accJwt, spub, sysJwt) 593 594 const secretToken = "--XX--" 595 const dummyToken = "--ZZ--" 596 const skKeyToken = "--SK--" 597 const scopedToken = "--Scoped--" 598 const badScopedToken = "--BADScoped--" 599 dkp, notAllowAccountPub := createKey(t) 600 handler := func(m *nats.Msg) { 601 user, si, _, opts, _ := decodeAuthRequest(t, m.Data) 602 if opts.Token == secretToken { 603 ujwt := createAuthUser(t, user, "dlc", tpub, "", tkp, 0, nil) 604 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 605 } else if opts.Token == dummyToken { 606 ujwt := createAuthUser(t, user, "dummy", notAllowAccountPub, "", dkp, 0, nil) 607 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 608 } else if opts.Token == skKeyToken { 609 ujwt := createAuthUser(t, user, "sk", tpub, tpub, tSigningKp, 0, nil) 610 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 611 } else if opts.Token == scopedToken { 612 // must have no limits set 613 ujwt := createAuthUser(t, user, "scoped", tpub, tpub, scopedKp, 0, &jwt.UserPermissionLimits{}) 614 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 615 } else if opts.Token == badScopedToken { 616 // limits are nil - here which result in a default user - this will fail scoped 617 ujwt := createAuthUser(t, user, "bad-scoped", tpub, tpub, scopedKp, 0, nil) 618 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 619 } else { 620 m.Respond(nil) 621 } 622 } 623 624 ac := NewAuthTest(t, conf, handler, nats.UserCredentials(creds)) 625 defer ac.Cleanup() 626 resp, err := ac.authClient.Request(userDirectInfoSubj, nil, time.Second) 627 require_NoError(t, err) 628 response := ServerAPIResponse{Data: &UserInfo{}} 629 err = json.Unmarshal(resp.Data, &response) 630 require_NoError(t, err) 631 632 userInfo := response.Data.(*UserInfo) 633 expected := &UserInfo{ 634 UserID: upub, 635 Account: apub, 636 Permissions: &Permissions{ 637 Publish: &SubjectPermission{ 638 Deny: []string{AuthCalloutSubject}, // Will be auto-added since in auth account. 639 }, 640 Subscribe: &SubjectPermission{}, 641 }, 642 } 643 if !reflect.DeepEqual(expected, userInfo) { 644 t.Fatalf("User info did not match expected, expected auto-deny permissions on callout subject") 645 } 646 647 // Bearer token etc.. 648 // This is used by all users, and the customization will be in other connect args. 649 // This needs to also be bound to the authorization account. 650 creds = createBasicAccountUser(t, akp) 651 defer removeFile(t, creds) 652 653 // We require a token. 654 ac.RequireConnectError(nats.UserCredentials(creds)) 655 656 // Send correct token. This should switch us to the test account. 657 nc := ac.Connect(nats.UserCredentials(creds), nats.Token(secretToken)) 658 require_NoError(t, err) 659 660 resp, err = nc.Request(userDirectInfoSubj, nil, time.Second) 661 require_NoError(t, err) 662 response = ServerAPIResponse{Data: &UserInfo{}} 663 err = json.Unmarshal(resp.Data, &response) 664 require_NoError(t, err) 665 666 userInfo = response.Data.(*UserInfo) 667 668 // Make sure we switch accounts. 669 if userInfo.Account != tpub { 670 t.Fatalf("Expected to be switched to %q, but got %q", tpub, userInfo.Account) 671 } 672 673 // Now make sure that if the authorization service switches to an account that is not allowed, we reject. 674 ac.RequireConnectError(nats.UserCredentials(creds), nats.Token(dummyToken)) 675 676 // Send the signing key token. This should switch us to the test account, but the user 677 // is signed with the account signing key 678 nc = ac.Connect(nats.UserCredentials(creds), nats.Token(skKeyToken)) 679 680 resp, err = nc.Request(userDirectInfoSubj, nil, time.Second) 681 require_NoError(t, err) 682 response = ServerAPIResponse{Data: &UserInfo{}} 683 err = json.Unmarshal(resp.Data, &response) 684 require_NoError(t, err) 685 686 userInfo = response.Data.(*UserInfo) 687 if userInfo.Account != tpub { 688 t.Fatalf("Expected to be switched to %q, but got %q", tpub, userInfo.Account) 689 } 690 691 // bad scoped user 692 ac.RequireConnectError(nats.UserCredentials(creds), nats.Token(badScopedToken)) 693 694 // Send the signing key token. This should switch us to the test account, but the user 695 // is signed with the account signing key 696 nc = ac.Connect(nats.UserCredentials(creds), nats.Token(scopedToken)) 697 require_NoError(t, err) 698 699 resp, err = nc.Request(userDirectInfoSubj, nil, time.Second) 700 require_NoError(t, err) 701 response = ServerAPIResponse{Data: &UserInfo{}} 702 err = json.Unmarshal(resp.Data, &response) 703 require_NoError(t, err) 704 705 userInfo = response.Data.(*UserInfo) 706 if userInfo.Account != tpub { 707 t.Fatalf("Expected to be switched to %q, but got %q", tpub, userInfo.Account) 708 } 709 require_True(t, len(userInfo.Permissions.Publish.Allow) == 2) 710 sort.Strings(userInfo.Permissions.Publish.Allow) 711 require_Equal(t, "foo.>", userInfo.Permissions.Publish.Allow[1]) 712 sort.Strings(userInfo.Permissions.Subscribe.Allow) 713 require_True(t, len(userInfo.Permissions.Subscribe.Allow) == 2) 714 require_Equal(t, "foo.>", userInfo.Permissions.Subscribe.Allow[1]) 715 } 716 717 func testAuthCalloutScopedUser(t *testing.T, allowAnyAccount bool) { 718 _, spub := createKey(t) 719 sysClaim := jwt.NewAccountClaims(spub) 720 sysClaim.Name = "$SYS" 721 sysJwt, err := sysClaim.Encode(oKp) 722 require_NoError(t, err) 723 724 // TEST account. 725 _, tpub := createKey(t) 726 _, tSigningPub := createKey(t) 727 accClaim := jwt.NewAccountClaims(tpub) 728 accClaim.Name = "TEST" 729 accClaim.SigningKeys.Add(tSigningPub) 730 scope, scopedKp := newScopedRole(t, "foo", []string{"foo.>", "$SYS.REQ.USER.INFO"}, []string{"foo.>", "_INBOX.>"}, true) 731 scope.Template.Limits.Subs = 10 732 scope.Template.Limits.Payload = 512 733 accClaim.SigningKeys.AddScopedSigner(scope) 734 accJwt, err := accClaim.Encode(oKp) 735 require_NoError(t, err) 736 737 // AUTH service account. 738 akp, err := nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 739 require_NoError(t, err) 740 741 apub, err := akp.PublicKey() 742 require_NoError(t, err) 743 744 // The authorized user for the service. 745 upub, creds := createAuthServiceUser(t, akp) 746 defer removeFile(t, creds) 747 748 authClaim := jwt.NewAccountClaims(apub) 749 authClaim.Name = "AUTH" 750 authClaim.EnableExternalAuthorization(upub) 751 if allowAnyAccount { 752 authClaim.Authorization.AllowedAccounts.Add("*") 753 } else { 754 authClaim.Authorization.AllowedAccounts.Add(tpub) 755 } 756 // the scope for the bearer token which has no permissions 757 sentinelScope, authKP := newScopedRole(t, "sentinel", nil, nil, false) 758 sentinelScope.Template.Sub.Deny.Add(">") 759 sentinelScope.Template.Pub.Deny.Add(">") 760 sentinelScope.Template.Limits.Subs = 0 761 sentinelScope.Template.Payload = 0 762 authClaim.SigningKeys.AddScopedSigner(sentinelScope) 763 764 authJwt, err := authClaim.Encode(oKp) 765 require_NoError(t, err) 766 767 conf := fmt.Sprintf(` 768 listen: 127.0.0.1:-1 769 operator: %s 770 system_account: %s 771 resolver: MEM 772 resolver_preload: { 773 %s: %s 774 %s: %s 775 %s: %s 776 } 777 `, ojwt, spub, apub, authJwt, tpub, accJwt, spub, sysJwt) 778 779 const scopedToken = "--Scoped--" 780 handler := func(m *nats.Msg) { 781 user, si, _, opts, _ := decodeAuthRequest(t, m.Data) 782 if opts.Token == scopedToken { 783 // must have no limits set 784 ujwt := createAuthUser(t, user, "scoped", tpub, tpub, scopedKp, 0, &jwt.UserPermissionLimits{}) 785 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 786 } else { 787 m.Respond(nil) 788 } 789 } 790 791 ac := NewAuthTest(t, conf, handler, nats.UserCredentials(creds)) 792 defer ac.Cleanup() 793 resp, err := ac.authClient.Request(userDirectInfoSubj, nil, time.Second) 794 require_NoError(t, err) 795 response := ServerAPIResponse{Data: &UserInfo{}} 796 err = json.Unmarshal(resp.Data, &response) 797 require_NoError(t, err) 798 799 userInfo := response.Data.(*UserInfo) 800 expected := &UserInfo{ 801 UserID: upub, 802 Account: apub, 803 Permissions: &Permissions{ 804 Publish: &SubjectPermission{ 805 Deny: []string{AuthCalloutSubject}, // Will be auto-added since in auth account. 806 }, 807 Subscribe: &SubjectPermission{}, 808 }, 809 } 810 if !reflect.DeepEqual(expected, userInfo) { 811 t.Fatalf("User info did not match expected, expected auto-deny permissions on callout subject") 812 } 813 814 // Bearer token - this has no permissions see sentinelScope 815 // This is used by all users, and the customization will be in other connect args. 816 // This needs to also be bound to the authorization account. 817 creds = createScopedUser(t, akp, authKP) 818 defer removeFile(t, creds) 819 820 // Send the signing key token. This should switch us to the test account, but the user 821 // is signed with the account signing key 822 nc := ac.Connect(nats.UserCredentials(creds), nats.Token(scopedToken)) 823 824 resp, err = nc.Request(userDirectInfoSubj, nil, time.Second) 825 require_NoError(t, err) 826 response = ServerAPIResponse{Data: &UserInfo{}} 827 err = json.Unmarshal(resp.Data, &response) 828 require_NoError(t, err) 829 830 userInfo = response.Data.(*UserInfo) 831 if userInfo.Account != tpub { 832 t.Fatalf("Expected to be switched to %q, but got %q", tpub, userInfo.Account) 833 } 834 require_True(t, len(userInfo.Permissions.Publish.Allow) == 2) 835 sort.Strings(userInfo.Permissions.Publish.Allow) 836 require_Equal(t, "foo.>", userInfo.Permissions.Publish.Allow[1]) 837 sort.Strings(userInfo.Permissions.Subscribe.Allow) 838 require_True(t, len(userInfo.Permissions.Subscribe.Allow) == 2) 839 require_Equal(t, "foo.>", userInfo.Permissions.Subscribe.Allow[1]) 840 841 _, err = nc.Subscribe("foo.>", func(msg *nats.Msg) { 842 t.Log("got request on foo.>") 843 require_NoError(t, msg.Respond(nil)) 844 }) 845 require_NoError(t, err) 846 847 m, err := nc.Request("foo.bar", nil, time.Second) 848 require_NoError(t, err) 849 require_NotNil(t, m) 850 t.Log("go response from foo.bar") 851 852 nc.Close() 853 } 854 855 func TestAuthCalloutScopedUserAssignedAccount(t *testing.T) { 856 testAuthCalloutScopedUser(t, false) 857 } 858 859 func TestAuthCalloutScopedUserAllAccount(t *testing.T) { 860 testAuthCalloutScopedUser(t, true) 861 } 862 863 const ( 864 curveSeed = "SXAAXMRAEP6JWWHNB6IKFL554IE6LZVT6EY5MBRICPILTLOPHAG73I3YX4" 865 curvePublic = "XAB3NANV3M6N7AHSQP2U5FRWKKUT7EG2ZXXABV4XVXYQRJGM4S2CZGHT" 866 ) 867 868 func TestAuthCalloutServerConfigEncryption(t *testing.T) { 869 tmpl := ` 870 listen: "127.0.0.1:-1" 871 server_name: A 872 authorization { 873 timeout: 1s 874 users: [ { user: "auth", password: "pwd" } ] 875 auth_callout { 876 # Needs to be a public account nkey, will work for both server config and operator mode. 877 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 878 # users that will power the auth callout service. 879 auth_users: [ auth ] 880 # This is a public xkey (x25519). The auth service has the private key. 881 xkey: "%s" 882 } 883 } 884 ` 885 conf := fmt.Sprintf(tmpl, curvePublic) 886 887 rkp, err := nkeys.FromCurveSeed([]byte(curveSeed)) 888 require_NoError(t, err) 889 890 handler := func(m *nats.Msg) { 891 // This will be encrypted. 892 _, err := jwt.DecodeAuthorizationRequestClaims(string(m.Data)) 893 require_Error(t, err) 894 895 xkey := m.Header.Get(AuthRequestXKeyHeader) 896 require_True(t, xkey != _EMPTY_) 897 decrypted, err := rkp.Open(m.Data, xkey) 898 require_NoError(t, err) 899 user, si, ci, opts, _ := decodeAuthRequest(t, decrypted) 900 // The header xkey must match the signed xkey in server info. 901 require_True(t, si.XKey == xkey) 902 require_True(t, si.Name == "A") 903 require_True(t, ci.Host == "127.0.0.1") 904 // Allow dlc user. 905 if opts.Username == "dlc" && opts.Password == "zzz" { 906 ujwt := createAuthUser(t, user, _EMPTY_, globalAccountName, "", nil, 10*time.Minute, nil) 907 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 908 } else if opts.Username == "dlc" && opts.Password == "xxx" { 909 ujwt := createAuthUser(t, user, _EMPTY_, globalAccountName, "", nil, 10*time.Minute, nil) 910 // Encrypt this response. 911 data, err := rkp.Seal(serviceResponse(t, user, si.ID, ujwt, "", 0), si.XKey) // Server's public xkey. 912 require_NoError(t, err) 913 m.Respond(data) 914 } else { 915 // Nil response signals no authentication. 916 m.Respond(nil) 917 } 918 } 919 920 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 921 defer ac.Cleanup() 922 923 ac.Connect(nats.UserInfo("dlc", "zzz")) 924 925 // Authorization services can optionally encrypt the responses using the server's public xkey. 926 ac.Connect(nats.UserInfo("dlc", "xxx")) 927 } 928 929 func TestAuthCalloutOperatorModeEncryption(t *testing.T) { 930 _, spub := createKey(t) 931 sysClaim := jwt.NewAccountClaims(spub) 932 sysClaim.Name = "$SYS" 933 sysJwt, err := sysClaim.Encode(oKp) 934 require_NoError(t, err) 935 936 // TEST account. 937 tkp, tpub := createKey(t) 938 accClaim := jwt.NewAccountClaims(tpub) 939 accClaim.Name = "TEST" 940 accJwt, err := accClaim.Encode(oKp) 941 require_NoError(t, err) 942 943 // AUTH service account. 944 akp, err := nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 945 require_NoError(t, err) 946 947 apub, err := akp.PublicKey() 948 require_NoError(t, err) 949 950 // The authorized user for the service. 951 upub, creds := createAuthServiceUser(t, akp) 952 defer removeFile(t, creds) 953 954 authClaim := jwt.NewAccountClaims(apub) 955 authClaim.Name = "AUTH" 956 authClaim.EnableExternalAuthorization(upub) 957 authClaim.Authorization.AllowedAccounts.Add(tpub) 958 authClaim.Authorization.XKey = curvePublic 959 960 authJwt, err := authClaim.Encode(oKp) 961 require_NoError(t, err) 962 963 conf := fmt.Sprintf(` 964 listen: 127.0.0.1:-1 965 operator: %s 966 system_account: %s 967 resolver: MEM 968 resolver_preload: { 969 %s: %s 970 %s: %s 971 %s: %s 972 } 973 `, ojwt, spub, apub, authJwt, tpub, accJwt, spub, sysJwt) 974 975 rkp, err := nkeys.FromCurveSeed([]byte(curveSeed)) 976 require_NoError(t, err) 977 978 const tokenA = "--XX--" 979 const tokenB = "--ZZ--" 980 981 handler := func(m *nats.Msg) { 982 // Make sure this is an encrypted request. 983 if bytes.HasPrefix(m.Data, []byte(jwtPrefix)) { 984 t.Fatalf("Request not encrypted") 985 } 986 xkey := m.Header.Get(AuthRequestXKeyHeader) 987 require_True(t, xkey != _EMPTY_) 988 decrypted, err := rkp.Open(m.Data, xkey) 989 require_NoError(t, err) 990 user, si, ci, opts, _ := decodeAuthRequest(t, decrypted) 991 // The header xkey must match the signed xkey in server info. 992 require_True(t, si.XKey == xkey) 993 require_True(t, ci.Host == "127.0.0.1") 994 if opts.Token == tokenA { 995 ujwt := createAuthUser(t, user, "dlc", tpub, "", tkp, 0, nil) 996 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 997 } else if opts.Token == tokenB { 998 ujwt := createAuthUser(t, user, "rip", tpub, "", tkp, 0, nil) 999 // Encrypt this response. 1000 data, err := rkp.Seal(serviceResponse(t, user, si.ID, ujwt, "", 0), si.XKey) // Server's public xkey. 1001 require_NoError(t, err) 1002 m.Respond(data) 1003 } else { 1004 m.Respond(nil) 1005 } 1006 } 1007 1008 ac := NewAuthTest(t, conf, handler, nats.UserCredentials(creds)) 1009 defer ac.Cleanup() 1010 1011 // Bearer token etc.. 1012 // This is used by all users, and the customization will be in other connect args. 1013 // This needs to also be bound to the authorization account. 1014 creds = createBasicAccountUser(t, akp) 1015 defer removeFile(t, creds) 1016 1017 // This will receive an encrypted request to the auth service but send plaintext response. 1018 ac.Connect(nats.UserCredentials(creds), nats.Token(tokenA)) 1019 1020 // This will receive an encrypted request to the auth service and send an encrypted response. 1021 ac.Connect(nats.UserCredentials(creds), nats.Token(tokenB)) 1022 } 1023 1024 func TestAuthCalloutServerTags(t *testing.T) { 1025 conf := ` 1026 listen: "127.0.0.1:-1" 1027 server_name: A 1028 server_tags: ["foo", "bar"] 1029 authorization { 1030 users: [ { user: "auth", password: "pwd" } ] 1031 auth_callout { 1032 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1033 auth_users: [ auth ] 1034 } 1035 } 1036 ` 1037 1038 tch := make(chan jwt.TagList, 1) 1039 handler := func(m *nats.Msg) { 1040 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1041 tch <- si.Tags 1042 ujwt := createAuthUser(t, user, _EMPTY_, globalAccountName, "", nil, 10*time.Minute, nil) 1043 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1044 } 1045 1046 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1047 defer ac.Cleanup() 1048 1049 ac.Connect() 1050 1051 tags := <-tch 1052 require_True(t, len(tags) == 2) 1053 require_True(t, tags.Contains("foo")) 1054 require_True(t, tags.Contains("bar")) 1055 } 1056 1057 func TestAuthCalloutServerClusterAndVersion(t *testing.T) { 1058 conf := ` 1059 listen: "127.0.0.1:-1" 1060 server_name: A 1061 authorization { 1062 users: [ { user: "auth", password: "pwd" } ] 1063 auth_callout { 1064 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1065 auth_users: [ auth ] 1066 } 1067 } 1068 cluster { name: HUB } 1069 ` 1070 ch := make(chan string, 2) 1071 handler := func(m *nats.Msg) { 1072 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1073 ch <- si.Cluster 1074 ch <- si.Version 1075 ujwt := createAuthUser(t, user, _EMPTY_, globalAccountName, "", nil, 10*time.Minute, nil) 1076 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1077 } 1078 1079 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1080 defer ac.Cleanup() 1081 1082 ac.Connect() 1083 1084 cluster := <-ch 1085 require_True(t, cluster == "HUB") 1086 1087 version := <-ch 1088 require_True(t, len(version) > 0) 1089 ok, err := versionAtLeastCheckError(version, 2, 10, 0) 1090 require_NoError(t, err) 1091 require_True(t, ok) 1092 } 1093 1094 func TestAuthCalloutErrorResponse(t *testing.T) { 1095 conf := ` 1096 listen: "127.0.0.1:-1" 1097 server_name: A 1098 authorization { 1099 users: [ { user: "auth", password: "pwd" } ] 1100 auth_callout { 1101 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1102 auth_users: [ auth ] 1103 } 1104 } 1105 ` 1106 handler := func(m *nats.Msg) { 1107 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1108 m.Respond(serviceResponse(t, user, si.ID, "", "BAD AUTH", 0)) 1109 } 1110 1111 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1112 defer ac.Cleanup() 1113 1114 ac.RequireConnectError(nats.UserInfo("dlc", "zzz")) 1115 } 1116 1117 func TestAuthCalloutAuthUserFailDoesNotInvokeCallout(t *testing.T) { 1118 conf := ` 1119 listen: "127.0.0.1:-1" 1120 server_name: A 1121 authorization { 1122 users: [ { user: "auth", password: "pwd" } ] 1123 auth_callout { 1124 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1125 auth_users: [ auth ] 1126 } 1127 } 1128 ` 1129 callouts := uint32(0) 1130 handler := func(m *nats.Msg) { 1131 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1132 atomic.AddUint32(&callouts, 1) 1133 m.Respond(serviceResponse(t, user, si.ID, "", "WRONG PASSWORD", 0)) 1134 } 1135 1136 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1137 defer ac.Cleanup() 1138 1139 ac.RequireConnectError(nats.UserInfo("auth", "zzz")) 1140 1141 if atomic.LoadUint32(&callouts) != 0 { 1142 t.Fatalf("Expected callout to not be called") 1143 } 1144 } 1145 1146 func TestAuthCalloutAuthErrEvents(t *testing.T) { 1147 conf := ` 1148 listen: "127.0.0.1:-1" 1149 server_name: A 1150 accounts { 1151 AUTH { users [ {user: "auth", password: "pwd"} ] } 1152 FOO {} 1153 BAR {} 1154 } 1155 authorization { 1156 auth_callout { 1157 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1158 account: AUTH 1159 auth_users: [ auth ] 1160 } 1161 } 1162 ` 1163 1164 handler := func(m *nats.Msg) { 1165 user, si, _, opts, _ := decodeAuthRequest(t, m.Data) 1166 // Allow dlc user and map to the BAZ account. 1167 if opts.Username == "dlc" && opts.Password == "zzz" { 1168 ujwt := createAuthUser(t, user, _EMPTY_, "FOO", "", nil, 0, nil) 1169 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1170 } else if opts.Username == "dlc" { 1171 m.Respond(serviceResponse(t, user, si.ID, "", "WRONG PASSWORD", 0)) 1172 } else { 1173 m.Respond(serviceResponse(t, user, si.ID, "", "BAD CREDS", 0)) 1174 } 1175 } 1176 1177 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1178 defer ac.Cleanup() 1179 1180 // This is where the event fires, in this account. 1181 sub, err := ac.authClient.SubscribeSync(authErrorAccountEventSubj) 1182 require_NoError(t, err) 1183 1184 // This one will use callout since not defined in server config. 1185 ac.Connect(nats.UserInfo("dlc", "zzz")) 1186 checkSubsPending(t, sub, 0) 1187 1188 checkAuthErrEvent := func(user, pass, reason string) { 1189 ac.RequireConnectError(nats.UserInfo(user, pass)) 1190 1191 m, err := sub.NextMsg(time.Second) 1192 require_NoError(t, err) 1193 1194 var dm DisconnectEventMsg 1195 err = json.Unmarshal(m.Data, &dm) 1196 require_NoError(t, err) 1197 1198 if !strings.Contains(dm.Reason, reason) { 1199 t.Fatalf("Expected %q reason, but got %q", reason, dm.Reason) 1200 } 1201 } 1202 1203 checkAuthErrEvent("dlc", "xxx", "WRONG PASSWORD") 1204 checkAuthErrEvent("rip", "abc", "BAD CREDS") 1205 } 1206 1207 func TestAuthCalloutConnectEvents(t *testing.T) { 1208 conf := ` 1209 listen: "127.0.0.1:-1" 1210 server_name: A 1211 accounts { 1212 AUTH { users [ {user: "auth", password: "pwd"} ] } 1213 FOO {} 1214 BAR {} 1215 $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } 1216 } 1217 authorization { 1218 auth_callout { 1219 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1220 account: AUTH 1221 auth_users: [ auth, admin ] 1222 } 1223 } 1224 ` 1225 1226 handler := func(m *nats.Msg) { 1227 user, si, _, opts, _ := decodeAuthRequest(t, m.Data) 1228 // Allow dlc user and map to the BAZ account. 1229 if opts.Username == "dlc" && opts.Password == "zzz" { 1230 ujwt := createAuthUser(t, user, _EMPTY_, "FOO", "", nil, 0, nil) 1231 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1232 } else if opts.Username == "rip" && opts.Password == "xxx" { 1233 ujwt := createAuthUser(t, user, _EMPTY_, "BAR", "", nil, 0, nil) 1234 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1235 } else { 1236 m.Respond(serviceResponse(t, user, si.ID, "", "BAD CREDS", 0)) 1237 } 1238 } 1239 1240 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1241 defer ac.Cleanup() 1242 1243 // Setup system user. 1244 snc := ac.Connect(nats.UserInfo("admin", "s3cr3t!")) 1245 1246 // Allow this connect event to pass us by.. 1247 time.Sleep(250 * time.Millisecond) 1248 1249 // Watch for connect events. 1250 csub, err := snc.SubscribeSync(fmt.Sprintf(connectEventSubj, "*")) 1251 require_NoError(t, err) 1252 1253 // Watch for disconnect events. 1254 dsub, err := snc.SubscribeSync(fmt.Sprintf(disconnectEventSubj, "*")) 1255 require_NoError(t, err) 1256 1257 // Connections updates. Old 1258 acOldSub, err := snc.SubscribeSync(fmt.Sprintf(accConnsEventSubjOld, "*")) 1259 require_NoError(t, err) 1260 1261 // Connections updates. New 1262 acNewSub, err := snc.SubscribeSync(fmt.Sprintf(accConnsEventSubjNew, "*")) 1263 require_NoError(t, err) 1264 1265 snc.Flush() 1266 1267 checkConnectEvents := func(user, pass, acc string) { 1268 nc := ac.Connect(nats.UserInfo(user, pass)) 1269 require_NoError(t, err) 1270 1271 m, err := csub.NextMsg(time.Second) 1272 require_NoError(t, err) 1273 1274 var cm ConnectEventMsg 1275 err = json.Unmarshal(m.Data, &cm) 1276 require_NoError(t, err) 1277 require_True(t, cm.Client.User == user) 1278 require_True(t, cm.Client.Account == acc) 1279 1280 // Check that we have updates, 1 each, for the connections updates. 1281 m, err = acOldSub.NextMsg(time.Second) 1282 require_NoError(t, err) 1283 1284 var anc AccountNumConns 1285 err = json.Unmarshal(m.Data, &anc) 1286 require_NoError(t, err) 1287 require_True(t, anc.AccountStat.Account == acc) 1288 require_True(t, anc.AccountStat.Conns == 1) 1289 1290 m, err = acNewSub.NextMsg(time.Second) 1291 require_NoError(t, err) 1292 1293 err = json.Unmarshal(m.Data, &anc) 1294 require_NoError(t, err) 1295 require_True(t, anc.AccountStat.Account == acc) 1296 require_True(t, anc.AccountStat.Conns == 1) 1297 1298 // Force the disconnect. 1299 nc.Close() 1300 1301 m, err = dsub.NextMsg(time.Second) 1302 require_NoError(t, err) 1303 1304 var dm DisconnectEventMsg 1305 err = json.Unmarshal(m.Data, &dm) 1306 require_NoError(t, err) 1307 1308 m, err = acOldSub.NextMsg(time.Second) 1309 require_NoError(t, err) 1310 err = json.Unmarshal(m.Data, &anc) 1311 require_NoError(t, err) 1312 require_True(t, anc.AccountStat.Account == acc) 1313 require_True(t, anc.AccountStat.Conns == 0) 1314 1315 m, err = acNewSub.NextMsg(time.Second) 1316 require_NoError(t, err) 1317 err = json.Unmarshal(m.Data, &anc) 1318 require_NoError(t, err) 1319 require_True(t, anc.AccountStat.Account == acc) 1320 require_True(t, anc.AccountStat.Conns == 0) 1321 1322 // Make sure no double events sent. 1323 time.Sleep(200 * time.Millisecond) 1324 checkSubsPending(t, csub, 0) 1325 checkSubsPending(t, dsub, 0) 1326 checkSubsPending(t, acOldSub, 0) 1327 checkSubsPending(t, acNewSub, 0) 1328 } 1329 1330 checkConnectEvents("dlc", "zzz", "FOO") 1331 checkConnectEvents("rip", "xxx", "BAR") 1332 } 1333 1334 func TestAuthCalloutBadServer(t *testing.T) { 1335 conf := ` 1336 listen: "127.0.0.1:-1" 1337 server_name: A 1338 accounts { 1339 AUTH { users [ {user: "auth", password: "pwd"} ] } 1340 FOO {} 1341 } 1342 authorization { 1343 auth_callout { 1344 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1345 account: AUTH 1346 auth_users: [ auth ] 1347 } 1348 } 1349 ` 1350 1351 handler := func(m *nats.Msg) { 1352 user, _, _, _, _ := decodeAuthRequest(t, m.Data) 1353 skp, err := nkeys.CreateServer() 1354 require_NoError(t, err) 1355 spk, err := skp.PublicKey() 1356 require_NoError(t, err) 1357 ujwt := createAuthUser(t, user, _EMPTY_, "FOO", "", nil, 0, nil) 1358 m.Respond(serviceResponse(t, user, spk, ujwt, "", 0)) 1359 } 1360 1361 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1362 defer ac.Cleanup() 1363 1364 // This is where the event fires, in this account. 1365 sub, err := ac.authClient.SubscribeSync(authErrorAccountEventSubj) 1366 require_NoError(t, err) 1367 1368 checkAuthErrEvent := func(user, pass, reason string) { 1369 ac.RequireConnectError(nats.UserInfo(user, pass)) 1370 1371 m, err := sub.NextMsg(time.Second) 1372 require_NoError(t, err) 1373 1374 var dm DisconnectEventMsg 1375 err = json.Unmarshal(m.Data, &dm) 1376 require_NoError(t, err) 1377 1378 if !strings.Contains(dm.Reason, reason) { 1379 t.Fatalf("Expected %q reason, but got %q", reason, dm.Reason) 1380 } 1381 } 1382 checkAuthErrEvent("hello", "world", "response is not for server") 1383 } 1384 1385 func TestAuthCalloutBadUser(t *testing.T) { 1386 conf := ` 1387 listen: "127.0.0.1:-1" 1388 server_name: A 1389 accounts { 1390 AUTH { users [ {user: "auth", password: "pwd"} ] } 1391 FOO {} 1392 } 1393 authorization { 1394 auth_callout { 1395 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1396 account: AUTH 1397 auth_users: [ auth ] 1398 } 1399 } 1400 ` 1401 1402 handler := func(m *nats.Msg) { 1403 _, si, _, _, _ := decodeAuthRequest(t, m.Data) 1404 kp, err := nkeys.CreateUser() 1405 require_NoError(t, err) 1406 upk, err := kp.PublicKey() 1407 require_NoError(t, err) 1408 ujwt := createAuthUser(t, upk, _EMPTY_, "FOO", "", nil, 0, nil) 1409 m.Respond(serviceResponse(t, upk, si.ID, ujwt, "", 0)) 1410 } 1411 1412 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1413 defer ac.Cleanup() 1414 1415 // This is where the event fires, in this account. 1416 sub, err := ac.authClient.SubscribeSync(authErrorAccountEventSubj) 1417 require_NoError(t, err) 1418 1419 checkAuthErrEvent := func(user, pass, reason string) { 1420 ac.RequireConnectError(nats.UserInfo(user, pass)) 1421 1422 m, err := sub.NextMsg(time.Second) 1423 require_NoError(t, err) 1424 1425 var dm DisconnectEventMsg 1426 err = json.Unmarshal(m.Data, &dm) 1427 require_NoError(t, err) 1428 1429 if !strings.Contains(dm.Reason, reason) { 1430 t.Fatalf("Expected %q reason, but got %q", reason, dm.Reason) 1431 } 1432 } 1433 checkAuthErrEvent("hello", "world", "auth callout response is not for expected user") 1434 } 1435 1436 func TestAuthCalloutExpiredUser(t *testing.T) { 1437 conf := ` 1438 listen: "127.0.0.1:-1" 1439 server_name: A 1440 accounts { 1441 AUTH { users [ {user: "auth", password: "pwd"} ] } 1442 FOO {} 1443 } 1444 authorization { 1445 auth_callout { 1446 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1447 account: AUTH 1448 auth_users: [ auth ] 1449 } 1450 } 1451 ` 1452 1453 handler := func(m *nats.Msg) { 1454 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1455 ujwt := createAuthUser(t, user, _EMPTY_, "FOO", "", nil, time.Second*-5, nil) 1456 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1457 } 1458 1459 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1460 defer ac.Cleanup() 1461 1462 // This is where the event fires, in this account. 1463 sub, err := ac.authClient.SubscribeSync(authErrorAccountEventSubj) 1464 require_NoError(t, err) 1465 1466 checkAuthErrEvent := func(user, pass, reason string) { 1467 ac.RequireConnectError(nats.UserInfo(user, pass)) 1468 1469 m, err := sub.NextMsg(time.Second) 1470 require_NoError(t, err) 1471 1472 var dm DisconnectEventMsg 1473 err = json.Unmarshal(m.Data, &dm) 1474 require_NoError(t, err) 1475 1476 if !strings.Contains(dm.Reason, reason) { 1477 t.Fatalf("Expected %q reason, but got %q", reason, dm.Reason) 1478 } 1479 } 1480 checkAuthErrEvent("hello", "world", "claim is expired") 1481 } 1482 1483 func TestAuthCalloutExpiredResponse(t *testing.T) { 1484 conf := ` 1485 listen: "127.0.0.1:-1" 1486 server_name: A 1487 accounts { 1488 AUTH { users [ {user: "auth", password: "pwd"} ] } 1489 FOO {} 1490 } 1491 authorization { 1492 auth_callout { 1493 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1494 account: AUTH 1495 auth_users: [ auth ] 1496 } 1497 } 1498 ` 1499 1500 handler := func(m *nats.Msg) { 1501 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1502 ujwt := createAuthUser(t, user, _EMPTY_, "FOO", "", nil, 0, nil) 1503 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", time.Second*-5)) 1504 } 1505 1506 ac := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1507 defer ac.Cleanup() 1508 1509 // This is where the event fires, in this account. 1510 sub, err := ac.authClient.SubscribeSync(authErrorAccountEventSubj) 1511 require_NoError(t, err) 1512 1513 checkAuthErrEvent := func(user, pass, reason string) { 1514 ac.RequireConnectError(nats.UserInfo(user, pass)) 1515 1516 m, err := sub.NextMsg(time.Second) 1517 require_NoError(t, err) 1518 1519 var dm DisconnectEventMsg 1520 err = json.Unmarshal(m.Data, &dm) 1521 require_NoError(t, err) 1522 1523 if !strings.Contains(dm.Reason, reason) { 1524 t.Fatalf("Expected %q reason, but got %q", reason, dm.Reason) 1525 } 1526 } 1527 checkAuthErrEvent("hello", "world", "claim is expired") 1528 } 1529 1530 func TestAuthCalloutOperator_AnyAccount(t *testing.T) { 1531 _, spub := createKey(t) 1532 sysClaim := jwt.NewAccountClaims(spub) 1533 sysClaim.Name = "$SYS" 1534 sysJwt, err := sysClaim.Encode(oKp) 1535 require_NoError(t, err) 1536 1537 // A account. 1538 akp, apk := createKey(t) 1539 aClaim := jwt.NewAccountClaims(apk) 1540 aClaim.Name = "A" 1541 aJwt, err := aClaim.Encode(oKp) 1542 require_NoError(t, err) 1543 1544 // B account. 1545 bkp, bpk := createKey(t) 1546 bClaim := jwt.NewAccountClaims(bpk) 1547 bClaim.Name = "B" 1548 bJwt, err := bClaim.Encode(oKp) 1549 require_NoError(t, err) 1550 1551 // AUTH callout service account. 1552 ckp, err := nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 1553 require_NoError(t, err) 1554 1555 cpk, err := ckp.PublicKey() 1556 require_NoError(t, err) 1557 1558 // The authorized user for the service. 1559 upub, creds := createAuthServiceUser(t, ckp) 1560 defer removeFile(t, creds) 1561 1562 authClaim := jwt.NewAccountClaims(cpk) 1563 authClaim.Name = "AUTH" 1564 authClaim.EnableExternalAuthorization(upub) 1565 authClaim.Authorization.AllowedAccounts.Add("*") 1566 authJwt, err := authClaim.Encode(oKp) 1567 require_NoError(t, err) 1568 1569 conf := fmt.Sprintf(` 1570 listen: 127.0.0.1:-1 1571 operator: %s 1572 system_account: %s 1573 resolver: MEM 1574 resolver_preload: { 1575 %s: %s 1576 %s: %s 1577 %s: %s 1578 %s: %s 1579 } 1580 `, ojwt, spub, cpk, authJwt, apk, aJwt, bpk, bJwt, spub, sysJwt) 1581 1582 handler := func(m *nats.Msg) { 1583 user, si, _, opts, _ := decodeAuthRequest(t, m.Data) 1584 if opts.Token == "PutMeInA" { 1585 ujwt := createAuthUser(t, user, "user_a", apk, "", akp, 0, nil) 1586 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1587 } else if opts.Token == "PutMeInB" { 1588 ujwt := createAuthUser(t, user, "user_b", bpk, "", bkp, 0, nil) 1589 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1590 } else { 1591 m.Respond(nil) 1592 } 1593 1594 } 1595 1596 ac := NewAuthTest(t, conf, handler, nats.UserCredentials(creds)) 1597 defer ac.Cleanup() 1598 resp, err := ac.authClient.Request(userDirectInfoSubj, nil, time.Second) 1599 require_NoError(t, err) 1600 response := ServerAPIResponse{Data: &UserInfo{}} 1601 err = json.Unmarshal(resp.Data, &response) 1602 require_NoError(t, err) 1603 1604 // Bearer token etc.. 1605 // This is used by all users, and the customization will be in other connect args. 1606 // This needs to also be bound to the authorization account. 1607 creds = createBasicAccountUser(t, ckp) 1608 defer removeFile(t, creds) 1609 1610 // We require a token. 1611 ac.RequireConnectError(nats.UserCredentials(creds)) 1612 1613 // Send correct token. This should switch us to the A account. 1614 nc := ac.Connect(nats.UserCredentials(creds), nats.Token("PutMeInA")) 1615 require_NoError(t, err) 1616 1617 resp, err = nc.Request(userDirectInfoSubj, nil, time.Second) 1618 require_NoError(t, err) 1619 response = ServerAPIResponse{Data: &UserInfo{}} 1620 err = json.Unmarshal(resp.Data, &response) 1621 require_NoError(t, err) 1622 userInfo := response.Data.(*UserInfo) 1623 require_Equal(t, userInfo.Account, apk) 1624 1625 nc = ac.Connect(nats.UserCredentials(creds), nats.Token("PutMeInB")) 1626 require_NoError(t, err) 1627 1628 resp, err = nc.Request(userDirectInfoSubj, nil, time.Second) 1629 require_NoError(t, err) 1630 response = ServerAPIResponse{Data: &UserInfo{}} 1631 err = json.Unmarshal(resp.Data, &response) 1632 require_NoError(t, err) 1633 userInfo = response.Data.(*UserInfo) 1634 require_Equal(t, userInfo.Account, bpk) 1635 } 1636 1637 func TestAuthCalloutWSClientTLSCerts(t *testing.T) { 1638 conf := ` 1639 server_name: T 1640 listen: "localhost:-1" 1641 1642 tls { 1643 cert_file = "../test/configs/certs/tlsauth/server.pem" 1644 key_file = "../test/configs/certs/tlsauth/server-key.pem" 1645 ca_file = "../test/configs/certs/tlsauth/ca.pem" 1646 verify = true 1647 } 1648 1649 websocket: { 1650 listen: "localhost:-1" 1651 tls { 1652 cert_file = "../test/configs/certs/tlsauth/server.pem" 1653 key_file = "../test/configs/certs/tlsauth/server-key.pem" 1654 ca_file = "../test/configs/certs/tlsauth/ca.pem" 1655 verify = true 1656 } 1657 } 1658 1659 accounts { 1660 AUTH { users [ {user: "auth", password: "pwd"} ] } 1661 FOO {} 1662 } 1663 authorization { 1664 timeout: 1s 1665 auth_callout { 1666 # Needs to be a public account nkey, will work for both server config and operator mode. 1667 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1668 account: AUTH 1669 auth_users: [ auth ] 1670 } 1671 } 1672 ` 1673 handler := func(m *nats.Msg) { 1674 user, si, ci, _, ctls := decodeAuthRequest(t, m.Data) 1675 require_Equal(t, si.Name, "T") 1676 require_Equal(t, ci.Host, "127.0.0.1") 1677 require_NotEqual(t, ctls, nil) 1678 // Zero since we are verified and will be under verified chains. 1679 require_Equal(t, len(ctls.Certs), 0) 1680 require_Equal(t, len(ctls.VerifiedChains), 1) 1681 // Since we have a CA. 1682 require_Equal(t, len(ctls.VerifiedChains[0]), 2) 1683 blk, _ := pem.Decode([]byte(ctls.VerifiedChains[0][0])) 1684 cert, err := x509.ParseCertificate(blk.Bytes) 1685 require_NoError(t, err) 1686 if strings.HasPrefix(cert.Subject.String(), "CN=example.com") { 1687 // Override blank name here, server will substitute. 1688 ujwt := createAuthUser(t, user, "dlc", "FOO", "", nil, 0, nil) 1689 m.Respond(serviceResponse(t, user, si.ID, ujwt, "", 0)) 1690 } 1691 } 1692 1693 ac := NewAuthTest(t, conf, handler, 1694 nats.UserInfo("auth", "pwd"), 1695 nats.ClientCert("../test/configs/certs/tlsauth/client2.pem", "../test/configs/certs/tlsauth/client2-key.pem"), 1696 nats.RootCAs("../test/configs/certs/tlsauth/ca.pem")) 1697 defer ac.Cleanup() 1698 1699 // Will use client cert to determine user. 1700 nc := ac.WSConnect( 1701 nats.ClientCert("../test/configs/certs/tlsauth/client2.pem", "../test/configs/certs/tlsauth/client2-key.pem"), 1702 nats.RootCAs("../test/configs/certs/tlsauth/ca.pem"), 1703 ) 1704 1705 resp, err := nc.Request(userDirectInfoSubj, nil, time.Second) 1706 require_NoError(t, err) 1707 response := ServerAPIResponse{Data: &UserInfo{}} 1708 err = json.Unmarshal(resp.Data, &response) 1709 require_NoError(t, err) 1710 userInfo := response.Data.(*UserInfo) 1711 1712 require_Equal(t, userInfo.UserID, "dlc") 1713 require_Equal(t, userInfo.Account, "FOO") 1714 } 1715 1716 func testConfClientClose(t *testing.T, respondNil bool) { 1717 conf := ` 1718 listen: "127.0.0.1:-1" 1719 server_name: ZZ 1720 accounts { 1721 AUTH { users [ {user: "auth", password: "pwd"} ] } 1722 } 1723 authorization { 1724 timeout: 1s 1725 auth_callout { 1726 # Needs to be a public account nkey, will work for both server config and operator mode. 1727 issuer: "ABJHLOVMPA4CI6R5KLNGOB4GSLNIY7IOUPAJC4YFNDLQVIOBYQGUWVLA" 1728 account: AUTH 1729 auth_users: [ auth ] 1730 } 1731 } 1732 ` 1733 handler := func(m *nats.Msg) { 1734 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1735 if respondNil { 1736 m.Respond(nil) 1737 } else { 1738 m.Respond(serviceResponse(t, user, si.ID, "", "not today", 0)) 1739 } 1740 } 1741 1742 at := NewAuthTest(t, conf, handler, nats.UserInfo("auth", "pwd")) 1743 defer at.Cleanup() 1744 1745 // This one will use callout since not defined in server config. 1746 _, err := at.NewClient(nats.UserInfo("a", "x")) 1747 require_Error(t, err) 1748 require_True(t, strings.Contains(strings.ToLower(err.Error()), nats.AUTHORIZATION_ERR)) 1749 } 1750 1751 func TestAuthCallout_ClientAuthErrorConf(t *testing.T) { 1752 testConfClientClose(t, true) 1753 testConfClientClose(t, false) 1754 } 1755 1756 func testAuthCall_ClientAuthErrorOperatorMode(t *testing.T, respondNil bool) { 1757 _, spub := createKey(t) 1758 sysClaim := jwt.NewAccountClaims(spub) 1759 sysClaim.Name = "$SYS" 1760 sysJwt, err := sysClaim.Encode(oKp) 1761 require_NoError(t, err) 1762 1763 // AUTH service account. 1764 akp, err := nkeys.FromSeed([]byte(authCalloutIssuerSeed)) 1765 require_NoError(t, err) 1766 1767 apub, err := akp.PublicKey() 1768 require_NoError(t, err) 1769 1770 // The authorized user for the service. 1771 upub, creds := createAuthServiceUser(t, akp) 1772 defer removeFile(t, creds) 1773 1774 authClaim := jwt.NewAccountClaims(apub) 1775 authClaim.Name = "AUTH" 1776 authClaim.EnableExternalAuthorization(upub) 1777 authClaim.Authorization.AllowedAccounts.Add("*") 1778 1779 // the scope for the bearer token which has no permissions 1780 sentinelScope, authKP := newScopedRole(t, "sentinel", nil, nil, false) 1781 sentinelScope.Template.Sub.Deny.Add(">") 1782 sentinelScope.Template.Pub.Deny.Add(">") 1783 sentinelScope.Template.Limits.Subs = 0 1784 sentinelScope.Template.Payload = 0 1785 authClaim.SigningKeys.AddScopedSigner(sentinelScope) 1786 1787 authJwt, err := authClaim.Encode(oKp) 1788 require_NoError(t, err) 1789 1790 conf := fmt.Sprintf(` 1791 listen: 127.0.0.1:-1 1792 operator: %s 1793 system_account: %s 1794 resolver: MEM 1795 resolver_preload: { 1796 %s: %s 1797 %s: %s 1798 } 1799 `, ojwt, spub, apub, authJwt, spub, sysJwt) 1800 1801 handler := func(m *nats.Msg) { 1802 user, si, _, _, _ := decodeAuthRequest(t, m.Data) 1803 if respondNil { 1804 m.Respond(nil) 1805 } else { 1806 m.Respond(serviceResponse(t, user, si.ID, "", "not today", 0)) 1807 } 1808 } 1809 1810 ac := NewAuthTest(t, conf, handler, nats.UserCredentials(creds)) 1811 defer ac.Cleanup() 1812 1813 // Bearer token - this has no permissions see sentinelScope 1814 // This is used by all users, and the customization will be in other connect args. 1815 // This needs to also be bound to the authorization account. 1816 creds = createScopedUser(t, akp, authKP) 1817 defer removeFile(t, creds) 1818 1819 // Send the signing key token. This should switch us to the test account, but the user 1820 // is signed with the account signing key 1821 _, err = ac.NewClient(nats.UserCredentials(creds)) 1822 require_Error(t, err) 1823 require_True(t, strings.Contains(strings.ToLower(err.Error()), nats.AUTHORIZATION_ERR)) 1824 } 1825 1826 func TestAuthCallout_ClientAuthErrorOperatorMode(t *testing.T) { 1827 testAuthCall_ClientAuthErrorOperatorMode(t, true) 1828 testAuthCall_ClientAuthErrorOperatorMode(t, false) 1829 }