github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/broker/network/choria_auth_test.go (about)

     1  // Copyright (c) 2020-2023, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package network
     6  
     7  import (
     8  	"crypto/ed25519"
     9  	"crypto/rsa"
    10  	"crypto/tls"
    11  	"crypto/x509"
    12  	"encoding/base64"
    13  	"encoding/hex"
    14  	"io"
    15  	"net"
    16  	"os"
    17  	"path/filepath"
    18  	"runtime"
    19  	"strings"
    20  	"time"
    21  
    22  	"github.com/choria-io/go-choria/choria"
    23  	"github.com/choria-io/go-choria/integration/testutil"
    24  	iu "github.com/choria-io/go-choria/internal/util"
    25  	"github.com/choria-io/tokens"
    26  	"github.com/golang-jwt/jwt/v4"
    27  	"github.com/golang/mock/gomock"
    28  	"github.com/nats-io/nats-server/v2/server"
    29  	. "github.com/onsi/ginkgo/v2"
    30  	. "github.com/onsi/gomega"
    31  	"github.com/sirupsen/logrus"
    32  )
    33  
    34  var _ = Describe("Network Broker/ChoriaAuth", func() {
    35  	var (
    36  		log        *logrus.Entry
    37  		auth       *ChoriaAuth
    38  		user       *server.User
    39  		mockClient *MockClientAuthentication
    40  		mockctl    *gomock.Controller
    41  	)
    42  
    43  	BeforeEach(func() {
    44  		logger := logrus.New()
    45  		logger.Out = io.Discard
    46  		log = logrus.NewEntry(logger)
    47  		auth = &ChoriaAuth{
    48  			clientAllowList: []string{},
    49  			log:             log,
    50  			choriaAccount:   &server.Account{Name: "choria"},
    51  			issuerTokens:    map[string]string{},
    52  		}
    53  		user = &server.User{
    54  			Username:    "bob",
    55  			Password:    "secret",
    56  			Permissions: &server.Permissions{},
    57  		}
    58  
    59  		mockctl = gomock.NewController(GinkgoT())
    60  		mockClient = NewMockClientAuthentication(mockctl)
    61  	})
    62  
    63  	AfterEach(func() {
    64  		mockctl.Finish()
    65  	})
    66  
    67  	createKeyPair := func() (td string, pri *rsa.PrivateKey) {
    68  		td, err := os.MkdirTemp("", "")
    69  		Expect(err).ToNot(HaveOccurred())
    70  
    71  		pri, err = testutil.CreateRSAKeyAndCert(td)
    72  		Expect(err).ToNot(HaveOccurred())
    73  
    74  		return td, pri
    75  	}
    76  
    77  	createSignedServerJWT := func(pk any, pubK []byte, claims map[string]any) string {
    78  		signed, err := testutil.CreateSignedServerJWT(pk, pubK, claims)
    79  		Expect(err).ToNot(HaveOccurred())
    80  
    81  		return signed
    82  	}
    83  
    84  	createSignedClientJWT := func(pk any, claims map[string]any) string {
    85  		signed, err := testutil.CreateSignedClientJWT(pk, claims)
    86  		Expect(err).ToNot(HaveOccurred())
    87  
    88  		return signed
    89  	}
    90  
    91  	Describe("Check", func() {
    92  		Describe("Provisioning user", func() {
    93  			BeforeEach(func() {
    94  				auth.isTLS = true
    95  				auth.provPass = "s3cret"
    96  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
    97  				copts := &server.ClientOpts{Username: "provisioner", Password: "s3cret"}
    98  				mockClient.EXPECT().GetOpts().Return(copts).AnyTimes()
    99  			})
   100  
   101  			It("Should only prov auth when tls is enabled", func() {
   102  				auth.isTLS = false
   103  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{})
   104  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   105  
   106  				Expect(auth.Check(mockClient)).To(BeFalse())
   107  
   108  				auth.isTLS = true
   109  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}).AnyTimes()
   110  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   111  					Expect(user.Account).To(Equal(auth.provisioningAccount))
   112  				})
   113  
   114  				Expect(auth.Check(mockClient)).To(BeTrue())
   115  			})
   116  
   117  			It("Should reject provision user on a plain connection", func() {
   118  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
   119  
   120  				mockClient.EXPECT().GetTLSConnectionState().Return(nil)
   121  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   122  
   123  				Expect(auth.Check(mockClient)).To(BeFalse())
   124  			})
   125  
   126  			It("Should not do provision auth for unverified connections", func() {
   127  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
   128  
   129  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   130  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{})
   131  				Expect(auth.Check(mockClient)).To(BeFalse())
   132  			})
   133  
   134  			It("Should verify the password correctly", func() {
   135  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
   136  				auth.provPass = "other"
   137  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   138  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}).AnyTimes()
   139  
   140  				Expect(auth.Check(mockClient)).To(BeFalse())
   141  			})
   142  
   143  			It("Should do provision auth for verified connections", func() {
   144  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
   145  
   146  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   147  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}).AnyTimes()
   148  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   149  					Expect(user.Account).To(Equal(auth.provisioningAccount))
   150  				})
   151  
   152  				Expect(auth.Check(mockClient)).To(BeTrue())
   153  			})
   154  		})
   155  
   156  		Describe("system user", func() {
   157  			var copts *server.ClientOpts
   158  
   159  			BeforeEach(func() {
   160  				auth.isTLS = true
   161  				auth.systemAccount = &server.Account{Name: "system"}
   162  				auth.systemUser = "system"
   163  				auth.systemPass = "sysTem"
   164  
   165  				copts = &server.ClientOpts{Username: "system", Password: "sysTem"}
   166  				mockClient.EXPECT().GetOpts().Return(copts).AnyTimes()
   167  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   168  			})
   169  
   170  			It("Should verify the password correctly", func() {
   171  				auth.systemPass = "other"
   172  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}).AnyTimes()
   173  
   174  				Expect(auth.Check(mockClient)).To(BeFalse())
   175  			})
   176  
   177  			It("Should register mTLS system users", func() {
   178  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}).AnyTimes()
   179  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   180  					Expect(user.Account).To(Equal(auth.systemAccount))
   181  				})
   182  
   183  				Expect(auth.Check(mockClient)).To(BeTrue())
   184  			})
   185  
   186  			It("Should reject non mTLS system users that has no JWT", func() {
   187  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{}).AnyTimes()
   188  				mockClient.EXPECT().RegisterUser(gomock.Any()).Times(0)
   189  				Expect(auth.Check(mockClient)).To(BeFalse())
   190  			})
   191  
   192  			Describe("JWT based system access", func() {
   193  				var (
   194  					td           string
   195  					privateKey   *rsa.PrivateKey
   196  					edPrivateKey ed25519.PrivateKey
   197  					edPublicKey  ed25519.PublicKey
   198  					err          error
   199  				)
   200  
   201  				BeforeEach(func() {
   202  					td, privateKey = createKeyPair()
   203  					auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
   204  					edPublicKey, edPrivateKey, err = choria.Ed25519KeyPair()
   205  					Expect(err).ToNot(HaveOccurred())
   206  					sig, err := choria.Ed25519Sign(edPrivateKey, []byte("toomanysecrets"))
   207  					mockClient.EXPECT().GetNonce().Return([]byte("toomanysecrets")).AnyTimes()
   208  					Expect(err).ToNot(HaveOccurred())
   209  					copts.Sig = base64.RawURLEncoding.EncodeToString(sig)
   210  					mockClient.EXPECT().Kind().Return(server.CLIENT).AnyTimes()
   211  				})
   212  
   213  				AfterEach(func() {
   214  					os.RemoveAll(td)
   215  				})
   216  
   217  				It("Should reject non mTLS system users with a JWT but without the needed permissions", func() {
   218  					mockClient.EXPECT().RegisterUser(gomock.Any()).Times(0)
   219  					mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{}).AnyTimes()
   220  					copts.Token = createSignedClientJWT(privateKey, map[string]any{
   221  						"purpose":    tokens.ClientIDPurpose,
   222  						"public_key": hex.EncodeToString(edPublicKey),
   223  					})
   224  
   225  					Expect(auth.Check(mockClient)).To(BeFalse())
   226  				})
   227  
   228  				It("Should reject non mTLS system users with a JWT that does not allow system access", func() {
   229  					mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{}).AnyTimes()
   230  					mockClient.EXPECT().RegisterUser(gomock.Any()).Times(0)
   231  
   232  					copts.Token = createSignedClientJWT(privateKey, map[string]any{
   233  						"purpose":     tokens.ClientIDPurpose,
   234  						"public_key":  hex.EncodeToString(edPublicKey),
   235  						"permissions": map[string]bool{},
   236  					})
   237  
   238  					Expect(auth.Check(mockClient)).To(BeFalse())
   239  				})
   240  
   241  				It("Should only accept system users with a JWT over TLS", func() {
   242  					mockClient.EXPECT().GetTLSConnectionState().Return(nil).AnyTimes()
   243  					mockClient.EXPECT().RegisterUser(gomock.Any()).Times(0)
   244  
   245  					copts.Token = createSignedClientJWT(privateKey, map[string]any{
   246  						"purpose":    tokens.ClientIDPurpose,
   247  						"public_key": hex.EncodeToString(edPublicKey),
   248  						"permissions": map[string]bool{
   249  							"system_user": true,
   250  						},
   251  					})
   252  
   253  					Expect(auth.Check(mockClient)).To(BeFalse())
   254  				})
   255  
   256  				It("Should accept non mTLS system users with a correct JWT", func() {
   257  					mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{}).AnyTimes()
   258  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   259  						Expect(user.Account).To(Equal(auth.systemAccount))
   260  					})
   261  
   262  					copts.Token = createSignedClientJWT(privateKey, map[string]any{
   263  						"purpose":    tokens.ClientIDPurpose,
   264  						"public_key": hex.EncodeToString(edPublicKey),
   265  						"permissions": map[string]bool{
   266  							"system_user": true,
   267  						},
   268  					})
   269  
   270  					Expect(auth.Check(mockClient)).To(BeTrue())
   271  				})
   272  			})
   273  		})
   274  	})
   275  
   276  	Describe("handleDefaultConnection", func() {
   277  		var (
   278  			td           string
   279  			privateKey   *rsa.PrivateKey
   280  			edPrivateKey ed25519.PrivateKey
   281  			edPublicKey  ed25519.PublicKey
   282  			copts        *server.ClientOpts
   283  			verifiedConn *tls.ConnectionState
   284  			err          error
   285  		)
   286  
   287  		BeforeEach(func() {
   288  			td, privateKey = createKeyPair()
   289  			auth.serverJwtSigners = []string{filepath.Join(td, "public.pem")}
   290  			edPublicKey, edPrivateKey, err = choria.Ed25519KeyPair()
   291  			Expect(err).ToNot(HaveOccurred())
   292  		})
   293  
   294  		AfterEach(func() {
   295  			os.RemoveAll(td)
   296  		})
   297  
   298  		Describe("Servers", func() {
   299  			BeforeEach(func() {
   300  				auth.serverJwtSigners = []string{filepath.Join(td, "public.pem")}
   301  				auth.clientAllowList = nil
   302  				auth.denyServers = false
   303  
   304  				copts = &server.ClientOpts{
   305  					Token: createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   306  						"purpose":     tokens.ServerPurpose,
   307  						"public_key":  hex.EncodeToString(edPublicKey),
   308  						"collectives": []string{"c1", "c2"},
   309  					}),
   310  				}
   311  				verifiedConn = &tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}
   312  				mockClient.EXPECT().GetOpts().Return(copts).AnyTimes()
   313  				mockClient.EXPECT().Kind().Return(server.CLIENT).AnyTimes()
   314  			})
   315  
   316  			It("Should require a remote", func() {
   317  				_, err := auth.verifyServerJWTBasedAuth(nil, "", nil, "", log)
   318  				Expect(err).To(MatchError("remote client information is required in anonymous TLS or JWT signing modes"))
   319  			})
   320  
   321  			It("Should fail on invalid jwt", func() {
   322  				_, err := auth.verifyServerJWTBasedAuth(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}, "x", nil, "", log)
   323  				Expect(err).To(MatchError("invalid JWT token"))
   324  			})
   325  
   326  			It("Should fail for invalid nonce", func() {
   327  				copts.Sig = "wrong"
   328  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   329  				mockClient.EXPECT().GetNonce().Return([]byte("toomanysecrets"))
   330  
   331  				verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   332  				Expect(err).To(MatchError("invalid nonce signature or jwt token"))
   333  				Expect(verified).To(BeFalse())
   334  			})
   335  
   336  			It("Should deny servers when allow list is set and servers are not allowed", func() {
   337  				auth.clientAllowList = []string{"10.0.0.0/24"}
   338  				auth.denyServers = true
   339  				mockClient.GetOpts().Token = ""
   340  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   341  				mockClient.EXPECT().GetNonce().Return(nil)
   342  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   343  					Expect(user.Username).To(BeEmpty())
   344  					Expect(user.Account).To(Equal(auth.choriaAccount))
   345  					Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   346  						Deny: []string{">"},
   347  					}))
   348  					Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   349  						Deny: []string{">"}},
   350  					))
   351  				})
   352  
   353  				verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   354  				Expect(err).ToNot(HaveOccurred())
   355  				Expect(verified).To(BeTrue())
   356  			})
   357  
   358  			Describe("Server Permissions", func() {
   359  				BeforeEach(func() {
   360  					auth.denyServers = false
   361  					sig, err := choria.Ed25519Sign(edPrivateKey, []byte("toomanysecrets"))
   362  					Expect(err).ToNot(HaveOccurred())
   363  					copts.Sig = base64.RawURLEncoding.EncodeToString(sig)
   364  
   365  					mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   366  					mockClient.EXPECT().GetNonce().Return([]byte("toomanysecrets"))
   367  				})
   368  
   369  				It("Should set strict permissions for a server JWT user", func() {
   370  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   371  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   372  						Expect(user.Account).To(Equal(auth.choriaAccount))
   373  						Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   374  							Allow: []string{
   375  								"c1.broadcast.agent.>",
   376  								"c1.node.ginkgo.example.net",
   377  								"c1.reply.3f7c3a791b0eb10da51dca4cdedb9418.>",
   378  								"c2.broadcast.agent.>",
   379  								"c2.node.ginkgo.example.net",
   380  								"c2.reply.3f7c3a791b0eb10da51dca4cdedb9418.>",
   381  							},
   382  						}))
   383  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   384  							Allow: []string{
   385  								"choria.lifecycle.>",
   386  								"choria.machine.transition",
   387  								"choria.machine.watcher.>",
   388  								"c1.reply.>",
   389  								"c1.broadcast.agent.registration",
   390  								"choria.federation.c1.collective",
   391  								"c2.reply.>",
   392  								"c2.broadcast.agent.registration",
   393  								"choria.federation.c2.collective",
   394  							},
   395  						}))
   396  					})
   397  
   398  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   399  					Expect(err).ToNot(HaveOccurred())
   400  					Expect(verified).To(BeTrue())
   401  				})
   402  
   403  				It("Should support denying servers", func() {
   404  					auth.denyServers = true
   405  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   406  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   407  						Expect(user.Account).To(Equal(auth.choriaAccount))
   408  						Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   409  							Deny: []string{">"},
   410  						}))
   411  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   412  							Deny: []string{">"},
   413  						}))
   414  					})
   415  
   416  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   417  					Expect(err).ToNot(HaveOccurred())
   418  					Expect(verified).To(BeTrue())
   419  				})
   420  
   421  				It("Should handle no collectives being set", func() {
   422  					copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   423  						"purpose":    tokens.ServerPurpose,
   424  						"public_key": hex.EncodeToString(edPublicKey),
   425  					})
   426  
   427  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   428  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   429  						Expect(user.Account).To(Equal(auth.choriaAccount))
   430  						Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   431  							Deny: []string{">"},
   432  						}))
   433  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   434  							Deny: []string{">"},
   435  						}))
   436  					})
   437  
   438  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   439  					Expect(err).ToNot(HaveOccurred())
   440  					Expect(verified).To(BeTrue())
   441  				})
   442  
   443  				It("Should support service hosts", func() {
   444  					copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   445  						"purpose":     tokens.ServerPurpose,
   446  						"public_key":  hex.EncodeToString(edPublicKey),
   447  						"collectives": []string{"c1", "c2"},
   448  						"permissions": &tokens.ServerPermissions{ServiceHost: true},
   449  					})
   450  
   451  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   452  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   453  						Expect(user.Account).To(Equal(auth.choriaAccount))
   454  						Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   455  							Allow: []string{
   456  								"c1.broadcast.agent.>",
   457  								"c1.node.ginkgo.example.net",
   458  								"c1.reply.3f7c3a791b0eb10da51dca4cdedb9418.>",
   459  								"c1.broadcast.service.>",
   460  								"c2.broadcast.agent.>",
   461  								"c2.node.ginkgo.example.net",
   462  								"c2.reply.3f7c3a791b0eb10da51dca4cdedb9418.>",
   463  								"c2.broadcast.service.>",
   464  							},
   465  						}))
   466  					})
   467  
   468  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   469  					Expect(err).ToNot(HaveOccurred())
   470  					Expect(verified).To(BeTrue())
   471  				})
   472  
   473  				It("Should support Governors", func() {
   474  					copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   475  						"purpose":     tokens.ServerPurpose,
   476  						"public_key":  hex.EncodeToString(edPublicKey),
   477  						"collectives": []string{"c1", "c2"},
   478  						"permissions": &tokens.ServerPermissions{Governor: true, Streams: true},
   479  					})
   480  
   481  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   482  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   483  						Expect(user.Account).To(Equal(auth.choriaAccount))
   484  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   485  							Allow: []string{
   486  								"choria.lifecycle.>",
   487  								"choria.machine.transition",
   488  								"choria.machine.watcher.>",
   489  								"c1.reply.>",
   490  								"c1.broadcast.agent.registration",
   491  								"choria.federation.c1.collective",
   492  								"c1.governor.*",
   493  								"c2.reply.>",
   494  								"c2.broadcast.agent.registration",
   495  								"choria.federation.c2.collective",
   496  								"c2.governor.*",
   497  								"$JS.API.STREAM.INFO.*",
   498  								"$JS.API.STREAM.MSG.GET.*",
   499  								"$JS.API.STREAM.MSG.DELETE.*",
   500  								"$JS.API.DIRECT.GET.*",
   501  								"$JS.API.DIRECT.GET.*.>",
   502  								"$JS.API.CONSUMER.CREATE.*",
   503  								"$JS.API.CONSUMER.CREATE.*.>",
   504  								"$JS.API.CONSUMER.DURABLE.CREATE.*.*",
   505  								"$JS.API.CONSUMER.INFO.*.*",
   506  								"$JS.API.CONSUMER.MSG.NEXT.*.*",
   507  								"$JS.ACK.>",
   508  								"$JS.FC.>",
   509  							},
   510  						}))
   511  					})
   512  
   513  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   514  					Expect(err).ToNot(HaveOccurred())
   515  					Expect(verified).To(BeTrue())
   516  				})
   517  
   518  				It("Should support Submission", func() {
   519  					copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   520  						"purpose":     tokens.ServerPurpose,
   521  						"public_key":  hex.EncodeToString(edPublicKey),
   522  						"collectives": []string{"c1", "c2"},
   523  						"permissions": &tokens.ServerPermissions{Submission: true},
   524  					})
   525  
   526  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   527  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   528  						Expect(user.Account).To(Equal(auth.choriaAccount))
   529  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   530  							Allow: []string{
   531  								"choria.lifecycle.>",
   532  								"choria.machine.transition",
   533  								"choria.machine.watcher.>",
   534  								"c1.reply.>",
   535  								"c1.broadcast.agent.registration",
   536  								"choria.federation.c1.collective",
   537  								"c1.submission.in.>",
   538  								"c2.reply.>",
   539  								"c2.broadcast.agent.registration",
   540  								"choria.federation.c2.collective",
   541  								"c2.submission.in.>",
   542  							},
   543  						}))
   544  					})
   545  
   546  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   547  					Expect(err).ToNot(HaveOccurred())
   548  					Expect(verified).To(BeTrue())
   549  				})
   550  
   551  				Describe("Should support Streams", func() {
   552  					It("Should support Streams in the choria org", func() {
   553  						copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   554  							"purpose":     tokens.ServerPurpose,
   555  							"public_key":  hex.EncodeToString(edPublicKey),
   556  							"collectives": []string{"c1", "c2"},
   557  							"permissions": &tokens.ServerPermissions{Streams: true},
   558  						})
   559  
   560  						mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   561  							Expect(user.Username).To(Equal("ginkgo.example.net"))
   562  							Expect(user.Account).To(Equal(auth.choriaAccount))
   563  							Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   564  								Allow: []string{
   565  									"choria.lifecycle.>",
   566  									"choria.machine.transition",
   567  									"choria.machine.watcher.>",
   568  									"c1.reply.>",
   569  									"c1.broadcast.agent.registration",
   570  									"choria.federation.c1.collective",
   571  									"c2.reply.>",
   572  									"c2.broadcast.agent.registration",
   573  									"choria.federation.c2.collective",
   574  									"$JS.API.STREAM.INFO.*",
   575  									"$JS.API.STREAM.MSG.GET.*",
   576  									"$JS.API.STREAM.MSG.DELETE.*",
   577  									"$JS.API.DIRECT.GET.*",
   578  									"$JS.API.DIRECT.GET.*.>",
   579  									"$JS.API.CONSUMER.CREATE.*",
   580  									"$JS.API.CONSUMER.CREATE.*.>",
   581  									"$JS.API.CONSUMER.DURABLE.CREATE.*.*",
   582  									"$JS.API.CONSUMER.INFO.*.*",
   583  									"$JS.API.CONSUMER.MSG.NEXT.*.*",
   584  									"$JS.ACK.>",
   585  									"$JS.FC.>",
   586  								},
   587  							}))
   588  						})
   589  
   590  						verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   591  						Expect(err).ToNot(HaveOccurred())
   592  						Expect(verified).To(BeTrue())
   593  					})
   594  					It("Should support Streams in other orgs", func() {
   595  						copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   596  							"purpose":     tokens.ServerPurpose,
   597  							"public_key":  hex.EncodeToString(edPublicKey),
   598  							"collectives": []string{"c1", "c2"},
   599  							"ou":          "other",
   600  							"permissions": &tokens.ServerPermissions{Streams: true},
   601  						})
   602  
   603  						mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   604  							Expect(user.Username).To(Equal("ginkgo.example.net"))
   605  							Expect(user.Account).To(Equal(auth.choriaAccount))
   606  							Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   607  								Allow: []string{
   608  									"choria.lifecycle.>",
   609  									"choria.machine.transition",
   610  									"choria.machine.watcher.>",
   611  									"c1.reply.>",
   612  									"c1.broadcast.agent.registration",
   613  									"choria.federation.c1.collective",
   614  									"c2.reply.>",
   615  									"c2.broadcast.agent.registration",
   616  									"choria.federation.c2.collective",
   617  									"choria.streams.STREAM.INFO.*",
   618  									"choria.streams.STREAM.MSG.GET.*",
   619  									"choria.streams.STREAM.MSG.DELETE.*",
   620  									"choria.streams.DIRECT.GET.*",
   621  									"choria.streams.DIRECT.GET.*.>",
   622  									"choria.streams.CONSUMER.CREATE.*",
   623  									"choria.streams.CONSUMER.CREATE.*.>",
   624  									"choria.streams.CONSUMER.DURABLE.CREATE.*.*",
   625  									"choria.streams.CONSUMER.INFO.*.*",
   626  									"choria.streams.CONSUMER.MSG.NEXT.*.*",
   627  									"$JS.ACK.>",
   628  									"$JS.FC.>",
   629  								},
   630  							}))
   631  						})
   632  
   633  						verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   634  						Expect(err).ToNot(HaveOccurred())
   635  						Expect(verified).To(BeTrue())
   636  					})
   637  				})
   638  
   639  				It("Should support additional subjects", func() {
   640  					copts.Token = createSignedServerJWT(privateKey, edPublicKey, map[string]any{
   641  						"purpose":      tokens.ServerPurpose,
   642  						"public_key":   hex.EncodeToString(edPublicKey),
   643  						"collectives":  []string{"c1", "c2"},
   644  						"pub_subjects": []string{"other", "subject"},
   645  					})
   646  
   647  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   648  						Expect(user.Username).To(Equal("ginkgo.example.net"))
   649  						Expect(user.Account).To(Equal(auth.choriaAccount))
   650  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   651  							Allow: []string{
   652  								"choria.lifecycle.>",
   653  								"choria.machine.transition",
   654  								"choria.machine.watcher.>",
   655  								"other",
   656  								"subject",
   657  								"c1.reply.>",
   658  								"c1.broadcast.agent.registration",
   659  								"choria.federation.c1.collective",
   660  								"c2.reply.>",
   661  								"c2.broadcast.agent.registration",
   662  								"choria.federation.c2.collective",
   663  							},
   664  						}))
   665  					})
   666  
   667  					verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   668  					Expect(err).ToNot(HaveOccurred())
   669  					Expect(verified).To(BeTrue())
   670  
   671  				})
   672  			})
   673  		})
   674  
   675  		Describe("Clients", func() {
   676  			BeforeEach(func() {
   677  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
   678  				copts = &server.ClientOpts{
   679  					Token: createSignedClientJWT(privateKey, map[string]any{
   680  						"purpose":    tokens.ClientIDPurpose,
   681  						"public_key": hex.EncodeToString(edPublicKey),
   682  					}),
   683  				}
   684  				verifiedConn = &tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}
   685  				mockClient.EXPECT().GetOpts().Return(copts).AnyTimes()
   686  				mockClient.EXPECT().Kind().Return(server.CLIENT).AnyTimes()
   687  			})
   688  
   689  			It("Should require a remote", func() {
   690  				_, err := auth.verifyClientJWTBasedAuth(nil, "", nil, "", log)
   691  				Expect(err).To(MatchError("remote client information is required in anonymous TLS or JWT signing modes"))
   692  			})
   693  
   694  			It("Should fail on invalid jwt", func() {
   695  				_, err := auth.verifyClientJWTBasedAuth(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}, "x", nil, "", log)
   696  				Expect(err).To(MatchError("invalid JWT token"))
   697  			})
   698  
   699  			It("Should fail for invalid nonce", func() {
   700  				copts.Sig = "wrong"
   701  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   702  				mockClient.EXPECT().GetNonce().Return([]byte("toomanysecrets"))
   703  
   704  				verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   705  				Expect(err).To(MatchError("invalid nonce signature or jwt token"))
   706  				Expect(verified).To(BeFalse())
   707  			})
   708  
   709  			It("Should set strict permissions for a client JWT user", func() {
   710  				sig, err := choria.Ed25519Sign(edPrivateKey, []byte("toomanysecrets"))
   711  				Expect(err).ToNot(HaveOccurred())
   712  				copts.Sig = base64.RawURLEncoding.EncodeToString(sig)
   713  
   714  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   715  				mockClient.EXPECT().GetNonce().Return([]byte("toomanysecrets"))
   716  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   717  					Expect(user.Username).To(Equal("up=ginkgo"))
   718  					Expect(user.Account).To(Equal(auth.choriaAccount))
   719  					Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   720  						Allow: []string{"*.reply.e33bf0376d4accbb4a8fd24b2f840b2e.>"},
   721  					}))
   722  					Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   723  						Allow: []string{"$SYS.REQ.USER.INFO"},
   724  					}))
   725  				})
   726  
   727  				verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   728  				Expect(err).ToNot(HaveOccurred())
   729  				Expect(verified).To(BeTrue())
   730  			})
   731  
   732  			Context("Org Issuers", func() {
   733  				var td string
   734  				var err error
   735  				var issuerPubk ed25519.PublicKey
   736  
   737  				BeforeEach(func() {
   738  					td, err = os.MkdirTemp("", "")
   739  					Expect(err).ToNot(HaveOccurred())
   740  
   741  					issuerPubk, _, err = iu.Ed25519KeyPair()
   742  					Expect(err).ToNot(HaveOccurred())
   743  
   744  					auth.issuerTokens = map[string]string{"choria": hex.EncodeToString(issuerPubk)}
   745  
   746  					// make sure no token is set so not accidentally entering jwt validation
   747  					copts.Token = ""
   748  					auth.isTLS = true
   749  
   750  					DeferCleanup(func() {
   751  						os.RemoveAll(td)
   752  					})
   753  				})
   754  
   755  				It("Should deny other clients", func() {
   756  					auth.allowIssuerBasedTLSAccess = false
   757  
   758  					mockClient.EXPECT().GetNonce().Return([]byte("")).AnyTimes()
   759  					mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   760  					mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{}).AnyTimes()
   761  
   762  					Expect(auth.Check(mockClient)).To(BeFalse())
   763  				})
   764  
   765  				It("Should support allowing pub sub clients", func() {
   766  					auth.allowIssuerBasedTLSAccess = true
   767  
   768  					mockClient.EXPECT().GetNonce().Return([]byte("")).AnyTimes()
   769  					mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""}).AnyTimes()
   770  					mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{nil}}).AnyTimes()
   771  
   772  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   773  						Expect(user.Username).To(Equal(""))
   774  						Expect(user.Account).To(Equal(auth.choriaAccount))
   775  						Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
   776  							Allow: []string{">"},
   777  							Deny: []string{
   778  								"*.broadcast.>",
   779  								"*.node.>",
   780  								"*.reply.>",
   781  								"choria.federation.>",
   782  								"choria.lifecycle.>",
   783  								"choria.machine.>",
   784  							},
   785  						}))
   786  
   787  						Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
   788  							Allow: []string{">"},
   789  							Deny: []string{
   790  								"*.broadcast.>",
   791  								"*.node.>",
   792  								"*.reply.>",
   793  								"choria.federation.>",
   794  								"choria.lifecycle.>",
   795  								"choria.machine.>",
   796  							},
   797  						}))
   798  					})
   799  
   800  					Expect(auth.Check(mockClient)).To(BeTrue())
   801  				})
   802  			})
   803  
   804  			It("Should register other clients without restriction", func() {
   805  				mockClient.GetOpts().Token = ""
   806  				mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
   807  				mockClient.EXPECT().GetNonce().Return(nil)
   808  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   809  					Expect(user.Username).To(BeEmpty())
   810  					Expect(user.Account).To(Equal(auth.choriaAccount))
   811  					Expect(user.Permissions.Subscribe).To(BeNil())
   812  					Expect(user.Permissions.Publish).To(BeNil())
   813  				})
   814  
   815  				verified, err := auth.handleDefaultConnection(mockClient, verifiedConn, true, log)
   816  				Expect(err).ToNot(HaveOccurred())
   817  				Expect(verified).To(BeTrue())
   818  			})
   819  		})
   820  
   821  		Describe("verifyNonceSignature", func() {
   822  			It("Should fail when no signature is given", func() {
   823  				ok, err := auth.verifyNonceSignature(nil, "", "", log)
   824  				Expect(ok).To(BeFalse())
   825  				Expect(err).To(MatchError("connection nonce was not signed"))
   826  			})
   827  
   828  			It("Should fail when no public key is in the jwt", func() {
   829  				ok, err := auth.verifyNonceSignature(nil, "x", "", log)
   830  				Expect(ok).To(BeFalse())
   831  				Expect(err).To(MatchError("no public key found in the JWT to verify nonce signature"))
   832  			})
   833  
   834  			It("Should fail when the server did not set a nonce", func() {
   835  				ok, err := auth.verifyNonceSignature(nil, "x", "x", log)
   836  				Expect(ok).To(BeFalse())
   837  				Expect(err).To(MatchError("server did not generate a nonce to verify"))
   838  			})
   839  
   840  			It("Should fail for invalid nonce signatures", func() {
   841  				ok, err := auth.verifyNonceSignature([]byte("toomanysecrets"), "x", hex.EncodeToString(edPublicKey), log)
   842  				Expect(ok).To(BeFalse())
   843  				Expect(err).To(MatchError("invalid url encoded signature: illegal base64 data at input byte 0"))
   844  			})
   845  
   846  			It("Should not panic for invalid length public keys", func() {
   847  				nonce := []byte("toomanysecrets")
   848  
   849  				sig, err := choria.Ed25519Sign(edPrivateKey, nonce)
   850  				Expect(err).ToNot(HaveOccurred())
   851  				Expect(sig).To(HaveLen(64))
   852  
   853  				ok, err := auth.verifyNonceSignature(nonce, base64.RawURLEncoding.EncodeToString(sig), hex.EncodeToString([]byte(hex.EncodeToString(edPublicKey))), log)
   854  				Expect(err).To(MatchError("could not verify nonce signature: invalid public key length 64"))
   855  				Expect(ok).To(BeFalse())
   856  			})
   857  
   858  			It("Should pass correct signatures", func() {
   859  				nonce := []byte("toomanysecrets")
   860  
   861  				sig, err := choria.Ed25519Sign(edPrivateKey, nonce)
   862  				Expect(err).ToNot(HaveOccurred())
   863  				Expect(sig).To(HaveLen(64))
   864  
   865  				ok, err := auth.verifyNonceSignature(nonce, base64.RawURLEncoding.EncodeToString(sig), hex.EncodeToString(edPublicKey), log)
   866  				Expect(err).ToNot(HaveOccurred())
   867  				Expect(ok).To(BeTrue())
   868  			})
   869  		})
   870  	})
   871  
   872  	Describe("handleVerifiedSystemAccount", func() {
   873  		It("Should fail without a password", func() {
   874  			auth.systemUser = ""
   875  			auth.systemPass = ""
   876  
   877  			verified, err := auth.handleVerifiedSystemAccount(mockClient, log)
   878  			Expect(err).To(MatchError("system user is required"))
   879  			Expect(verified).To(BeFalse())
   880  
   881  			auth.systemUser = "system"
   882  			verified, err = auth.handleVerifiedSystemAccount(mockClient, log)
   883  			Expect(err).To(MatchError("system password is required"))
   884  			Expect(verified).To(BeFalse())
   885  		})
   886  
   887  		It("Should fail without an account", func() {
   888  			auth.systemUser = "system"
   889  			auth.systemPass = "s3cret"
   890  
   891  			verified, err := auth.handleVerifiedSystemAccount(mockClient, log)
   892  			Expect(err).To(MatchError("system account is not set"))
   893  			Expect(verified).To(BeFalse())
   894  		})
   895  
   896  		It("Should verify the password", func() {
   897  			auth.systemUser = "system"
   898  			auth.systemPass = "other"
   899  			auth.systemAccount = &server.Account{Name: "system"}
   900  
   901  			mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: "system", Password: "s3cret"}).AnyTimes()
   902  			verified, err := auth.handleVerifiedSystemAccount(mockClient, log)
   903  			Expect(err).To(MatchError("invalid system credentials"))
   904  			Expect(verified).To(BeFalse())
   905  		})
   906  
   907  		It("Should correctly verify the password and register the user", func() {
   908  			auth.systemUser = "system"
   909  			auth.systemPass = "s3cret"
   910  			auth.systemAccount = &server.Account{Name: "system"}
   911  
   912  			mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: "system", Password: "s3cret"}).AnyTimes()
   913  			mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
   914  				Expect(user.Username).To(Equal("system"))
   915  				Expect(user.Password).To(Equal("s3cret"))
   916  				Expect(user.Account).To(Equal(auth.systemAccount))
   917  				Expect(user.Permissions).To(Not(BeNil()))
   918  				Expect(user.Permissions.Publish).To(BeNil())
   919  				Expect(user.Permissions.Subscribe).To(BeNil())
   920  				Expect(user.Permissions.Response).To(BeNil())
   921  			})
   922  
   923  			verified, err := auth.handleVerifiedSystemAccount(mockClient, log)
   924  			Expect(err).ToNot(HaveOccurred())
   925  			Expect(verified).To(BeTrue())
   926  		})
   927  	})
   928  
   929  	Describe("handleProvisioningUserConnection", func() {
   930  		It("Should fail without a password", func() {
   931  			auth.provPass = ""
   932  
   933  			verified, err := auth.handleProvisioningUserConnection(mockClient, true)
   934  			Expect(err).To(MatchError("provisioning user password not enabled"))
   935  			Expect(verified).To(BeFalse())
   936  		})
   937  
   938  		It("Should fail without an account", func() {
   939  			auth.provPass = "s3cret"
   940  
   941  			verified, err := auth.handleProvisioningUserConnection(mockClient, true)
   942  			Expect(err).To(MatchError("provisioning account is not set"))
   943  			Expect(verified).To(BeFalse())
   944  		})
   945  
   946  		Context("Using Issuers", func() {
   947  			var td string
   948  			var err error
   949  			var issuerPubk ed25519.PublicKey
   950  			var issuerPrik ed25519.PrivateKey
   951  
   952  			BeforeEach(func() {
   953  				td, err = os.MkdirTemp("", "")
   954  				Expect(err).ToNot(HaveOccurred())
   955  
   956  				issuerPubk, issuerPrik, err = iu.Ed25519KeyPair()
   957  				Expect(err).ToNot(HaveOccurred())
   958  
   959  				auth.issuerTokens = map[string]string{"choria": hex.EncodeToString(issuerPubk)}
   960  
   961  				DeferCleanup(func() {
   962  					os.RemoveAll(td)
   963  				})
   964  			})
   965  
   966  			It("Should require a token", func() {
   967  				auth.provPass = "s3cret"
   968  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
   969  
   970  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret"}).AnyTimes()
   971  
   972  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
   973  				Expect(err).To(MatchError("no token provided in connection"))
   974  				Expect(verified).To(BeFalse())
   975  			})
   976  
   977  			It("Should handle tokens that do not pass validation", func() {
   978  				auth.provPass = "s3cret"
   979  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
   980  
   981  				provPubk, _, err := iu.Ed25519KeyPair()
   982  				Expect(err).ToNot(HaveOccurred())
   983  
   984  				provClaims, err := tokens.NewClientIDClaims("provisioner", nil, "choria", nil, "", "", time.Hour, nil, provPubk)
   985  				Expect(err).ToNot(HaveOccurred())
   986  
   987  				// make sure its expired
   988  				provClaims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(-time.Hour))
   989  				signed, err := tokens.SignToken(provClaims, issuerPrik)
   990  				Expect(err).ToNot(HaveOccurred())
   991  
   992  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret", Token: signed}).AnyTimes()
   993  
   994  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
   995  				Expect(err.Error()).To(MatchRegexp("token is expired by 1h"))
   996  				Expect(verified).To(BeFalse())
   997  			})
   998  
   999  			It("Should require the provisioner permission", func() {
  1000  				auth.provPass = "s3cret"
  1001  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
  1002  
  1003  				provPubk, _, err := iu.Ed25519KeyPair()
  1004  				Expect(err).ToNot(HaveOccurred())
  1005  
  1006  				provClaims, err := tokens.NewClientIDClaims("provisioner", nil, "choria", nil, "", "", time.Hour, nil, provPubk)
  1007  				Expect(err).ToNot(HaveOccurred())
  1008  				signed, err := tokens.SignToken(provClaims, issuerPrik)
  1009  				Expect(err).ToNot(HaveOccurred())
  1010  
  1011  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret", Token: signed}).AnyTimes()
  1012  
  1013  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
  1014  				Expect(err).To(MatchError("provisioner claim is false in token with caller id 'provisioner'"))
  1015  				Expect(verified).To(BeFalse())
  1016  			})
  1017  
  1018  			It("Should support v1 provisioner connections", func() {
  1019  				auth.provWithoutToken = true
  1020  				auth.provPass = "s3cret"
  1021  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
  1022  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret"}).AnyTimes()
  1023  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
  1024  					Expect(user.Username).To(Equal(provisioningUser))
  1025  					Expect(user.Password).To(Equal("s3cret"))
  1026  					Expect(user.Account).To(Equal(auth.provisioningAccount))
  1027  					Expect(user.Permissions).To(Not(BeNil()))
  1028  					Expect(user.Permissions.Publish).To(BeNil())
  1029  					Expect(user.Permissions.Subscribe).To(BeNil())
  1030  					Expect(user.Permissions.Response).To(BeNil())
  1031  				})
  1032  
  1033  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
  1034  				Expect(err).ToNot(HaveOccurred())
  1035  				Expect(verified).To(BeTrue())
  1036  			})
  1037  
  1038  			It("Should correctly verify the password and register the user", func() {
  1039  				auth.provPass = "s3cret"
  1040  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
  1041  
  1042  				provPubk, _, err := iu.Ed25519KeyPair()
  1043  				Expect(err).ToNot(HaveOccurred())
  1044  
  1045  				provClaims, err := tokens.NewClientIDClaims("provisioner", nil, "choria", nil, "", "", time.Hour, &tokens.ClientPermissions{ServerProvisioner: true}, provPubk)
  1046  				Expect(err).ToNot(HaveOccurred())
  1047  				signed, err := tokens.SignToken(provClaims, issuerPrik)
  1048  				Expect(err).ToNot(HaveOccurred())
  1049  
  1050  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret", Token: signed}).AnyTimes()
  1051  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
  1052  					Expect(user.Username).To(Equal(provisioningUser))
  1053  					Expect(user.Password).To(Equal("s3cret"))
  1054  					Expect(user.Account).To(Equal(auth.provisioningAccount))
  1055  					Expect(user.Permissions).To(Not(BeNil()))
  1056  					Expect(user.Permissions.Publish).To(BeNil())
  1057  					Expect(user.Permissions.Subscribe).To(BeNil())
  1058  					Expect(user.Permissions.Response).To(BeNil())
  1059  				})
  1060  
  1061  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
  1062  				Expect(err).ToNot(HaveOccurred())
  1063  				Expect(verified).To(BeTrue())
  1064  			})
  1065  		})
  1066  
  1067  		Context("Using mTLS", func() {
  1068  			It("Should fail when server not in TLS mode", func() {
  1069  				auth.provPass = "s3cret"
  1070  				auth.isTLS = false
  1071  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
  1072  
  1073  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret"}).AnyTimes()
  1074  
  1075  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
  1076  				Expect(err).To(MatchError("provisioning user access requires TLS"))
  1077  				Expect(verified).To(BeFalse())
  1078  			})
  1079  
  1080  			It("Should fail when client is not using TLS", func() {
  1081  				auth.provPass = "s3cret"
  1082  				auth.isTLS = true
  1083  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
  1084  				mockClient.EXPECT().GetTLSConnectionState().Return(nil).AnyTimes()
  1085  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret"}).AnyTimes()
  1086  
  1087  				verified, err := auth.handleProvisioningUserConnection(mockClient, false)
  1088  				Expect(err).To(MatchError("provisioning user is only allowed over verified TLS connections"))
  1089  				Expect(verified).To(BeFalse())
  1090  			})
  1091  
  1092  			It("Should correctly verify the password and register the user", func() {
  1093  				auth.provPass = "s3cret"
  1094  				auth.isTLS = true
  1095  				auth.provisioningAccount = &server.Account{Name: provisioningUser}
  1096  				mockClient.EXPECT().GetTLSConnectionState().Return(&tls.ConnectionState{}).AnyTimes()
  1097  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Username: provisioningUser, Password: "s3cret"}).AnyTimes()
  1098  				mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
  1099  					Expect(user.Username).To(Equal(provisioningUser))
  1100  					Expect(user.Password).To(Equal("s3cret"))
  1101  					Expect(user.Account).To(Equal(auth.provisioningAccount))
  1102  					Expect(user.Permissions).To(Not(BeNil()))
  1103  					Expect(user.Permissions.Publish).To(BeNil())
  1104  					Expect(user.Permissions.Subscribe).To(BeNil())
  1105  					Expect(user.Permissions.Response).To(BeNil())
  1106  				})
  1107  
  1108  				verified, err := auth.handleProvisioningUserConnection(mockClient, true)
  1109  				Expect(err).ToNot(HaveOccurred())
  1110  				Expect(verified).To(BeTrue())
  1111  			})
  1112  		})
  1113  	})
  1114  
  1115  	Describe("handleUnverifiedProvisioningConnection", func() {
  1116  		Describe("Provisioner Client", func() {
  1117  			It("Should not accept connections from the provisioning user without verified TLS", func() {
  1118  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
  1119  				auth.provisioningAccount = &server.Account{Name: "provisioning"}
  1120  
  1121  				copts := &server.ClientOpts{Username: "provisioner", Password: "s3cret"}
  1122  				mockClient.EXPECT().GetOpts().Return(copts).AnyTimes()
  1123  
  1124  				validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1125  				Expect(err).To(MatchError("provisioning user requires a verified connection"))
  1126  				Expect(validated).To(BeFalse())
  1127  			})
  1128  		})
  1129  
  1130  		Context("Org Issuers", func() {
  1131  			var (
  1132  				issuerPubk                    ed25519.PublicKey
  1133  				issuerPrik                    ed25519.PrivateKey
  1134  				valid, invalid, wrongOU, noOU string
  1135  				err                           error
  1136  			)
  1137  
  1138  			BeforeEach(func() {
  1139  				issuerPubk, issuerPrik, err = iu.Ed25519KeyPair()
  1140  				Expect(err).ToNot(HaveOccurred())
  1141  
  1142  				td, err := os.MkdirTemp("", "")
  1143  				Expect(err).ToNot(HaveOccurred())
  1144  				DeferCleanup(func() { os.RemoveAll(td) })
  1145  
  1146  				token, err := tokens.NewProvisioningClaims(false, true, "s3cret", "", "", nil, "example.net", "", "", "choria", "xxx", time.Hour)
  1147  				Expect(err).ToNot(HaveOccurred())
  1148  				valid, err = tokens.SignToken(token, issuerPrik)
  1149  				Expect(err).ToNot(HaveOccurred())
  1150  
  1151  				token, err = tokens.NewProvisioningClaims(false, true, "s3cret", "", "", nil, "example.net", "", "", "choria", "xxx", time.Hour)
  1152  				Expect(err).ToNot(HaveOccurred())
  1153  				token.ExpiresAt = jwt.NewNumericDate(time.Now().Add(-1 * time.Hour))
  1154  				invalid, err = tokens.SignToken(token, issuerPrik)
  1155  				Expect(err).ToNot(HaveOccurred())
  1156  
  1157  				token, err = tokens.NewProvisioningClaims(false, true, "s3cret", "", "", nil, "example.net", "", "", "other", "xxx", time.Hour)
  1158  				Expect(err).ToNot(HaveOccurred())
  1159  				wrongOU, err = tokens.SignToken(token, issuerPrik)
  1160  				Expect(err).ToNot(HaveOccurred())
  1161  
  1162  				token, err = tokens.NewProvisioningClaims(false, true, "s3cret", "", "", nil, "example.net", "", "", "other", "xxx", time.Hour)
  1163  				token.OrganizationUnit = ""
  1164  				Expect(err).ToNot(HaveOccurred())
  1165  				noOU, err = tokens.SignToken(token, issuerPrik)
  1166  				Expect(err).ToNot(HaveOccurred())
  1167  
  1168  				auth.issuerTokens = map[string]string{"choria": hex.EncodeToString(issuerPubk)}
  1169  				auth.provPass = "s3cret"
  1170  			})
  1171  
  1172  			It("Should fail without a provisioner account", func() {
  1173  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{}).AnyTimes()
  1174  
  1175  				validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1176  				Expect(validated).To(BeFalse())
  1177  				Expect(err).To(MatchError("provisioning account is not set"))
  1178  			})
  1179  
  1180  			Describe("Servers", func() {
  1181  				BeforeEach(func() {
  1182  					auth.provisioningAccount = &server.Account{Name: "provisioning"}
  1183  				})
  1184  
  1185  				It("Should fail for invalid tokens", func() {
  1186  					mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: invalid}).AnyTimes()
  1187  
  1188  					validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1189  					Expect(validated).To(BeFalse())
  1190  					Expect(err.Error()).To(MatchRegexp("token is expired by"))
  1191  				})
  1192  
  1193  				It("Should detect missing ou claims", func() {
  1194  					mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: noOU}).AnyTimes()
  1195  
  1196  					validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1197  					Expect(validated).To(BeFalse())
  1198  					Expect(err.Error()).To(MatchRegexp("no ou claim in token"))
  1199  				})
  1200  
  1201  				It("Should detect unconfigured Issuers", func() {
  1202  					mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: wrongOU}).AnyTimes()
  1203  
  1204  					validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1205  					Expect(validated).To(BeFalse())
  1206  					Expect(err.Error()).To(MatchRegexp("no issuer found for ou other"))
  1207  				})
  1208  
  1209  				It("Should set server permissions and register", func() {
  1210  					mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: valid}).AnyTimes()
  1211  					mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
  1212  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
  1213  						Expect(user.Username).To(BeEmpty())
  1214  						Expect(user.Password).To(BeEmpty())
  1215  						Expect(user.Account).To(Equal(auth.provisioningAccount))
  1216  						Expect(user.Permissions).To(Not(BeNil()))
  1217  						Expect(user.Permissions.Subscribe.Allow).To(Equal([]string{
  1218  							"provisioning.node.>",
  1219  							"provisioning.broadcast.agent.discovery",
  1220  							"provisioning.broadcast.agent.rpcutil",
  1221  							"provisioning.broadcast.agent.choria_util",
  1222  							"provisioning.broadcast.agent.choria_provision",
  1223  						}))
  1224  						Expect(user.Permissions.Publish.Allow).To(Equal([]string{
  1225  							"choria.lifecycle.>",
  1226  							"provisioning.reply.>",
  1227  							"provisioning.registration.>",
  1228  						}))
  1229  					})
  1230  
  1231  					validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1232  					Expect(validated).To(BeTrue())
  1233  					Expect(err).ToNot(HaveOccurred())
  1234  				})
  1235  			})
  1236  		})
  1237  
  1238  		Context("mTLS", func() {
  1239  			It("Should fail without a signer cert set or present", func() {
  1240  				t, err := os.ReadFile("testdata/provisioning/invalid.jwt")
  1241  				Expect(err).ToNot(HaveOccurred())
  1242  
  1243  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: string(t)}).AnyTimes()
  1244  				auth.provisioningAccount = &server.Account{Name: "provisioning"}
  1245  
  1246  				validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1247  				Expect(validated).To(BeFalse())
  1248  				Expect(err).To(MatchError("provisioning is not enabled"))
  1249  
  1250  				auth.provisioningTokenSigner = "/nonexisting"
  1251  				validated, err = auth.handleUnverifiedProvisioningConnection(mockClient)
  1252  				Expect(validated).To(BeFalse())
  1253  				Expect(err).To(MatchError("provisioning signer certificate /nonexisting does not exist"))
  1254  			})
  1255  
  1256  			It("Should fail without a provisioner account", func() {
  1257  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{}).AnyTimes()
  1258  
  1259  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
  1260  
  1261  				validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1262  				Expect(validated).To(BeFalse())
  1263  				Expect(err).To(MatchError("provisioning account is not set"))
  1264  			})
  1265  
  1266  			It("Should fail without a token", func() {
  1267  				mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{}).AnyTimes()
  1268  				auth.provisioningAccount = &server.Account{Name: "provisioning"}
  1269  				auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
  1270  
  1271  				validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1272  				Expect(validated).To(BeFalse())
  1273  				Expect(err).To(MatchError("provisioning requires a token"))
  1274  			})
  1275  
  1276  			Describe("Servers", func() {
  1277  				BeforeEach(func() {
  1278  					auth.provisioningTokenSigner = "testdata/ssl/certs/rip.mcollective.pem"
  1279  					auth.provisioningAccount = &server.Account{Name: "provisioning"}
  1280  				})
  1281  
  1282  				It("Should fail for invalid tokens", func() {
  1283  					t, err := os.ReadFile("testdata/provisioning/invalid.jwt")
  1284  					Expect(err).ToNot(HaveOccurred())
  1285  
  1286  					mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: string(t)}).AnyTimes()
  1287  
  1288  					validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1289  					Expect(validated).To(BeFalse())
  1290  					Expect(err).To(MatchError("could not parse provisioner token: crypto/rsa: verification error"))
  1291  				})
  1292  
  1293  				It("Should set server permissions and register", func() {
  1294  					t, err := os.ReadFile("testdata/provisioning/secure.jwt")
  1295  					Expect(err).ToNot(HaveOccurred())
  1296  
  1297  					mockClient.EXPECT().GetOpts().Return(&server.ClientOpts{Token: string(t)}).AnyTimes()
  1298  					mockClient.EXPECT().RemoteAddress().Return(&net.IPAddr{IP: net.ParseIP("192.168.0.1"), Zone: ""})
  1299  					mockClient.EXPECT().RegisterUser(gomock.Any()).Do(func(user *server.User) {
  1300  						Expect(user.Username).To(BeEmpty())
  1301  						Expect(user.Password).To(BeEmpty())
  1302  						Expect(user.Account).To(Equal(auth.provisioningAccount))
  1303  						Expect(user.Permissions).To(Not(BeNil()))
  1304  						Expect(user.Permissions.Subscribe.Allow).To(Equal([]string{
  1305  							"provisioning.node.>",
  1306  							"provisioning.broadcast.agent.discovery",
  1307  							"provisioning.broadcast.agent.rpcutil",
  1308  							"provisioning.broadcast.agent.choria_util",
  1309  							"provisioning.broadcast.agent.choria_provision",
  1310  						}))
  1311  						Expect(user.Permissions.Publish.Allow).To(Equal([]string{
  1312  							"choria.lifecycle.>",
  1313  							"provisioning.reply.>",
  1314  							"provisioning.registration.>",
  1315  						}))
  1316  					})
  1317  
  1318  					validated, err := auth.handleUnverifiedProvisioningConnection(mockClient)
  1319  					Expect(validated).To(BeTrue())
  1320  					Expect(err).ToNot(HaveOccurred())
  1321  				})
  1322  			})
  1323  		})
  1324  	})
  1325  
  1326  	Describe("remoteInClientAllowList", func() {
  1327  		It("Should allow all when no allowlist is set", func() {
  1328  			ipv4Addr, _, err := net.ParseCIDR("192.0.2.1/24")
  1329  			Expect(err).ToNot(HaveOccurred())
  1330  
  1331  			Expect(auth.remoteInClientAllowList(&net.IPAddr{IP: ipv4Addr})).To(BeTrue())
  1332  		})
  1333  
  1334  		It("Should handle nil remotes", func() {
  1335  			Expect(auth.remoteInClientAllowList(nil)).To(BeTrue())
  1336  		})
  1337  
  1338  		It("Should handle invalid remotes", func() {
  1339  			ipv4Addr, _, err := net.ParseCIDR("192.0.2.1/24")
  1340  			Expect(err).ToNot(HaveOccurred())
  1341  
  1342  			auth.clientAllowList = []string{"192.0.2.1/24"}
  1343  			Expect(auth.remoteInClientAllowList(&net.IPAddr{IP: ipv4Addr})).To(BeFalse())
  1344  		})
  1345  
  1346  		It("Should handle simple strings", func() {
  1347  			ipv4Addr, _, err := net.ParseCIDR("192.0.2.1/24")
  1348  			Expect(err).ToNot(HaveOccurred())
  1349  
  1350  			auth.clientAllowList = []string{"192.0.2.1"}
  1351  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv4Addr, Port: 1232})).To(BeTrue())
  1352  		})
  1353  
  1354  		It("Should handle subnets", func() {
  1355  			ipv4Addr, _, err := net.ParseCIDR("192.0.2.1/24")
  1356  			Expect(err).ToNot(HaveOccurred())
  1357  
  1358  			auth.clientAllowList = []string{"192.0.0.0/8"}
  1359  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv4Addr, Port: 1232})).To(BeTrue())
  1360  		})
  1361  
  1362  		It("Should support IPv6", func() {
  1363  			auth.clientAllowList = []string{
  1364  				"2a00:1450::/32",
  1365  				"2a01:1450:4002:801::200e",
  1366  			}
  1367  
  1368  			ipv6Addr, _, err := net.ParseCIDR("2a00:1450:4002:801::200e/64")
  1369  			Expect(err).ToNot(HaveOccurred())
  1370  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv6Addr, Port: 1232})).To(BeTrue())
  1371  
  1372  			ipv6Addr, _, err = net.ParseCIDR("2a01:1450:4002:801::200e/64")
  1373  			Expect(err).ToNot(HaveOccurred())
  1374  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv6Addr, Port: 1232})).To(BeTrue())
  1375  
  1376  			ipv6Addr, _, err = net.ParseCIDR("2a02:1450:4002:801::200e/64")
  1377  			Expect(err).ToNot(HaveOccurred())
  1378  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv6Addr, Port: 1232})).To(BeFalse())
  1379  		})
  1380  
  1381  		It("Should be false for un matched nodes", func() {
  1382  			ipv4Addr, _, err := net.ParseCIDR("192.0.2.1/24")
  1383  			Expect(err).ToNot(HaveOccurred())
  1384  
  1385  			auth.clientAllowList = []string{"127.0.0.0/8"}
  1386  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv4Addr, Port: 1232})).To(BeFalse())
  1387  
  1388  			ipv4Addr, _, err = net.ParseCIDR("127.0.2.1/24")
  1389  			Expect(err).ToNot(HaveOccurred())
  1390  			Expect(auth.remoteInClientAllowList(&net.TCPAddr{IP: ipv4Addr, Port: 1232})).To(BeTrue())
  1391  		})
  1392  	})
  1393  
  1394  	Describe("parseServerJWT", func() {
  1395  		It("Should fail without a cert", func() {
  1396  			_, err := auth.parseServerJWT("")
  1397  			Expect(err).To(MatchError("no Server JWT signer or Organization Issuer set, denying all servers"))
  1398  		})
  1399  
  1400  		It("Should fail for empty JWTs", func() {
  1401  			auth.serverJwtSigners = []string{"testdata/public.pem"}
  1402  			_, err := auth.parseServerJWT("")
  1403  			Expect(err).To(MatchError("no JWT received"))
  1404  		})
  1405  
  1406  		Describe("Issuers", func() {
  1407  			var (
  1408  				issuerPubk, serverPubk ed25519.PublicKey
  1409  				issuerPrik             ed25519.PrivateKey
  1410  				err                    error
  1411  			)
  1412  
  1413  			BeforeEach(func() {
  1414  				issuerPubk, issuerPrik, err = iu.Ed25519KeyPair()
  1415  				Expect(err).ToNot(HaveOccurred())
  1416  				serverPubk, _, err = iu.Ed25519KeyPair()
  1417  				Expect(err).ToNot(HaveOccurred())
  1418  
  1419  				auth.issuerTokens = map[string]string{"choria": hex.EncodeToString(issuerPubk)}
  1420  			})
  1421  
  1422  			It("Should detect missing ou claims", func() {
  1423  				signed := createSignedServerJWT(issuerPrik, serverPubk, map[string]any{
  1424  					"ou": nil,
  1425  				})
  1426  
  1427  				_, err = auth.parseServerJWT(signed)
  1428  				Expect(err.Error()).To(MatchRegexp("no ou claim in token"))
  1429  			})
  1430  
  1431  			It("Should detect unconfigured Issuers", func() {
  1432  				signed := createSignedServerJWT(issuerPrik, serverPubk, map[string]any{
  1433  					"ou": "other",
  1434  				})
  1435  
  1436  				_, err = auth.parseServerJWT(signed)
  1437  				Expect(err.Error()).To(MatchRegexp("no issuer found for ou other"))
  1438  			})
  1439  
  1440  			It("Should parse the token and handle failures", func() {
  1441  				signed := createSignedClientJWT(issuerPrik, map[string]any{
  1442  					"ou": "choria",
  1443  				})
  1444  
  1445  				_, err := auth.parseServerJWT(signed)
  1446  				Expect(err).To(MatchError("failed to parse token issued by the choria chain: not a server token"))
  1447  			})
  1448  
  1449  			It("Should handle valid tokens issued by a chain issuer", func() {
  1450  				// this is for provisioner signing servers
  1451  				chainIssuerPubk, chainIssuerPrik, err := iu.Ed25519KeyPair()
  1452  				Expect(err).ToNot(HaveOccurred())
  1453  				chainIssuer, err := tokens.NewClientIDClaims("chain_issuer", nil, "choria", nil, "", "", time.Hour, nil, chainIssuerPubk)
  1454  				Expect(err).ToNot(HaveOccurred())
  1455  				Expect(chainIssuer.AddOrgIssuerData(issuerPrik)).To(Succeed())
  1456  
  1457  				serverPubk, _, err := iu.Ed25519KeyPair()
  1458  				Expect(err).ToNot(HaveOccurred())
  1459  				server, err := tokens.NewServerClaims("ginkgo.example.net", []string{"choria"}, "choria", nil, nil, serverPubk, "", time.Hour)
  1460  				Expect(err).ToNot(HaveOccurred())
  1461  				Expect(server.AddChainIssuerData(chainIssuer, chainIssuerPrik)).To(Succeed())
  1462  				signed, err := tokens.SignToken(server, chainIssuerPrik)
  1463  				Expect(err).ToNot(HaveOccurred())
  1464  
  1465  				claims, err := auth.parseServerJWT(signed)
  1466  				Expect(err).ToNot(HaveOccurred())
  1467  				Expect(claims.ChoriaIdentity).To(Equal("ginkgo.example.net"))
  1468  			})
  1469  
  1470  			It("Should handle valid tokens issued by the org issuer", func() {
  1471  				pubk, _, err := iu.Ed25519KeyPair()
  1472  				Expect(err).ToNot(HaveOccurred())
  1473  				server, err := tokens.NewServerClaims("ginkgo.example.net", []string{"choria"}, "choria", nil, nil, pubk, "", time.Hour)
  1474  				Expect(err).ToNot(HaveOccurred())
  1475  				signed, err := tokens.SignToken(server, issuerPrik)
  1476  				Expect(err).ToNot(HaveOccurred())
  1477  
  1478  				claims, err := auth.parseServerJWT(signed)
  1479  				Expect(err).ToNot(HaveOccurred())
  1480  				Expect(claims.ChoriaIdentity).To(Equal("ginkgo.example.net"))
  1481  			})
  1482  		})
  1483  
  1484  		Describe("Trusted Signers", func() {
  1485  			It("Should verify JWTs", func() {
  1486  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1487  				Expect(err).ToNot(HaveOccurred())
  1488  
  1489  				auth.serverJwtSigners = []string{hex.EncodeToString(edPublicKey)}
  1490  				signed := createSignedClientJWT(edPriKey, map[string]any{
  1491  					"exp": time.Now().UTC().Add(-time.Hour).Unix(),
  1492  				})
  1493  
  1494  				_, err = auth.parseServerJWT(signed)
  1495  				Expect(err).To(MatchError(jwt.ErrTokenExpired))
  1496  			})
  1497  
  1498  			It("Should check a purpose field", func() {
  1499  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1500  				Expect(err).ToNot(HaveOccurred())
  1501  				auth.serverJwtSigners = []string{hex.EncodeToString(edPublicKey)}
  1502  
  1503  				signed := createSignedClientJWT(edPriKey, nil)
  1504  				_, err = auth.parseServerJWT(signed)
  1505  				Expect(err).To(MatchError(tokens.ErrNotAServerToken))
  1506  
  1507  				signed = createSignedClientJWT(edPriKey, map[string]any{
  1508  					"purpose": "wrong",
  1509  				})
  1510  				_, err = auth.parseServerJWT(signed)
  1511  				Expect(err).To(MatchError(tokens.ErrNotAServerToken))
  1512  			})
  1513  
  1514  			It("Should check the identity", func() {
  1515  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1516  				Expect(err).ToNot(HaveOccurred())
  1517  				auth.serverJwtSigners = []string{hex.EncodeToString(edPublicKey)}
  1518  
  1519  				signed := createSignedClientJWT(edPriKey, map[string]any{
  1520  					"purpose": tokens.ServerPurpose,
  1521  				})
  1522  				_, err = auth.parseServerJWT(signed)
  1523  				Expect(err).To(MatchError("identity not in claims"))
  1524  			})
  1525  
  1526  			It("Should check the public key", func() {
  1527  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1528  				Expect(err).ToNot(HaveOccurred())
  1529  				auth.serverJwtSigners = []string{hex.EncodeToString(edPublicKey)}
  1530  
  1531  				signed := createSignedClientJWT(edPriKey, map[string]any{
  1532  					"purpose":  tokens.ServerPurpose,
  1533  					"identity": "ginkgo.example.net",
  1534  				})
  1535  				_, err = auth.parseServerJWT(signed)
  1536  				Expect(err).To(MatchError("no public key in claims"))
  1537  			})
  1538  
  1539  			It("Should handle public keys that are 64 long file names", func() {
  1540  				if runtime.GOOS == "windows" {
  1541  					Skip("Not supported on windows")
  1542  				}
  1543  
  1544  				td, err := os.MkdirTemp("/tmp", "")
  1545  				Expect(err).ToNot(HaveOccurred())
  1546  				defer os.RemoveAll(td)
  1547  
  1548  				if len(td) > 50 {
  1549  					Skip("Temp directory is too long for filename test")
  1550  				}
  1551  
  1552  				pkPath := filepath.Join(td, strings.Repeat("x", 65-len(td)-strings.Count(td, string(os.PathSeparator))))
  1553  				Expect(pkPath).To(HaveLen(64))
  1554  
  1555  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1556  				Expect(err).ToNot(HaveOccurred())
  1557  				Expect(os.WriteFile(pkPath, []byte(hex.EncodeToString(edPublicKey)), 0600)).To(Succeed())
  1558  
  1559  				auth.serverJwtSigners = []string{pkPath}
  1560  
  1561  				signed := createSignedServerJWT(edPriKey, edPublicKey, map[string]any{
  1562  					"purpose":    tokens.ServerPurpose,
  1563  					"identity":   "ginkgo.example.net",
  1564  					"public_key": hex.EncodeToString(edPublicKey),
  1565  				})
  1566  
  1567  				_, err = auth.parseServerJWT(signed)
  1568  				Expect(err).ToNot(HaveOccurred())
  1569  			})
  1570  
  1571  			It("Should handle multiple public identifiers", func() {
  1572  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1573  				Expect(err).ToNot(HaveOccurred())
  1574  				auth.serverJwtSigners = []string{"/nonexisting", hex.EncodeToString(edPublicKey)}
  1575  
  1576  				signed := createSignedServerJWT(edPriKey, edPublicKey, map[string]any{
  1577  					"purpose":    tokens.ServerPurpose,
  1578  					"identity":   "ginkgo.example.net",
  1579  					"public_key": hex.EncodeToString(edPublicKey),
  1580  				})
  1581  
  1582  				_, err = auth.parseServerJWT(signed)
  1583  				Expect(err).ToNot(HaveOccurred())
  1584  			})
  1585  		})
  1586  	})
  1587  
  1588  	Describe("parseClientIDJWT", func() {
  1589  		var td string
  1590  		var privateKey *rsa.PrivateKey
  1591  
  1592  		BeforeEach(func() {
  1593  			td, privateKey = createKeyPair()
  1594  		})
  1595  
  1596  		AfterEach(func() {
  1597  			os.RemoveAll(td)
  1598  		})
  1599  
  1600  		It("Should fail without a cert", func() {
  1601  			_, err := auth.parseClientIDJWT("")
  1602  			Expect(err).To(MatchError("no Client JWT signer or Organization Issuer set, denying all clients"))
  1603  		})
  1604  
  1605  		It("Should fail for empty JWTs", func() {
  1606  			auth.clientJwtSigners = []string{"testdata/public.pem"}
  1607  			_, err := auth.parseClientIDJWT("")
  1608  			Expect(err).To(MatchError("no JWT received"))
  1609  		})
  1610  
  1611  		Describe("Issuers", func() {
  1612  			var (
  1613  				issuerPubk ed25519.PublicKey
  1614  				issuerPrik ed25519.PrivateKey
  1615  				err        error
  1616  			)
  1617  
  1618  			BeforeEach(func() {
  1619  				issuerPubk, issuerPrik, err = iu.Ed25519KeyPair()
  1620  				Expect(err).ToNot(HaveOccurred())
  1621  				auth.issuerTokens = map[string]string{"choria": hex.EncodeToString(issuerPubk)}
  1622  			})
  1623  
  1624  			It("Should detect missing ou claims", func() {
  1625  				signed := createSignedClientJWT(privateKey, nil)
  1626  
  1627  				_, err := auth.parseClientIDJWT(signed)
  1628  				Expect(err.Error()).To(MatchRegexp("no ou claim in token"))
  1629  			})
  1630  
  1631  			It("Should detect unconfigured Issuers", func() {
  1632  				signed := createSignedClientJWT(privateKey, map[string]any{
  1633  					"exp": time.Now().UTC().Add(-time.Hour).Unix(),
  1634  					"ou":  "other",
  1635  				})
  1636  
  1637  				_, err := auth.parseClientIDJWT(signed)
  1638  				Expect(err.Error()).To(MatchRegexp("no issuer configured for ou 'other'"))
  1639  			})
  1640  
  1641  			It("Should parse the token and handle failures", func() {
  1642  				pubk, _, err := iu.Ed25519KeyPair()
  1643  				Expect(err).ToNot(HaveOccurred())
  1644  
  1645  				signed := createSignedServerJWT(issuerPrik, pubk, map[string]any{
  1646  					"ou": "choria",
  1647  				})
  1648  				_, err = auth.parseClientIDJWT(signed)
  1649  				Expect(err.Error()).To(MatchRegexp("failed to parse client token issued by the choria chain: not a client token"))
  1650  			})
  1651  
  1652  			It("Should handle valid tokens issued by a chain issuer", func() {
  1653  				chainIssuerPubk, chainIssuerPrik, err := iu.Ed25519KeyPair()
  1654  				Expect(err).ToNot(HaveOccurred())
  1655  				chainIssuer, err := tokens.NewClientIDClaims("chain_issuer", nil, "choria", nil, "", "", time.Hour, nil, chainIssuerPubk)
  1656  				Expect(err).ToNot(HaveOccurred())
  1657  				Expect(chainIssuer.AddOrgIssuerData(issuerPrik)).To(Succeed())
  1658  
  1659  				clientPubk, _, err := iu.Ed25519KeyPair()
  1660  				Expect(err).ToNot(HaveOccurred())
  1661  				client, err := tokens.NewClientIDClaims("ginkgo", nil, "choria", nil, "", "", time.Hour, nil, clientPubk)
  1662  				Expect(err).ToNot(HaveOccurred())
  1663  				Expect(client.AddChainIssuerData(chainIssuer, chainIssuerPrik)).To(Succeed())
  1664  				signed, err := tokens.SignToken(client, chainIssuerPrik)
  1665  				Expect(err).ToNot(HaveOccurred())
  1666  
  1667  				claims, err := auth.parseClientIDJWT(signed)
  1668  				Expect(err).ToNot(HaveOccurred())
  1669  				Expect(claims.CallerID).To(Equal("ginkgo"))
  1670  			})
  1671  
  1672  			It("Should handle valid tokens issued by the org issuer", func() {
  1673  				pubk, _, err := iu.Ed25519KeyPair()
  1674  				Expect(err).ToNot(HaveOccurred())
  1675  				client, err := tokens.NewClientIDClaims("ginkgo", nil, "choria", nil, "", "", time.Hour, nil, pubk)
  1676  				Expect(err).ToNot(HaveOccurred())
  1677  				// Expect(client.AddOrgIssuerData(issuerPrik)).To(Succeed())
  1678  
  1679  				signed, err := tokens.SignToken(client, issuerPrik)
  1680  				Expect(err).ToNot(HaveOccurred())
  1681  
  1682  				claims, err := auth.parseClientIDJWT(signed)
  1683  				Expect(err).ToNot(HaveOccurred())
  1684  				Expect(claims.CallerID).To(Equal("ginkgo"))
  1685  			})
  1686  		})
  1687  
  1688  		Describe("Trusted Signers", func() {
  1689  			It("Should verify JWTs", func() {
  1690  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
  1691  				signed := createSignedClientJWT(privateKey, map[string]any{
  1692  					"exp": time.Now().UTC().Add(-time.Hour).Unix(),
  1693  				})
  1694  
  1695  				_, err := auth.parseClientIDJWT(signed)
  1696  				Expect(err.Error()).To(MatchRegexp("token is expired by"))
  1697  			})
  1698  
  1699  			It("Should detect missing callers", func() {
  1700  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
  1701  				signed := createSignedClientJWT(privateKey, map[string]any{
  1702  					"callerid": "",
  1703  					"purpose":  tokens.ClientIDPurpose,
  1704  				})
  1705  
  1706  				_, err := auth.parseClientIDJWT(signed)
  1707  				Expect(err).To(MatchError("no callerid in claims"))
  1708  			})
  1709  
  1710  			It("Should check the purpose field", func() {
  1711  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
  1712  				signed := createSignedClientJWT(privateKey, nil)
  1713  				_, err := auth.parseClientIDJWT(signed)
  1714  				Expect(err).To(MatchError(tokens.ErrNotAClientToken))
  1715  
  1716  				signed = createSignedClientJWT(privateKey, map[string]any{
  1717  					"purpose": "wrong",
  1718  				})
  1719  				_, err = auth.parseClientIDJWT(signed)
  1720  				Expect(err).To(MatchError(tokens.ErrNotAClientToken))
  1721  			})
  1722  
  1723  			It("Should check the caller", func() {
  1724  				edPublicKey, _, err := choria.Ed25519KeyPair()
  1725  				Expect(err).ToNot(HaveOccurred())
  1726  
  1727  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
  1728  				signed := createSignedClientJWT(privateKey, map[string]any{
  1729  					"purpose":    tokens.ClientIDPurpose,
  1730  					"public_key": hex.EncodeToString(edPublicKey),
  1731  				})
  1732  
  1733  				claims, err := auth.parseClientIDJWT(signed)
  1734  				Expect(err).ToNot(HaveOccurred())
  1735  				Expect(claims.CallerID).To(Equal("up=ginkgo"))
  1736  			})
  1737  
  1738  			It("Should check the public key", func() {
  1739  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
  1740  				signed := createSignedClientJWT(privateKey, map[string]any{
  1741  					"purpose": tokens.ClientIDPurpose,
  1742  				})
  1743  
  1744  				claims, err := auth.parseClientIDJWT(signed)
  1745  				Expect(err).To(MatchError("no public key in claims"))
  1746  				Expect(claims).To(BeNil())
  1747  			})
  1748  
  1749  			It("Should handle file names that are exactly 64 characters long", func() {
  1750  				if runtime.GOOS == "windows" {
  1751  					Skip("Not supported on windows")
  1752  				}
  1753  
  1754  				td, err := os.MkdirTemp("/tmp", "")
  1755  				Expect(err).ToNot(HaveOccurred())
  1756  				defer os.RemoveAll(td)
  1757  
  1758  				if len(td) > 50 {
  1759  					Skip("Temp directory is too long for filename test")
  1760  				}
  1761  
  1762  				pkPath := filepath.Join(td, strings.Repeat("x", 65-len(td)-strings.Count(td, string(os.PathSeparator))))
  1763  				Expect(pkPath).To(HaveLen(64))
  1764  
  1765  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1766  				Expect(err).ToNot(HaveOccurred())
  1767  				Expect(os.WriteFile(pkPath, []byte(hex.EncodeToString(edPublicKey)), 0600)).To(Succeed())
  1768  
  1769  				auth.clientJwtSigners = []string{pkPath}
  1770  
  1771  				signed := createSignedClientJWT(edPriKey, map[string]any{
  1772  					"purpose":    tokens.ClientIDPurpose,
  1773  					"public_key": hex.EncodeToString(edPublicKey),
  1774  				})
  1775  
  1776  				claims, err := auth.parseClientIDJWT(signed)
  1777  				Expect(err).ToNot(HaveOccurred())
  1778  				Expect(claims.CallerID).To(Equal("up=ginkgo"))
  1779  			})
  1780  
  1781  			It("Should handle multiple public identifiers", func() {
  1782  				edPublicKey, edPriKey, err := choria.Ed25519KeyPair()
  1783  				Expect(err).ToNot(HaveOccurred())
  1784  				signed := createSignedClientJWT(edPriKey, map[string]any{
  1785  					"purpose":    tokens.ClientIDPurpose,
  1786  					"public_key": hex.EncodeToString(edPublicKey),
  1787  				})
  1788  
  1789  				// should fail the public key not there
  1790  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem")}
  1791  				claims, err := auth.parseClientIDJWT(signed)
  1792  				Expect(err).To(MatchError("could not parse client id token: ed25519 public key required"))
  1793  				Expect(claims).To(BeNil())
  1794  
  1795  				// should now pass after having done a multi check
  1796  				auth.clientJwtSigners = []string{filepath.Join(td, "public.pem"), "/nonexisting", hex.EncodeToString(edPublicKey)}
  1797  				claims, err = auth.parseClientIDJWT(signed)
  1798  				Expect(err).ToNot(HaveOccurred())
  1799  				Expect(claims.CallerID).To(Equal("up=ginkgo"))
  1800  			})
  1801  		})
  1802  	})
  1803  
  1804  	Describe("setClientPermissions", func() {
  1805  		var (
  1806  			log    *logrus.Entry
  1807  			minSub = []string{"*.reply.>"}
  1808  			minPub = []string{"$SYS.REQ.USER.INFO"}
  1809  		)
  1810  
  1811  		BeforeEach(func() {
  1812  			log = logrus.NewEntry(logrus.New())
  1813  			log.Logger.SetOutput(GinkgoWriter)
  1814  		})
  1815  
  1816  		Describe("System User", func() {
  1817  			It("Should should set correct permissions", func() {
  1818  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{OrgAdmin: true}}, log)
  1819  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1820  					Allow: []string{">"},
  1821  				}))
  1822  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1823  					Allow: []string{">"},
  1824  				}))
  1825  			})
  1826  		})
  1827  
  1828  		Describe("Stream Users", func() {
  1829  			It("Should set no permissions for non choria users", func() {
  1830  				user.Account = auth.provisioningAccount
  1831  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{StreamsUser: true}}, log)
  1832  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1833  					Allow: minSub,
  1834  				}))
  1835  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1836  					Allow: []string{"$SYS.REQ.USER.INFO"},
  1837  				}))
  1838  			})
  1839  
  1840  			It("Should set correct permissions for the choria user", func() {
  1841  				user.Account = auth.choriaAccount
  1842  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{StreamsUser: true}}, log)
  1843  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1844  					Allow: minSub,
  1845  				}))
  1846  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1847  					Allow: append(minPub,
  1848  						"$JS.API.INFO",
  1849  						"$JS.API.STREAM.NAMES",
  1850  						"$JS.API.STREAM.LIST",
  1851  						"$JS.API.STREAM.INFO.*",
  1852  						"$JS.API.STREAM.MSG.GET.*",
  1853  						"$JS.API.STREAM.MSG.DELETE.*",
  1854  						"$JS.API.DIRECT.GET.*",
  1855  						"$JS.API.DIRECT.GET.*.>",
  1856  						"$JS.API.CONSUMER.CREATE.*",
  1857  						"$JS.API.CONSUMER.CREATE.*.>",
  1858  						"$JS.API.CONSUMER.DURABLE.CREATE.*.*",
  1859  						"$JS.API.CONSUMER.DELETE.*.*",
  1860  						"$JS.API.CONSUMER.NAMES.*",
  1861  						"$JS.API.CONSUMER.LIST.*",
  1862  						"$JS.API.CONSUMER.INFO.*.*",
  1863  						"$JS.API.CONSUMER.MSG.NEXT.*.*",
  1864  						"$JS.ACK.>",
  1865  						"$JS.FC.>",
  1866  						"$KV.>",
  1867  						"$O.>"),
  1868  				}))
  1869  			})
  1870  		})
  1871  
  1872  		Describe("Governor Users", func() {
  1873  			It("Should not set provisioner permissions", func() {
  1874  				user.Account = auth.provisioningAccount
  1875  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{StreamsUser: true, Governor: true}}, log)
  1876  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1877  					Allow: minSub,
  1878  				}))
  1879  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1880  					Allow: minPub,
  1881  				}))
  1882  			})
  1883  
  1884  			It("Should set choria permissions", func() {
  1885  				user.Account = auth.choriaAccount
  1886  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{StreamsUser: true, Governor: true}}, log)
  1887  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1888  					Allow: minSub,
  1889  				}))
  1890  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1891  					Allow: append(minPub, []string{
  1892  						"$JS.API.INFO",
  1893  						"$JS.API.STREAM.NAMES",
  1894  						"$JS.API.STREAM.LIST",
  1895  						"$JS.API.STREAM.INFO.*",
  1896  						"$JS.API.STREAM.MSG.GET.*",
  1897  						"$JS.API.STREAM.MSG.DELETE.*",
  1898  						"$JS.API.DIRECT.GET.*",
  1899  						"$JS.API.DIRECT.GET.*.>",
  1900  						"$JS.API.CONSUMER.CREATE.*",
  1901  						"$JS.API.CONSUMER.CREATE.*.>",
  1902  						"$JS.API.CONSUMER.DURABLE.CREATE.*.*",
  1903  						"$JS.API.CONSUMER.DELETE.*.*",
  1904  						"$JS.API.CONSUMER.NAMES.*",
  1905  						"$JS.API.CONSUMER.LIST.*",
  1906  						"$JS.API.CONSUMER.INFO.*.*",
  1907  						"$JS.API.CONSUMER.MSG.NEXT.*.*",
  1908  						"$JS.ACK.>",
  1909  						"$JS.FC.>",
  1910  						"$KV.>",
  1911  						"$O.>",
  1912  						"*.governor.*",
  1913  						"choria.lifecycle.event.governor.>",
  1914  					}...),
  1915  				}))
  1916  			})
  1917  
  1918  		})
  1919  
  1920  		Describe("Event Viewers", func() {
  1921  			It("Should set provisioning permissions", func() {
  1922  				user.Account = auth.provisioningAccount
  1923  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{EventsViewer: true}}, log)
  1924  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1925  					Allow: append(minSub, "choria.lifecycle.event.*.provision_mode_server"),
  1926  				}))
  1927  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1928  					Allow: minPub,
  1929  				}))
  1930  			})
  1931  
  1932  			It("Should set choria permissions", func() {
  1933  				user.Account = auth.choriaAccount
  1934  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{EventsViewer: true}}, log)
  1935  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1936  					Allow: append(minSub, "choria.lifecycle.event.>",
  1937  						"choria.machine.watcher.>",
  1938  						"choria.machine.transition"),
  1939  				}))
  1940  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1941  					Allow: minPub,
  1942  					Deny:  nil,
  1943  				}))
  1944  			})
  1945  		})
  1946  
  1947  		Describe("Election Users", func() {
  1948  			It("Should set provisioning permissions", func() {
  1949  				user.Account = auth.provisioningAccount
  1950  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{ElectionUser: true}}, log)
  1951  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1952  					Allow: minSub,
  1953  				}))
  1954  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1955  					Allow: append(minPub,
  1956  						"choria.streams.STREAM.INFO.KV_CHORIA_LEADER_ELECTION",
  1957  						"$KV.CHORIA_LEADER_ELECTION.provisioner"),
  1958  				}))
  1959  			})
  1960  
  1961  			It("Should set choria permissions", func() {
  1962  				user.Account = auth.choriaAccount
  1963  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{ElectionUser: true}}, log)
  1964  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1965  					Allow: minSub,
  1966  				}))
  1967  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1968  					Allow: append(minPub,
  1969  						"$JS.API.STREAM.INFO.KV_CHORIA_LEADER_ELECTION",
  1970  						"$KV.CHORIA_LEADER_ELECTION.>"),
  1971  				}))
  1972  			})
  1973  		})
  1974  		Describe("Streams Admin", func() {
  1975  			It("Should set no permissions for non choria users", func() {
  1976  				user.Account = auth.provisioningAccount
  1977  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{StreamsAdmin: true}}, log)
  1978  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1979  					Allow: minSub,
  1980  				}))
  1981  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1982  					Allow: minPub,
  1983  				}))
  1984  			})
  1985  
  1986  			It("Should set correct permissions for choria user", func() {
  1987  				user.Account = auth.choriaAccount
  1988  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{StreamsAdmin: true}}, log)
  1989  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  1990  					Allow: append(minSub, "$JS.EVENT.>"),
  1991  				}))
  1992  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  1993  					Allow: append(minPub, "$JS.>"),
  1994  				}))
  1995  			})
  1996  		})
  1997  
  1998  		Describe("Fleet Management", func() {
  1999  			It("Should set correct permissions for fleet management users", func() {
  2000  				user.Account = auth.choriaAccount
  2001  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{Permissions: &tokens.ClientPermissions{FleetManagement: true}}, log)
  2002  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  2003  					Allow: minSub,
  2004  				}))
  2005  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  2006  					Allow: append(minPub, "*.broadcast.agent.>", "*.broadcast.service.>", "*.node.>", "choria.federation.*.federation"),
  2007  				}))
  2008  			})
  2009  		})
  2010  
  2011  		Describe("Additional subjects", func() {
  2012  			It("Should set the permissions correctly", func() {
  2013  				user.Account = auth.choriaAccount
  2014  				auth.setClientPermissions(user, "", &tokens.ClientIDClaims{
  2015  					AdditionalSubscribeSubjects: []string{"sub.>"},
  2016  					AdditionalPublishSubjects:   []string{"pub.>"},
  2017  				}, log)
  2018  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  2019  					Allow: append(minSub, "sub.>"),
  2020  				}))
  2021  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  2022  					Allow: append(minPub, "pub.>"),
  2023  				}))
  2024  			})
  2025  		})
  2026  
  2027  		Describe("Minimal Permissions", func() {
  2028  			It("Should support caller private reply subjects", func() {
  2029  				user.Account = auth.choriaAccount
  2030  				auth.setClientPermissions(user, "u=ginkgo", nil, log)
  2031  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  2032  					Allow: []string{"*.reply.0f47cbbd2accc01a51e57261d6e64b8b.>"},
  2033  				}))
  2034  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  2035  					Allow: minPub,
  2036  				}))
  2037  			})
  2038  
  2039  			It("Should support standard reply subjects", func() {
  2040  				user.Account = auth.choriaAccount
  2041  				auth.setClientPermissions(user, "", nil, log)
  2042  				Expect(user.Permissions.Subscribe).To(Equal(&server.SubjectPermission{
  2043  					Allow: []string{"*.reply.>"},
  2044  				}))
  2045  				Expect(user.Permissions.Publish).To(Equal(&server.SubjectPermission{
  2046  					Allow: minPub,
  2047  				}))
  2048  			})
  2049  		})
  2050  	})
  2051  
  2052  	Describe("setServerPermissions", func() {
  2053  		It("Should set correct permissions", func() {
  2054  			auth.setServerPermissions(user, nil, log)
  2055  
  2056  			Expect(user.Permissions.Publish.Allow).To(Equal([]string{
  2057  				">",
  2058  			}))
  2059  
  2060  			Expect(user.Permissions.Publish.Deny).To(Equal([]string{
  2061  				"*.broadcast.agent.>",
  2062  				"*.broadcast.service.>",
  2063  				"*.node.>",
  2064  				"choria.federation.*.federation",
  2065  			}))
  2066  
  2067  			Expect(user.Permissions.Subscribe.Allow).To(BeEmpty())
  2068  			Expect(user.Permissions.Subscribe.Deny).To(Equal([]string{
  2069  				"*.reply.>",
  2070  				"choria.federation.>",
  2071  				"choria.lifecycle.>",
  2072  			}))
  2073  		})
  2074  
  2075  		It("Should support denying servers", func() {
  2076  			auth.denyServers = true
  2077  			auth.setServerPermissions(user, nil, log)
  2078  			Expect(user.Permissions.Publish.Deny).To(Equal([]string{">"}))
  2079  			Expect(user.Permissions.Publish.Allow).To(BeNil())
  2080  		})
  2081  	})
  2082  })