From 3b4812b225586752c9b29d0de2e1139164ce90c4 Mon Sep 17 00:00:00 2001 From: btoews Date: Mon, 1 Apr 2024 12:06:44 -0600 Subject: [PATCH] add UserInfoHandler for dynamically fetching username+password Signed-off-by: btoews --- nats.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/nats.go b/nats.go index 06897b8a4..87fc8861a 100644 --- a/nats.go +++ b/nats.go @@ -131,6 +131,7 @@ var ( ErrNkeysNotSupported = errors.New("nats: nkeys not supported by the server") ErrStaleConnection = errors.New("nats: " + STALE_CONNECTION) ErrTokenAlreadySet = errors.New("nats: token and token handler both set") + ErrUserInfoAlreadySet = errors.New("nats: user info and user info handler both set") ErrMsgNotBound = errors.New("nats: message is not bound to subscription/connection") ErrMsgNoReply = errors.New("nats: message does not have a reply") ErrClientIPNotSupported = errors.New("nats: client IP not supported by this server") @@ -230,6 +231,9 @@ type SignatureHandler func([]byte) ([]byte, error) // AuthTokenHandler is used to generate a new token. type AuthTokenHandler func() string +// AuthUserInfoHandler is used to fetch username and password. +type AuthUserInfoHandler func() (string, string) + // ReconnectDelayHandler is used to get from the user the desired // delay the library should pause before attempting to reconnect // again. Note that this is invoked after the library tried the @@ -443,6 +447,10 @@ type Options struct { // Password sets the password to be used when connecting to a server. Password string + // UserInfoHandler designates the function used to fetch the username and + // password to be used when connecting to a server. + UserInfoHandler AuthUserInfoHandler + // Token sets the token to be used when connecting to a server. Token string @@ -1166,6 +1174,15 @@ func UserInfo(user, password string) Option { } } +// UserInfoHandler is an Option to set the user info handler to use when a +// username and password is not otherwise specified. +func UserInfoHandler(cb AuthUserInfoHandler) Option { + return func(o *Options) error { + o.UserInfoHandler = cb + return nil + } +} + // Token is an Option to set the token to use // when a token is not included directly in the URLs // and when a token handler is not provided. @@ -2557,6 +2574,13 @@ func (nc *Conn) connectProto() (string, error) { token = nc.Opts.TokenHandler() } + if nc.Opts.UserInfoHandler != nil { + if user != _EMPTY_ || pass != _EMPTY_ { + return _EMPTY_, ErrUserInfoAlreadySet + } + user, pass = nc.Opts.UserInfoHandler() + } + // If our server does not support headers then we can't do them or no responders. hdrs := nc.info.Headers cinfo := connectInfo{o.Verbose, o.Pedantic, ujwt, nkey, sig, user, pass, token,