github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/integration/suites/broker_auth/broker_auth_test.go (about)

     1  package broker_auth
     2  
     3  import (
     4  	"context"
     5  	"crypto/ed25519"
     6  	"crypto/rsa"
     7  	"crypto/tls"
     8  	"encoding/hex"
     9  	"os"
    10  	"strings"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/choria-io/go-choria/broker/network"
    16  	"github.com/choria-io/go-choria/choria"
    17  	"github.com/choria-io/go-choria/integration/testbroker"
    18  	"github.com/choria-io/go-choria/integration/testutil"
    19  	"github.com/choria-io/tokens"
    20  	"github.com/nats-io/nats.go"
    21  	. "github.com/onsi/ginkgo/v2"
    22  	. "github.com/onsi/gomega"
    23  	"github.com/onsi/gomega/gbytes"
    24  	"github.com/sirupsen/logrus"
    25  )
    26  
    27  // TestBrokerAuthentication is a number of tests that essentially test out broker.ChoriaAuth class
    28  // by starting a broker with a specific configuration file and then using the nats.go client to attempt
    29  // to connect to it, bypass restrictions and more
    30  func TestBrokerAuthentication(t *testing.T) {
    31  	RegisterFailHandler(Fail)
    32  	RunSpecs(t, "Integration/Broker Authentication")
    33  }
    34  
    35  var _ = Describe("Authentication", func() {
    36  	var (
    37  		ctx     context.Context
    38  		cancel  context.CancelFunc
    39  		wg      sync.WaitGroup
    40  		logger  *logrus.Logger
    41  		logbuff *gbytes.Buffer
    42  	)
    43  
    44  	BeforeEach(func() {
    45  		ctx, cancel = context.WithTimeout(context.Background(), 45*time.Second)
    46  		DeferCleanup(func() {
    47  			cancel()
    48  			Eventually(logbuff, 5).Should(gbytes.Say("Choria Network Broker shut down"))
    49  		})
    50  
    51  		logbuff, logger = testutil.GbytesLogger(logrus.DebugLevel)
    52  	})
    53  
    54  	Describe("JWT Auth", func() {
    55  		var (
    56  			edPrivateKey   ed25519.PrivateKey
    57  			edPublicKey    ed25519.PublicKey
    58  			nodeSignerPK   *rsa.PrivateKey
    59  			clientSignerPK *rsa.PrivateKey
    60  		)
    61  
    62  		BeforeEach(func() {
    63  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/anontls.conf", logger)
    64  			Expect(err).ToNot(HaveOccurred())
    65  
    66  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
    67  
    68  			Expect(logbuff.Contents()).To(ContainSubstring("Allowing unverified TLS connections for AAA signed clients"))
    69  			Expect(logbuff.Contents()).To(ContainSubstring("Allowing unverified TLS connections for Provisioner signed servers"))
    70  			Expect(logbuff.Contents()).To(ContainSubstring("TLS required for client connections"))
    71  
    72  			edPublicKey, edPrivateKey, err = choria.Ed25519KeyPair()
    73  			Expect(err).ToNot(HaveOccurred())
    74  
    75  			nodeSignerPK, err = testutil.LoadRSAKey("../../ca/node-signer-key.pem")
    76  			Expect(err).ToNot(HaveOccurred())
    77  			clientSignerPK, err = testutil.LoadRSAKey("../../ca/client-signer-key.pem")
    78  			Expect(err).ToNot(HaveOccurred())
    79  		})
    80  
    81  		Describe("JWT Token Servers", func() {
    82  			It("Should fail for invalid server tokens", func() {
    83  				// signing the server jwt with the client signer which will yield an invalid connection
    84  				jwt, err := testutil.CreateSignedServerJWT(clientSignerPK, edPublicKey, map[string]any{
    85  					"purpose":     tokens.ServerPurpose,
    86  					"public_key":  hex.EncodeToString(edPublicKey),
    87  					"collectives": []string{"c1"},
    88  				})
    89  				Expect(err).ToNot(HaveOccurred())
    90  
    91  				_, err = nats.Connect("nats://localhost:4222",
    92  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
    93  					nats.Token(jwt),
    94  					nats.UserJWT(func() (string, error) {
    95  						return jwt, nil
    96  					}, func(n []byte) ([]byte, error) {
    97  						return choria.Ed25519Sign(edPrivateKey, n)
    98  					}),
    99  				)
   100  				Expect(err).To(MatchError("nats: Authorization Violation"))
   101  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   102  				Eventually(logbuff, 1).Should(gbytes.Say("could not parse server id token: crypto/rsa: verification error"))
   103  				Eventually(logbuff, 1).Should(gbytes.Say("invalid nonce signature or jwt token"))
   104  				Eventually(logbuff, 1).ShouldNot(gbytes.Say("Registering user"))
   105  			})
   106  
   107  			It("Should fail for invalid nonce signatures", func() {
   108  				jwt, err := testutil.CreateSignedServerJWT(nodeSignerPK, edPublicKey, map[string]any{
   109  					"purpose":     tokens.ServerPurpose,
   110  					"public_key":  hex.EncodeToString(edPublicKey),
   111  					"collectives": []string{"c1"},
   112  				})
   113  				Expect(err).ToNot(HaveOccurred())
   114  
   115  				_, err = nats.Connect("nats://localhost:4222",
   116  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   117  					nats.Token(jwt),
   118  					nats.UserJWT(func() (string, error) {
   119  						return jwt, nil
   120  					}, func(n []byte) ([]byte, error) {
   121  						// we create an invalid nonce signature so this must fail
   122  						return []byte("invalid signature"), nil
   123  					}),
   124  				)
   125  				Expect(err).To(MatchError("nats: Authorization Violation"))
   126  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   127  				Eventually(logbuff, 1).Should(gbytes.Say("nonce signature verification failed: nonce signature did not verify using pub key in the jwt"))
   128  				Eventually(logbuff, 1).ShouldNot(gbytes.Say("Registering user"))
   129  			})
   130  
   131  			It("Should accept valid servers and set permissions", func() {
   132  				jwt, err := testutil.CreateSignedServerJWT(nodeSignerPK, edPublicKey, map[string]any{
   133  					"purpose":     tokens.ServerPurpose,
   134  					"public_key":  hex.EncodeToString(edPublicKey),
   135  					"collectives": []string{"c1"},
   136  				})
   137  				Expect(err).ToNot(HaveOccurred())
   138  
   139  				clBuffer, clLogger := testutil.GbytesLogger(logrus.DebugLevel)
   140  
   141  				nc, err := nats.Connect("nats://localhost:4222",
   142  					nats.ErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, err error) {
   143  						clLogger.Errorf(strings.ReplaceAll(err.Error(), `"`, ``))
   144  					}),
   145  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   146  					nats.Token(jwt),
   147  					nats.UserJWT(func() (string, error) {
   148  						return jwt, nil
   149  					}, func(n []byte) ([]byte, error) {
   150  						return choria.Ed25519Sign(edPrivateKey, n)
   151  					}),
   152  				)
   153  				Expect(err).ToNot(HaveOccurred())
   154  				defer nc.Close()
   155  
   156  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   157  				Eventually(logbuff, 1).Should(gbytes.Say("Successfully verified nonce signature"))
   158  				Eventually(logbuff, 1).Should(gbytes.Say("Extracted remote identity ginkgo.example.net from JWT token"))
   159  				Eventually(logbuff, 1).Should(gbytes.Say("Setting server permissions based on token claims"))
   160  				Eventually(logbuff, 1).Should(gbytes.Say("Registering user 'ginkgo.example.net' in account 'choria'"))
   161  
   162  				Expect(nc.ConnectedUrl()).To(Equal("nats://localhost:4222"))
   163  				Expect(nc.Publish("choria.lifecycle.x", []byte("x"))).ToNot(HaveOccurred())
   164  				Expect(nc.Publish("choria.machine.transition", []byte("x"))).ToNot(HaveOccurred())
   165  				Expect(nc.Publish("choria.machine.watcher.x", []byte("x"))).ToNot(HaveOccurred())
   166  
   167  				// should not allow submission by default
   168  				Expect(nc.Publish("c1.submission.in.x", []byte("x"))).ToNot(HaveOccurred())
   169  				Eventually(clBuffer, 1).Should(gbytes.Say(`Permissions Violation for Publish to c1.submission.in.x`))
   170  
   171  				// should only allow us to sub to our id
   172  				_, err = nc.Subscribe("c1.node.other.node", func(m *nats.Msg) {})
   173  				Expect(err).ToNot(HaveOccurred())
   174  				Eventually(clBuffer, 1).Should(gbytes.Say("Permissions Violation for Subscription to c1.node.other.node"))
   175  
   176  				_, err = nc.Subscribe("c1.node.ginkgo.example.net", func(m *nats.Msg) {})
   177  				Expect(err).ToNot(HaveOccurred())
   178  				Eventually(clBuffer, 1).ShouldNot(gbytes.Say("Permissions Violation for Subscription"))
   179  
   180  				// should not allow sub collective escape
   181  				_, err = nc.Subscribe("other.node.ginkgo.example.net", func(m *nats.Msg) {})
   182  				Expect(err).ToNot(HaveOccurred())
   183  				Eventually(clBuffer, 1).Should(gbytes.Say("Permissions Violation for Subscription to other.node.ginkgo.example.net"))
   184  
   185  			})
   186  		})
   187  
   188  		Describe("JWT Token Clients", func() {
   189  			It("Should fail for invalid client tokens", func() {
   190  				// signing the client jwt with the server signer which will yield an invalid connection
   191  				jwt, err := testutil.CreateSignedServerJWT(nodeSignerPK, edPublicKey, map[string]any{
   192  					"purpose":    tokens.ClientIDPurpose,
   193  					"callerid":   "up=ginkgo",
   194  					"public_key": hex.EncodeToString(edPublicKey),
   195  				})
   196  				Expect(err).ToNot(HaveOccurred())
   197  
   198  				_, err = nats.Connect("nats://localhost:4222",
   199  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   200  					nats.Token(jwt),
   201  					nats.UserJWT(func() (string, error) {
   202  						return jwt, nil
   203  					}, func(n []byte) ([]byte, error) {
   204  						return choria.Ed25519Sign(edPrivateKey, n)
   205  					}),
   206  				)
   207  				Expect(err).To(MatchError("nats: Authorization Violation"))
   208  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   209  				Eventually(logbuff, 1).Should(gbytes.Say("could not parse client id token: crypto/rsa: verification error"))
   210  				Eventually(logbuff, 1).Should(gbytes.Say("invalid nonce signature or jwt token"))
   211  				Eventually(logbuff, 1).ShouldNot(gbytes.Say("Registering user"))
   212  			})
   213  
   214  			It("Should fail for invalid nonce signatures", func() {
   215  				jwt, err := testutil.CreateSignedServerJWT(clientSignerPK, edPublicKey, map[string]any{
   216  					"purpose":    tokens.ClientIDPurpose,
   217  					"callerid":   "up=ginkgo",
   218  					"public_key": hex.EncodeToString(edPublicKey),
   219  				})
   220  				Expect(err).ToNot(HaveOccurred())
   221  
   222  				_, err = nats.Connect("nats://localhost:4222",
   223  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   224  					nats.Token(jwt),
   225  					nats.UserJWT(func() (string, error) {
   226  						return jwt, nil
   227  					}, func(n []byte) ([]byte, error) {
   228  						// we create an invalid nonce signature so this must fail
   229  						return []byte("invalid signature"), nil
   230  					}),
   231  				)
   232  				Expect(err).To(MatchError("nats: Authorization Violation"))
   233  
   234  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   235  				Eventually(logbuff, 1).Should(gbytes.Say("nonce signature verification failed: nonce signature did not verify using pub key in the jwt"))
   236  				Eventually(logbuff, 1).ShouldNot(gbytes.Say("Registering user"))
   237  			})
   238  
   239  			It("Should require a caller id claim", func() {
   240  				jwt, err := testutil.CreateSignedServerJWT(clientSignerPK, edPublicKey, map[string]any{
   241  					"purpose":    tokens.ClientIDPurpose,
   242  					"public_key": hex.EncodeToString(edPublicKey),
   243  				})
   244  				Expect(err).ToNot(HaveOccurred())
   245  
   246  				_, err = nats.Connect("nats://localhost:4222",
   247  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   248  					nats.Token(jwt),
   249  					nats.UserJWT(func() (string, error) {
   250  						return jwt, nil
   251  					}, func(n []byte) ([]byte, error) {
   252  						return choria.Ed25519Sign(edPrivateKey, n)
   253  					}),
   254  				)
   255  				Expect(err).To(MatchError("nats: Authorization Violation"))
   256  
   257  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   258  				Eventually(logbuff, 1).Should(gbytes.Say("no callerid in claims"))
   259  				Eventually(logbuff, 1).ShouldNot(gbytes.Say("Registering user"))
   260  			})
   261  
   262  			It("Should accept valid clients and set permissions", func() {
   263  				jwt, err := testutil.CreateSignedServerJWT(clientSignerPK, edPublicKey, map[string]any{
   264  					"purpose":    tokens.ClientIDPurpose,
   265  					"callerid":   "up=ginkgo",
   266  					"public_key": hex.EncodeToString(edPublicKey),
   267  				})
   268  				Expect(err).ToNot(HaveOccurred())
   269  
   270  				clBuffer, clLogger := testutil.GbytesLogger(logrus.DebugLevel)
   271  
   272  				nc, err := nats.Connect("nats://localhost:4222",
   273  					nats.ErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, err error) {
   274  						clLogger.Errorf(strings.ReplaceAll(err.Error(), `"`, ``))
   275  					}),
   276  					nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   277  					nats.Token(jwt),
   278  					nats.UserJWT(func() (string, error) {
   279  						return jwt, nil
   280  					}, func(n []byte) ([]byte, error) {
   281  						return choria.Ed25519Sign(edPrivateKey, n)
   282  					}),
   283  				)
   284  				Expect(err).ToNot(HaveOccurred())
   285  				defer nc.Close()
   286  
   287  				Eventually(logbuff, 5).Should(gbytes.Say("Performing JWT based authentication verification"))
   288  				Eventually(logbuff, 1).Should(gbytes.Say("Successfully verified nonce signature"))
   289  				Eventually(logbuff, 1).Should(gbytes.Say("Extracted caller id up=ginkgo from JWT token"))
   290  				Eventually(logbuff, 1).Should(gbytes.Say("Creating ACLs for a private reply subject on \\*.reply.e33bf0376d4accbb4a8fd24b2f840b2e.>"))
   291  				Eventually(logbuff, 1).Should(gbytes.Say("Registering user 'up=ginkgo' in account 'choria'"))
   292  
   293  				// should only access its own replies
   294  				_, err = nc.Subscribe("c1.reply.xxxx.>", func(_ *nats.Msg) {})
   295  				Expect(err).ToNot(HaveOccurred())
   296  				Eventually(logbuff, 1).Should(gbytes.Say("Subscription Violation - User .+up=ginkgo.+, Subject .+c1.reply.xxxx.>"))
   297  				Eventually(clBuffer, 1).Should(gbytes.Say("Permissions Violation for Subscription to c1.reply.xxxx.>"))
   298  
   299  				_, err = nc.Subscribe("c1.reply.e33bf0376d4accbb4a8fd24b2f840b2e.>", func(_ *nats.Msg) {})
   300  				Expect(err).ToNot(HaveOccurred())
   301  				Eventually(logbuff, 1).ShouldNot(gbytes.Say("c1.reply.e33bf0376d4accbb4a8fd24b2f840b2e"))
   302  				Eventually(clBuffer, 1).ShouldNot(gbytes.Say("c1.reply.e33bf0376d4accbb4a8fd24b2f840b2e"))
   303  
   304  				// should not be able to be a node
   305  				_, err = nc.Subscribe("c1.node.other.node", func(m *nats.Msg) {})
   306  				Expect(err).ToNot(HaveOccurred())
   307  				Eventually(clBuffer, 1).Should(gbytes.Say("Permissions Violation for Subscription to c1.node.other.node"))
   308  
   309  			})
   310  		})
   311  	})
   312  
   313  	Describe("In-process connections", func() {
   314  		var broker *network.Server
   315  		var err error
   316  
   317  		Describe("mTLS Broker", func() {
   318  			BeforeEach(func() {
   319  				broker, err = testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/mtls.conf", logger)
   320  				Expect(err).ToNot(HaveOccurred())
   321  				Eventually(logbuff, 1).Should(gbytes.Say("TLS required for client connections"))
   322  				Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   323  			})
   324  
   325  			It("Should allow in process connections to the choria account", func() {
   326  				_, err = nats.Connect("nats://localhost:4222", nats.InProcessServer(broker), nats.Secure(&tls.Config{InsecureSkipVerify: true}))
   327  				Expect(err).ToNot(HaveOccurred())
   328  				Expect(logbuff.Contents()).To(ContainSubstring("Allowing pipe connection without any limitations"))
   329  				Expect(logbuff.Contents()).To(ContainSubstring("Registering user '' in account 'choria'"))
   330  			})
   331  
   332  			It("Should allow in process connections to the system account", func() {
   333  				_, err = nats.Connect("nats://localhost:4222", nats.UserInfo("system", "system"), nats.InProcessServer(broker), nats.Secure(&tls.Config{InsecureSkipVerify: true}))
   334  				Expect(err).ToNot(HaveOccurred())
   335  				Expect(logbuff.Contents()).To(ContainSubstring("Registering user 'system' in account 'system'"))
   336  			})
   337  		})
   338  
   339  		Describe("JWT Broker", func() {
   340  			BeforeEach(func() {
   341  				broker, err = testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/anontls.conf", logger)
   342  				Expect(err).ToNot(HaveOccurred())
   343  
   344  				Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   345  				Expect(logbuff.Contents()).To(ContainSubstring("Allowing unverified TLS connections for AAA signed clients"))
   346  				Expect(logbuff.Contents()).To(ContainSubstring("Allowing unverified TLS connections for Provisioner signed servers"))
   347  				Expect(logbuff.Contents()).To(ContainSubstring("TLS required for client connections"))
   348  			})
   349  
   350  			It("Should allow in process connections to the choria account", func() {
   351  				_, err = nats.Connect("nats://localhost:4222", nats.InProcessServer(broker), nats.Secure(&tls.Config{InsecureSkipVerify: true}))
   352  				Expect(err).ToNot(HaveOccurred())
   353  				Expect(logbuff.Contents()).To(ContainSubstring("Allowing pipe connection without any limitations"))
   354  				Expect(logbuff.Contents()).To(ContainSubstring("Registering user '' in account 'choria'"))
   355  			})
   356  
   357  			It("Should allow in process connections to the system account", func() {
   358  				_, err = nats.Connect("nats://localhost:4222", nats.UserInfo("system", "systemS3cret"), nats.InProcessServer(broker), nats.Secure(&tls.Config{InsecureSkipVerify: true}))
   359  				Expect(err).ToNot(HaveOccurred())
   360  				Expect(logbuff.Contents()).To(ContainSubstring("Registering user 'system' in account 'system'"))
   361  			})
   362  		})
   363  	})
   364  
   365  	Describe("mTLS Connections", FlakeAttempts(5), func() {
   366  		BeforeEach(func() {
   367  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/mtls.conf", logger)
   368  			Expect(err).ToNot(HaveOccurred())
   369  
   370  			Eventually(logbuff, 2).Should(gbytes.Say("TLS required for client connections"))
   371  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   372  		})
   373  
   374  		It("Should reject unverified TLS connections", func() {
   375  			_, err := nats.Connect("nats://localhost:4222",
   376  				nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   377  			)
   378  			Expect(err).To(MatchError("nats: Authorization Violation"))
   379  			Eventually(logbuff, 2).Should(gbytes.Say("Rejecting unverified connection without token"))
   380  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   381  		})
   382  
   383  		It("Should be rejected using the certs from an unknown CA", func() {
   384  			nc, err := nats.Connect("tls://localhost:4222",
   385  				nats.ClientCert(testutil.CertPath("two", "rip.mcollective"), testutil.KeyPath("two", "rip.mcollective")),
   386  				nats.RootCAs(testutil.CertPath("one", "ca")),
   387  			)
   388  			Eventually(logbuff, 5).Should(gbytes.Say("failed to verify.+certificate: x509: certificate signed by unknown authority"))
   389  			Expect(err).To(Or(MatchError("remote error: tls: bad certificate"), MatchError("remote error: tls: unknown certificate authority")))
   390  			Expect(nc).To(BeNil())
   391  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   392  		})
   393  
   394  		It("Should allow connections using the right CA and valid keys", func() {
   395  			nc, err := nats.Connect("tls://localhost:4222",
   396  				nats.ClientCert(testutil.CertPath("one", "rip.mcollective"), testutil.KeyPath("one", "rip.mcollective")),
   397  				nats.RootCAs(testutil.CertPath("one", "ca")),
   398  			)
   399  			Expect(err).ToNot(HaveOccurred())
   400  			defer nc.Close()
   401  
   402  			Eventually(logbuff, 1).Should(gbytes.Say("Registering user '' in account 'choria'"))
   403  			Expect(nc.ConnectedUrl()).To(Equal("tls://localhost:4222"))
   404  		})
   405  	})
   406  
   407  	Describe("System Account Connections", func() {
   408  		BeforeEach(func() {
   409  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/provisioning.conf", logger)
   410  			Expect(err).ToNot(HaveOccurred())
   411  			Eventually(logbuff, 1).Should(gbytes.Say("Allowing unverified TLS connections for provisioning purposes"))
   412  			Eventually(logbuff, 2).Should(gbytes.Say("TLS required for client connections"))
   413  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   414  		})
   415  
   416  		It("Should prevent the system user from connecting without full TLS", func() {
   417  			_, err := nats.Connect("nats://localhost:4222",
   418  				nats.UserInfo("system", "systemS3cret"),
   419  				nats.Secure(&tls.Config{InsecureSkipVerify: true}))
   420  			Expect(err).To(MatchError("nats: Authorization Violation"))
   421  			Expect(logbuff).To(gbytes.Say("Handling unverified TLS system user failed, denying: no JWT token received"))
   422  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   423  		})
   424  
   425  		It("Should verify credentials", func() {
   426  			_, err := nats.Connect("nats://localhost:4222",
   427  				nats.UserInfo("system", "s3cret"),
   428  				nats.ClientCert(testutil.CertPath("one", "rip.mcollective"), testutil.KeyPath("one", "rip.mcollective")),
   429  				nats.RootCAs(testutil.CertPath("one", "ca")))
   430  			Expect(err).To(MatchError("nats: Authorization Violation"))
   431  			Expect(logbuff).To(gbytes.Say("Handling system user failed, denying: invalid system credentials"))
   432  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   433  		})
   434  
   435  		It("Should register correct connections", func() {
   436  			nc, err := nats.Connect("nats://localhost:4222",
   437  				nats.UserInfo("system", "systemS3cret"),
   438  				nats.ClientCert(testutil.CertPath("one", "rip.mcollective"), testutil.KeyPath("one", "rip.mcollective")),
   439  				nats.RootCAs(testutil.CertPath("one", "ca")))
   440  			Expect(err).ToNot(HaveOccurred())
   441  			Expect(nc.ConnectedUrl()).To(Equal("nats://localhost:4222"))
   442  			Expect(logbuff).To(gbytes.Say("Registering user 'system' in account 'system'"))
   443  		})
   444  	})
   445  
   446  	Describe("Provisioning Mode Server Connections", func() {
   447  		var (
   448  			jwt        []byte
   449  			invalidJwt []byte
   450  		)
   451  
   452  		BeforeEach(func() {
   453  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/provisioning.conf", logger)
   454  			Expect(err).ToNot(HaveOccurred())
   455  			Eventually(logbuff, 1).Should(gbytes.Say("Allowing unverified TLS connections for provisioning purposes"))
   456  			Eventually(logbuff, 2).Should(gbytes.Say("TLS required for client connections"))
   457  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   458  
   459  			invalidJwt, err = os.ReadFile("../../ca/invalid-provisioning.jwt")
   460  			Expect(err).ToNot(HaveOccurred())
   461  
   462  			jwt, err = os.ReadFile("../../ca/provisioning.jwt")
   463  			Expect(err).ToNot(HaveOccurred())
   464  		})
   465  
   466  		It("Should fail without a token", func() {
   467  			_, err := nats.Connect("nats://localhost:4222",
   468  				nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   469  			)
   470  			Expect(err).To(MatchError("nats: Authorization Violation"))
   471  			Expect(logbuff).To(gbytes.Say("Rejecting unverified connection without token"))
   472  			Expect(logbuff).To(gbytes.Say("unverified connection without JWT token"))
   473  			Expect(logbuff).To(gbytes.Say("provisioning requires a token"))
   474  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   475  		})
   476  
   477  		It("Should verify the token", func() {
   478  			_, err := nats.Connect("nats://localhost:4222",
   479  				nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   480  				nats.Token(string(invalidJwt)),
   481  			)
   482  			Expect(err).To(MatchError("nats: Authorization Violation"))
   483  
   484  			Expect(logbuff).To(gbytes.Say("Performing JWT based authentication verification"))
   485  			Expect(logbuff).To(gbytes.Say("could not parse provisioner token: crypto/rsa: verification error"))
   486  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   487  		})
   488  
   489  		It("Should accept correctly configured servers", func() {
   490  			nc, err := nats.Connect("nats://localhost:4222",
   491  				nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   492  				nats.Token(string(jwt)),
   493  			)
   494  			Expect(err).ToNot(HaveOccurred())
   495  
   496  			Expect(nc.ConnectedUrl()).To(Equal("nats://localhost:4222"))
   497  			Expect(logbuff).To(gbytes.Say("Performing JWT based authentication verification"))
   498  			Expect(logbuff).To(gbytes.Say("Allowing a provisioning server from using unverified TLS connection from"))
   499  			Expect(logbuff).To(gbytes.Say("Registering user '' in account 'provisioning'"))
   500  			Expect(logbuff).ToNot(gbytes.Say("in account 'choria'"))
   501  		})
   502  	})
   503  
   504  	Describe("Server Provisioner connections", func() {
   505  		It("Should deny the provisioner user over unverified tls", func() {
   506  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/provisioning.conf", logger)
   507  			Expect(err).ToNot(HaveOccurred())
   508  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   509  
   510  			_, err = nats.Connect("nats://localhost:4222",
   511  				nats.Secure(&tls.Config{InsecureSkipVerify: true}),
   512  				nats.UserInfo("provisioner", "s3cret"),
   513  			)
   514  
   515  			Expect(err).To(MatchError("nats: Authorization Violation"))
   516  			Expect(logbuff).To(gbytes.Say("provisioning user is only allowed over verified TLS connections"))
   517  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   518  		})
   519  
   520  		It("Should only accept provisioning connections when configured", func() {
   521  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/mtls.conf", logger)
   522  			Expect(err).ToNot(HaveOccurred())
   523  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   524  
   525  			_, err = nats.Connect("tls://localhost:4222",
   526  				nats.UserInfo("provisioner", "s3cret"),
   527  				nats.ClientCert(testutil.CertPath("one", "rip.mcollective"), testutil.KeyPath("one", "rip.mcollective")),
   528  				nats.RootCAs(testutil.CertPath("one", "ca")),
   529  			)
   530  			Expect(err).To(MatchError("nats: Authorization Violation"))
   531  			Eventually(logbuff, 1).Should(gbytes.Say("provisioning user password not enabled"))
   532  			Expect(logbuff).ToNot(gbytes.Say("Registering user"))
   533  		})
   534  
   535  		It("Should require a password on the connection", func() {
   536  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/provisioning.conf", logger)
   537  			Expect(err).ToNot(HaveOccurred())
   538  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   539  
   540  			_, err = nats.Connect("tls://localhost:4222",
   541  				nats.UserInfo("provisioner", ""),
   542  				nats.ClientCert(testutil.CertPath("one", "rip.mcollective"), testutil.KeyPath("one", "rip.mcollective")),
   543  				nats.RootCAs(testutil.CertPath("one", "ca")),
   544  			)
   545  			Expect(err).To(MatchError("nats: Authorization Violation"))
   546  			Expect(string(logbuff.Contents())).To(MatchRegexp("Handling provisioning user connection failed, denying.+: password required"))
   547  		})
   548  
   549  		It("Should register the connection into the provisioning account", func() {
   550  			_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/provisioning.conf", logger)
   551  			Expect(err).ToNot(HaveOccurred())
   552  			Eventually(logbuff, 1).Should(gbytes.Say("Allowing unverified TLS connections for provisioning purposes"))
   553  			Eventually(logbuff, 1).Should(gbytes.Say("TLS required for client connections"))
   554  			Eventually(logbuff, 1).Should(gbytes.Say("Server is ready"))
   555  
   556  			nc, err := nats.Connect("tls://localhost:4222",
   557  				nats.UserInfo("provisioner", "s3cret"),
   558  				nats.ClientCert(testutil.CertPath("one", "rip.mcollective"), testutil.KeyPath("one", "rip.mcollective")),
   559  				nats.RootCAs(testutil.CertPath("one", "ca")),
   560  			)
   561  			Expect(err).ToNot(HaveOccurred())
   562  			Expect(nc.ConnectedUrl()).To(Equal("tls://localhost:4222"))
   563  			Expect(logbuff).To(gbytes.Say(`Registering user 'provisioner' in account 'provisioning'`))
   564  		})
   565  	})
   566  })