-
Notifications
You must be signed in to change notification settings - Fork 153
Enhance NATS provider to support multiple authentication methods #1222
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
base: main
Are you sure you want to change the base?
Conversation
…uding JWT, NKey, and Username/Password. Signed-off-by: Latch Mihay <latch@mihay.net>
|
@cappyzawa fixed it, its pointing to main now |
|
Thanks for the contribution! Please run |
Signed-off-by: Latch Mihay <latch@mihay.net>
|
One suggestion: the auth decision in This keeps Something like: type natsClient struct {
server string
authFn func() (nats.Option, func(), error)
}
func NewNATS(...) (*NATS, error) {
client := &natsClient{server: server}
if len(credsData) > 0 {
client.authFn = func() (nats.Option, func(), error) {
return nats.UserCredentialBytes(credsData), nil, nil
}
} else if len(nkeySeed) > 0 {
client.authFn = func() (nats.Option, func(), error) {
kp, err := nkeys.FromSeed(nkeySeed)
if err != nil {
return nil, nil, fmt.Errorf("error parsing nkey seed: %w", err)
}
pubKey, err := kp.PublicKey()
if err != nil {
kp.Wipe()
return nil, nil, fmt.Errorf("error getting public key: %w", err)
}
sigCB := func(nonce []byte) ([]byte, error) {
return kp.Sign(nonce)
}
return nats.Nkey(pubKey, sigCB), kp.Wipe, nil
}
} else if username != "" && password != "" {
client.authFn = func() (nats.Option, func(), error) {
return nats.UserInfo(username, password), nil, nil
}
}
// ...
}
func (n *natsClient) publish(...) error {
opts := []nats.Option{nats.Name("NATS Provider Publisher")}
if n.authFn != nil {
authOpt, cleanup, err := n.authFn()
if err != nil {
return err
}
if cleanup != nil {
defer cleanup()
}
opts = append(opts, authOpt)
}
nc, err := nats.Connect(n.server, opts...)
// ...
}The cleanup func handles Not a blocker, just a suggestion for cleaner separation. |
…aner separation. From @cappyzawa suggestion. Signed-off-by: Latch Mihay <latch@mihay.net>
cappyzawa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The authFn refactoring looks clean! 👍
One thing I noticed: the current test checks authFn != nil, but doesn't actually call authFn() to verify it returns the correct auth type. Since we moved away from storing fields directly, it'd be nice to confirm the returned nats.Option actually sets the right authentication.
Also, the "credentials file data is stored" and "nkey seed data is stored" cases could double as priority tests by adding the other auth params - this way we can verify creds > nkey > userpass priority works correctly.
Here's a minimal diff that adds this verification:
+ "github.com/nats-io/nats.go"
+ // Priority tests: creds > nkey > userpass
{
- name: "credentials file data is stored",
+ name: "creds takes priority over nkey and userpass",
subject: "test",
server: "nats",
+ username: "user",
+ password: "pass",
credsData: []byte("credentials-content"),
+ nkeySeed: []byte("SUAGMJH5XLGZKQQWAWKRZJIGMOU4HPFUYLXJMXOO5NLFEO2OOQJ5LPRDPM"),
expectedSubject: "test",
expectedCreds: true,
},
{
- name: "nkey seed data is stored",
+ name: "nkey takes priority over userpass",
subject: "test",
server: "nats",
+ username: "user",
+ password: "pass",
nkeySeed: []byte("SUAGMJH5XLGZKQQWAWKRZJIGMOU4HPFUYLXJMXOO5NLFEO2OOQJ5LPRDPM"),
expectedSubject: "test",
expectedNkey: true,
},And add verification logic after checking client.authFn:
// Verify authFn returns valid option and correct auth type
if client.authFn != nil {
opt, cleanup, err := client.authFn()
g.Expect(err).To(BeNil(), "authFn should not return error")
g.Expect(opt).NotTo(BeNil(), "authFn should return a valid option")
if cleanup != nil {
defer cleanup()
}
// Apply option to verify which auth method was selected
var opts nats.Options
g.Expect(opt(&opts)).To(Succeed())
if tt.expectedCreds {
g.Expect(opts.UserJWT).NotTo(BeNil(), "creds auth should set UserJWT")
} else if tt.expectedNkey {
g.Expect(opts.Nkey).NotTo(BeEmpty(), "nkey auth should set Nkey")
g.Expect(opts.SignatureCB).NotTo(BeNil(), "nkey auth should set SignatureCB")
} else if tt.expectedUsername != "" {
g.Expect(opts.User).To(Equal(tt.expectedUsername), "userpass auth should set User")
g.Expect(opts.Password).To(Equal(tt.expectedPassword), "userpass auth should set Password")
}
}This keeps the existing test structure while adding actual auth type verification. What do you think?
returned auth type. Signed-off-by: Latch Mihay <latch@mihay.net>
Thank you for the suggestions, they have been added :) |
cappyzawa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks for implementing the test improvements - the priority tests and authFn verification look great. 🎉
Enhance NATS provider to support multiple authentication methods including JWT, NKey, and Username/Password.
This would allow the notification-controller to support the recommended NATS 2.0+ authentication paradigms.