-
Notifications
You must be signed in to change notification settings - Fork 12
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
CLI for local users MFA #2979
base: main
Are you sure you want to change the base?
CLI for local users MFA #2979
Conversation
🎉 All Contributor License Agreements have been signed. Ready to merge. |
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.
Thanks! I left some comments/questions
fcdb80b
to
63e09be
Compare
e76e75f
to
8a5734c
Compare
@@ -112,7 +112,7 @@ func PersistCCloudCredentialsToConfig(config *config.Config, client *ccloudv1.Cl | |||
return ctx.CurrentEnvironment, user.GetOrganization(), nil | |||
} | |||
|
|||
func addOrUpdateContext(cfg *config.Config, isCloud bool, credentials *Credentials, ctxName, url string, state *config.ContextState, caCertPath, organizationId string, save bool) error { | |||
func addOrUpdateContext(cfg *config.Config, isCloud bool, credentials *Credentials, ctxName, url string, state *config.ContextState, caCertPath, organizationId string, save, IsMfa bool) error { |
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.
For go, please follow the acronyms convention to use isMFA
instead.
For local variable including the ones in the arguments, the first letter should be non capitalized.
@@ -494,7 +494,7 @@ func (c *Config) FindContext(name string) (*Context, error) { | |||
return context, nil | |||
} | |||
|
|||
func (c *Config) AddContext(name, platformName, credentialName string, kafkaClusters map[string]*KafkaClusterConfig, kafka string, state *ContextState, organizationId, environmentId string) error { | |||
func (c *Config) AddContext(name, platformName, credentialName string, kafkaClusters map[string]*KafkaClusterConfig, kafka string, state *ContextState, organizationId, environmentId string, IsMfa bool) error { |
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.
Same here, please update the argument names wherever applies.
@@ -40,11 +42,16 @@ func (a *AuthTokenHandlerImpl) GetCCloudTokens(clientFactory CCloudClientFactory | |||
if token, refreshToken, err := a.refreshCCloudSSOToken(client, credentials.AuthRefreshToken, organizationId); err == nil { | |||
return token, refreshToken, nil | |||
} | |||
} else if credentials.IsMfa { |
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.
refreshCCloudMFAToken
} | ||
|
||
client = clientFactory.JwtHTTPClientFactory(context.Background(), token, url) | ||
err = a.checkMFAEmailMatchesLogin(client, credentials.Username) |
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.
If the function returns an error: “Validate” or “verify” implies the function will produce an error if the emails do not match.
validateMFAEmailMatchesLogin()
@@ -146,6 +209,24 @@ func (a *AuthTokenHandlerImpl) refreshCCloudSSOToken(client *ccloudv1.Client, re | |||
|
|||
return res.GetToken(), refreshToken, err | |||
} | |||
func (a *AuthTokenHandlerImpl) refreshCCloudMfaToken(client *ccloudv1.Client, refreshToken, organizationId, email string) (string, string, error) { |
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.
Should we check for things as we did in getCCloudMfaToken()
?
@@ -108,6 +109,9 @@ func (h *LoginCredentialsManagerImpl) getCredentialsFromEnvVarFunc(envVars envir | |||
if h.isSSOUser(email, organizationId) { | |||
log.CliLogger.Debugf("%s=%s belongs to an SSO user.", ConfluentCloudEmail, email) | |||
return &Credentials{Username: email, IsSSO: true}, nil | |||
} else if h.isMFARequired(email, organizationId) { | |||
log.CliLogger.Debugf("%s=%s belongs to an MFA user.", ConfluentCloudEmail, email) |
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.
a MFA user.
res, err := h.client.User.LoginRealm(req) | ||
// Fine to ignore non-nil err for this request: e.g. what if this fails due to invalid/malicious | ||
// email, we want to silently continue and give the illusion of password prompt. | ||
return err == nil && res.GetMfaRequired() |
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.
It seems the comments indicate we can ignore the err, but line 303 doesn't can you please confirm?
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.
we are ignoring the non-nil error. We still want to catch the nil error. This is very similar to the SSO case where we do the similar thing. This should be good as is
MFAProviderIDToken string | ||
MFAProviderRefreshToken string | ||
MFAProviderState string | ||
email string |
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.
If we want to export it we should use Email
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.
we are not exporting email, it is only for MFA
return &authServer{ | ||
wait: make(chan bool), | ||
State: state, | ||
} | ||
} | ||
|
||
// Start begins the server including attempting to bind the desired TCP port | ||
func (s *authServer) startServer() error { | ||
func (s *authServer) StartServer() error { |
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.
Why are we making this change, while the StartServer() inside mfa folder is non-capitalized?
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.
yes i will revert this, there were some changes made for testing purpose, i will fix all the capitalization/non-capitaloizatiom
@@ -13,7 +13,7 @@ import ( | |||
) | |||
|
|||
func Login(authURL string, noBrowser bool, connectionName string) (string, string, error) { | |||
state, err := newState(authURL, noBrowser) | |||
state, err := NewState(authURL, noBrowser) |
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.
Uppercase first letter → Exported (visible outside the package).
Lowercase first letter → Unexported (internal to the package).
Acronyms (e.g., URL, HTTP, ID) remain uppercase as per Go style guidelines.
Release Notes
Breaking Changes
New Features
Bug Fixes
Checklist
What
section below whether this PR applies to Confluent Cloud, Confluent Platform, or both.Test & Review
section below.Blast Radius
section below.What
Add Multi-Factor Authentication (MFA) for users logging in using the CLI.
Blast Radius
This will impact all users trying to log into the confluent CLI whose organization has enabled Multi-Factor Authentication (MFA).
References
https://confluentinc.atlassian.net/browse/CLI-3318
Test & Review
Testing Doc: https://docs.google.com/document/d/1woyiPp9a4cPlECj0tfgxl5QRzdkxH-4KDj89MMDQbFM/edit?tab=t.0