Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ADDED] IgnoreAuthErrorAbort option on Connect #1141

Merged
merged 1 commit into from Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 15 additions & 2 deletions nats.go
Expand Up @@ -471,6 +471,10 @@ type Options struct {

// InboxPrefix allows the default _INBOX prefix to be customized
InboxPrefix string

// IgnoreAuthErrorAbort - if set to true, client opts out of the default connect behavior of aborting
// subsequent reconnect attempts if server returns the same auth error twice (regardless of reconnect policy).
IgnoreAuthErrorAbort bool
}

const (
Expand Down Expand Up @@ -1249,6 +1253,15 @@ func CustomInboxPrefix(p string) Option {
}
}

// IgnoreAuthErrorAbort opts out of the default connect behavior of aborting
// subsequent reconnect attempts if server returns the same auth error twice.
func IgnoreAuthErrorAbort() Option {
return func(o *Options) error {
o.IgnoreAuthErrorAbort = true
return nil
}
}

// Handler processing

// SetDisconnectHandler will set the disconnect event handler.
Expand Down Expand Up @@ -3153,8 +3166,8 @@ func (nc *Conn) processAuthError(err error) bool {
nc.ach.push(func() { nc.Opts.AsyncErrorCB(nc, nil, err) })
}
// We should give up if we tried twice on this server and got the
// same error.
if nc.current.lastErr == err {
// same error. This behavior can be modified using IgnoreAuthErrorAbort.
if nc.current.lastErr == err && !nc.Opts.IgnoreAuthErrorAbort {
nc.ar = true
} else {
nc.current.lastErr = err
Expand Down
42 changes: 35 additions & 7 deletions nats_test.go
Expand Up @@ -1610,10 +1610,14 @@ func TestExpiredAuthentication(t *testing.T) {
name string
expectedProto string
expectedErr error
ignoreAbort bool
}{
{"expired users credentials", AUTHENTICATION_EXPIRED_ERR, ErrAuthExpired},
{"revoked users credentials", AUTHENTICATION_REVOKED_ERR, ErrAuthRevoked},
{"expired account", ACCOUNT_AUTHENTICATION_EXPIRED_ERR, ErrAccountAuthExpired},
{"expired users credentials", AUTHENTICATION_EXPIRED_ERR, ErrAuthExpired, false},
{"revoked users credentials", AUTHENTICATION_REVOKED_ERR, ErrAuthRevoked, false},
{"expired account", ACCOUNT_AUTHENTICATION_EXPIRED_ERR, ErrAccountAuthExpired, false},
{"expired users credentials", AUTHENTICATION_EXPIRED_ERR, ErrAuthExpired, true},
{"revoked users credentials", AUTHENTICATION_REVOKED_ERR, ErrAuthRevoked, true},
{"expired account", ACCOUNT_AUTHENTICATION_EXPIRED_ERR, ErrAccountAuthExpired, true},
} {
t.Run(test.name, func(t *testing.T) {
l, e := net.Listen("tcp", "127.0.0.1:0")
Expand Down Expand Up @@ -1661,8 +1665,8 @@ func TestExpiredAuthentication(t *testing.T) {
errCh := make(chan error, 10)

url := fmt.Sprintf("nats://127.0.0.1:%d", addr.Port)
nc, err := Connect(url,
ReconnectWait(25*time.Millisecond),
opts := []Option{
ReconnectWait(25 * time.Millisecond),
ReconnectJitter(0, 0),
MaxReconnects(-1),
ErrorHandler(func(_ *Conn, _ *Subscription, e error) {
Expand All @@ -1674,12 +1678,36 @@ func TestExpiredAuthentication(t *testing.T) {
ClosedHandler(func(nc *Conn) {
ch <- true
}),
)
}
if test.ignoreAbort {
opts = append(opts, IgnoreAuthErrorAbort())
}
nc, err := Connect(url, opts...)
if err != nil {
t.Fatalf("Expected to connect, got %v", err)
}
defer nc.Close()

if test.ignoreAbort {
// We expect more than 3 errors, as the connect attempt should not be aborted after 2 failed attempts.
for i := 0; i < 4; i++ {
select {
case e := <-errCh:
if i == 0 && e != test.expectedErr {
t.Fatalf("Expected error %q, got %q", test.expectedErr, e)
} else if i > 0 && e != ErrAuthorization {
t.Fatalf("Expected error %q, got %q", ErrAuthorization, e)
}
case <-time.After(time.Second):
if i == 0 {
t.Fatalf("Missing %q error", test.expectedErr)
} else {
t.Fatalf("Missing %q error", ErrAuthorization)
}
}
}
return
}
// We should give up since we get the same error on both tries.
if err := WaitTime(ch, 2*time.Second); err != nil {
t.Fatal("Should have closed after multiple failed attempts.")
Expand Down Expand Up @@ -1795,7 +1823,7 @@ func TestNkeyAuth(t *testing.T) {

sopts := natsserver.DefaultTestOptions
sopts.Port = TEST_PORT
sopts.Nkeys = []*server.NkeyUser{&server.NkeyUser{Nkey: string(pub)}}
sopts.Nkeys = []*server.NkeyUser{{Nkey: string(pub)}}
ts := RunServerWithOptions(&sopts)
defer ts.Shutdown()

Expand Down