mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 11:48:43 -07:00
253 lines
7.6 KiB
Go
253 lines
7.6 KiB
Go
// Copyright 2018 The NATS Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package test
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/nats-io/gnatsd/server"
|
|
"github.com/nats-io/go-nats"
|
|
"github.com/nats-io/jwt"
|
|
"github.com/nats-io/nkeys"
|
|
)
|
|
|
|
const testOpConfig = "./configs/operator.conf"
|
|
|
|
// This matches ./configs/nkeys_jwts/test.seed
|
|
// Test operator seed.
|
|
var oSeed = []byte("SOAFYNORQLQFJYBYNUGC5D7SH2MXMUX5BFEWWGHN3EK4VGG5TPT5DZP7QU")
|
|
|
|
// This is a signing key seed.
|
|
var skSeed = []byte("SOAEL3NFOTU6YK3DBTEKQYZ2C5IWSVZWWZCQDASBUOHJKBFLVANK27JMMQ")
|
|
|
|
func checkKeys(t *testing.T, opts *server.Options, opc *jwt.OperatorClaims, expected int) {
|
|
// We should have filled in the TrustedKeys here.
|
|
if len(opts.TrustedKeys) != expected {
|
|
t.Fatalf("Should have %d trusted keys, got %d", expected, len(opts.TrustedKeys))
|
|
}
|
|
// Check that we properly placed all keys from the opc into TrustedKeys
|
|
chkMember := func(s string) {
|
|
for _, c := range opts.TrustedKeys {
|
|
if s == c {
|
|
return
|
|
}
|
|
}
|
|
t.Fatalf("Expected %q to be in TrustedKeys", s)
|
|
}
|
|
chkMember(opc.Issuer)
|
|
for _, sk := range opc.SigningKeys {
|
|
chkMember(sk)
|
|
}
|
|
}
|
|
|
|
// This will test that we enforce certain restrictions when you use trusted operators.
|
|
// Like auth is always true, can't define accounts or users, required to define an account resolver, etc.
|
|
func TestOperatorRestrictions(t *testing.T) {
|
|
opts, err := server.ProcessConfigFile(testOpConfig)
|
|
if err != nil {
|
|
t.Fatalf("Error processing config file: %v", err)
|
|
}
|
|
if _, err := server.NewServer(opts); err != nil {
|
|
t.Fatalf("Expected to create a server successfully")
|
|
}
|
|
// TrustedKeys get defined when processing from above, trying again with
|
|
// same opts should not work.
|
|
if _, err := server.NewServer(opts); err == nil {
|
|
t.Fatalf("Expected an error with TrustedKeys defined")
|
|
}
|
|
// Must wipe and rebuild to succeed.
|
|
wipeOpts := func() {
|
|
opts.TrustedKeys = nil
|
|
opts.Accounts = nil
|
|
opts.Users = nil
|
|
opts.Nkeys = nil
|
|
opts.AllowNewAccounts = false
|
|
}
|
|
|
|
wipeOpts()
|
|
opts.Accounts = []*server.Account{&server.Account{Name: "TEST"}}
|
|
if _, err := server.NewServer(opts); err == nil {
|
|
t.Fatalf("Expected an error with Accounts defined")
|
|
}
|
|
wipeOpts()
|
|
opts.Users = []*server.User{&server.User{Username: "TEST"}}
|
|
if _, err := server.NewServer(opts); err == nil {
|
|
t.Fatalf("Expected an error with Users defined")
|
|
}
|
|
wipeOpts()
|
|
opts.Nkeys = []*server.NkeyUser{&server.NkeyUser{Nkey: "TEST"}}
|
|
if _, err := server.NewServer(opts); err == nil {
|
|
t.Fatalf("Expected an error with Nkey Users defined")
|
|
}
|
|
wipeOpts()
|
|
opts.AllowNewAccounts = true
|
|
if _, err := server.NewServer(opts); err == nil {
|
|
t.Fatalf("Expected an error with AllowNewAccounts set to true")
|
|
}
|
|
|
|
wipeOpts()
|
|
opts.AccountResolver = nil
|
|
if _, err := server.NewServer(opts); err == nil {
|
|
t.Fatalf("Expected an error without an AccountResolver defined")
|
|
}
|
|
}
|
|
|
|
func TestOperatorConfig(t *testing.T) {
|
|
opts, err := server.ProcessConfigFile(testOpConfig)
|
|
if err != nil {
|
|
t.Fatalf("Error processing config file: %v", err)
|
|
}
|
|
// Check we have the TrustedOperators
|
|
if len(opts.TrustedOperators) != 1 {
|
|
t.Fatalf("Expected to load the operator")
|
|
}
|
|
_, err = server.NewServer(opts)
|
|
if err != nil {
|
|
t.Fatalf("Expected to create a server: %v", err)
|
|
}
|
|
// We should have filled in the TrustedKeys here.
|
|
// Our master key (issuer) plus the signing keys (3).
|
|
checkKeys(t, opts, opts.TrustedOperators[0], 4)
|
|
}
|
|
|
|
func runOperatorServer(t *testing.T) (*server.Server, *server.Options) {
|
|
return RunServerWithConfig(testOpConfig)
|
|
}
|
|
|
|
func createAccountForOperatorKey(t *testing.T, s *server.Server, seed []byte) (*server.Account, nkeys.KeyPair) {
|
|
t.Helper()
|
|
okp, _ := nkeys.FromSeed(seed)
|
|
akp, _ := nkeys.CreateAccount()
|
|
pub, _ := akp.PublicKey()
|
|
nac := jwt.NewAccountClaims(pub)
|
|
jwt, _ := nac.Encode(okp)
|
|
if err := s.AccountResolver().Store(pub, jwt); err != nil {
|
|
t.Fatalf("Account Resolver returned an error: %v", err)
|
|
}
|
|
return s.LookupAccount(pub), akp
|
|
}
|
|
|
|
func createAccount(t *testing.T, s *server.Server) (*server.Account, nkeys.KeyPair) {
|
|
t.Helper()
|
|
return createAccountForOperatorKey(t, s, oSeed)
|
|
}
|
|
|
|
func createUserCreds(t *testing.T, s *server.Server, akp nkeys.KeyPair) nats.Option {
|
|
t.Helper()
|
|
kp, _ := nkeys.CreateUser()
|
|
pub, _ := kp.PublicKey()
|
|
nuc := jwt.NewUserClaims(pub)
|
|
ujwt, err := nuc.Encode(akp)
|
|
if err != nil {
|
|
t.Fatalf("Error generating user JWT: %v", err)
|
|
}
|
|
userCB := func() (string, error) {
|
|
return ujwt, nil
|
|
}
|
|
sigCB := func(nonce []byte) ([]byte, error) {
|
|
sig, _ := kp.Sign(nonce)
|
|
return sig, nil
|
|
}
|
|
return nats.UserJWT(userCB, sigCB)
|
|
}
|
|
|
|
func TestOperatorServer(t *testing.T) {
|
|
s, opts := runOperatorServer(t)
|
|
defer s.Shutdown()
|
|
|
|
url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port)
|
|
if _, err := nats.Connect(url); err == nil {
|
|
t.Fatalf("Expected to fail with no credentials")
|
|
}
|
|
|
|
_, akp := createAccount(t, s)
|
|
nc, err := nats.Connect(url, createUserCreds(t, s, akp))
|
|
if err != nil {
|
|
t.Fatalf("Error on connect: %v", err)
|
|
}
|
|
nc.Close()
|
|
|
|
// Now create an account from another operator, this should fail.
|
|
okp, _ := nkeys.CreateOperator()
|
|
seed, _ := okp.Seed()
|
|
_, akp = createAccountForOperatorKey(t, s, seed)
|
|
_, err = nats.Connect(url, createUserCreds(t, s, akp))
|
|
if err == nil {
|
|
t.Fatalf("Expected error on connect")
|
|
}
|
|
}
|
|
|
|
func TestOperatorSystemAccount(t *testing.T) {
|
|
s, _ := runOperatorServer(t)
|
|
defer s.Shutdown()
|
|
|
|
// Create an account from another operator, this should fail if used as a system account.
|
|
okp, _ := nkeys.CreateOperator()
|
|
seed, _ := okp.Seed()
|
|
acc, _ := createAccountForOperatorKey(t, s, seed)
|
|
if err := s.SetSystemAccount(acc.Name); err == nil {
|
|
t.Fatalf("Expected this to fail")
|
|
}
|
|
if acc := s.SystemAccount(); acc != nil {
|
|
t.Fatalf("Expected no account to be set for system account")
|
|
}
|
|
|
|
acc, _ = createAccount(t, s)
|
|
if err := s.SetSystemAccount(acc.Name); err != nil {
|
|
t.Fatalf("Expected this succeed, got %v", err)
|
|
}
|
|
if sysAcc := s.SystemAccount(); sysAcc != acc {
|
|
t.Fatalf("Did not get matching account for system account")
|
|
}
|
|
}
|
|
|
|
func TestOperatorSigningKeys(t *testing.T) {
|
|
s, opts := runOperatorServer(t)
|
|
defer s.Shutdown()
|
|
|
|
// Create an account with a signing key, not the master key.
|
|
acc, akp := createAccountForOperatorKey(t, s, skSeed)
|
|
|
|
// Make sure we can set system account.
|
|
if err := s.SetSystemAccount(acc.Name); err != nil {
|
|
t.Fatalf("Expected this succeed, got %v", err)
|
|
}
|
|
|
|
// Make sure we can create users with it too.
|
|
url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port)
|
|
nc, err := nats.Connect(url, createUserCreds(t, s, akp))
|
|
if err != nil {
|
|
t.Fatalf("Error on connect: %v", err)
|
|
}
|
|
nc.Close()
|
|
}
|
|
|
|
func TestOperatorMemResolverPreload(t *testing.T) {
|
|
s, opts := RunServerWithConfig("./configs/resolver_preload.conf")
|
|
|
|
// Make sure we can look up the account.
|
|
acc := s.LookupAccount("ADM2CIIL3RWXBA6T2HW3FODNCQQOUJEHHQD6FKCPVAMHDNTTSMO73ROX")
|
|
if acc == nil {
|
|
t.Fatalf("Expected to properly lookup account")
|
|
}
|
|
sacc := s.SystemAccount()
|
|
if sacc == nil {
|
|
t.Fatalf("Expected to have system account registered")
|
|
}
|
|
if sacc.Name != opts.SystemAccount {
|
|
t.Fatalf("System account does not match, wanted %q, got %q", opts.SystemAccount, sacc.Name)
|
|
}
|
|
}
|