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  }