From 3ba8e08f8f3a4877cd22b9d200bdd72615425514 Mon Sep 17 00:00:00 2001 From: Piotr Piotrowski Date: Tue, 19 Mar 2024 17:46:17 +0100 Subject: [PATCH] [IMPROVED] Add test checking if client reconnects after jwt expires (#1586) Signed-off-by: Piotr Piotrowski --- go_test.mod | 1 + go_test.sum | 9 +++++ test/reconnect_test.go | 76 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/go_test.mod b/go_test.mod index 24cbb5247..5dfd112f5 100644 --- a/go_test.mod +++ b/go_test.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/golang/protobuf v1.4.2 github.com/klauspost/compress v1.17.6 + github.com/nats-io/jwt v1.2.2 github.com/nats-io/nats-server/v2 v2.10.11 github.com/nats-io/nkeys v0.4.7 github.com/nats-io/nuid v1.0.1 diff --git a/go_test.sum b/go_test.sum index e6fe15871..d28f0f625 100644 --- a/go_test.sum +++ b/go_test.sum @@ -14,10 +14,13 @@ github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2e github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/nats-io/jwt v1.2.2 h1:w3GMTO969dFg+UOKTmmyuu7IGdusK+7Ytlt//OYH/uU= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= github.com/nats-io/jwt/v2 v2.5.3 h1:/9SWvzc6hTfamcgXJ3uYRpgj+QuY2aLNqRiqrKcrpEo= github.com/nats-io/jwt/v2 v2.5.3/go.mod h1:iysuPemFcc7p4IoYots3IuELSI4EDe9Y0bQMe+I3Bf4= github.com/nats-io/nats-server/v2 v2.10.11 h1:yKUiLVincZISpo3A4YljJQ+HfLltGAgoNNJl99KL8I0= github.com/nats-io/nats-server/v2 v2.10.11/go.mod h1:dXtOqVWzbMTEj+tUyC/itXjJhW37xh0tUBrTAlqAfx8= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= @@ -26,11 +29,17 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= diff --git a/test/reconnect_test.go b/test/reconnect_test.go index b1b398442..66cc9b6ca 100644 --- a/test/reconnect_test.go +++ b/test/reconnect_test.go @@ -14,6 +14,7 @@ package test import ( + "errors" "fmt" "net" "net/url" @@ -22,8 +23,10 @@ import ( "testing" "time" + "github.com/nats-io/jwt" "github.com/nats-io/nats-server/v2/server" "github.com/nats-io/nats.go" + "github.com/nats-io/nkeys" ) func startReconnectServer(t *testing.T) *server.Server { @@ -826,3 +829,76 @@ func TestReconnectBufSizeDisable(t *testing.T) { t.Errorf("Unexpected buffered bytes: %v", got) } } + +func TestAuthExpiredReconnect(t *testing.T) { + ts := runTrustServer() + defer ts.Shutdown() + + _, err := nats.Connect(ts.ClientURL()) + if err == nil { + t.Fatalf("Expecting an error on connect") + } + ukp, err := nkeys.FromSeed(uSeed) + if err != nil { + t.Fatalf("Error creating user key pair: %v", err) + } + upub, err := ukp.PublicKey() + if err != nil { + t.Fatalf("Error getting user public key: %v", err) + } + akp, err := nkeys.FromSeed(aSeed) + if err != nil { + t.Fatalf("Error creating account key pair: %v", err) + } + + jwtCB := func() (string, error) { + claims := jwt.NewUserClaims("test") + claims.Expires = time.Now().Add(500 * time.Millisecond).Unix() + claims.Subject = upub + jwt, err := claims.Encode(akp) + if err != nil { + return "", err + } + return jwt, nil + } + sigCB := func(nonce []byte) ([]byte, error) { + kp, _ := nkeys.FromSeed(uSeed) + sig, _ := kp.Sign(nonce) + return sig, nil + } + + errCh := make(chan error, 1) + nc, err := nats.Connect(ts.ClientURL(), nats.UserJWT(jwtCB, sigCB), nats.ReconnectWait(100*time.Millisecond), + nats.ErrorHandler(func(_ *nats.Conn, _ *nats.Subscription, err error) { + errCh <- err + })) + if err != nil { + t.Fatalf("Expected to connect, got %v", err) + } + stasusCh := nc.StatusChanged(nats.RECONNECTING, nats.CONNECTED) + select { + case err := <-errCh: + if !errors.Is(err, nats.ErrAuthExpired) { + t.Fatalf("Expected auth expired error, got %v", err) + } + case <-time.After(2 * time.Second): + t.Fatal("Did not get the auth expired error") + } + select { + case s := <-stasusCh: + if s != nats.RECONNECTING { + t.Fatalf("Expected to be in reconnecting state after jwt expires, got %v", s) + } + case <-time.After(2 * time.Second): + t.Fatal("Did not get the status change") + } + select { + case s := <-stasusCh: + if s != nats.CONNECTED { + t.Fatalf("Expected to reconnect, got %v", s) + } + case <-time.After(2 * time.Second): + t.Fatal("Did not get the status change") + } + nc.Close() +}