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

CLI-1107: Update confluent login environment variables #981

Merged
merged 5 commits into from
Sep 13, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions internal/cmd/login/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package login

import (
"context"
"os"
"fmt"
"regexp"
"strings"

Expand Down Expand Up @@ -52,8 +52,9 @@ func (c *Command) init(prerunner pcmd.PreRunner) {
loginCmd := &cobra.Command{
Use: "login",
Short: "Log in to Confluent Cloud or Confluent Platform.",
Long: "Log in to Confluent Cloud using your email and password, or non-interactively using the `CCLOUD_EMAIL` and `CCLOUD_PASSWORD` environment variables.\n\n" +
"You can log in to Confluent Platform with your username and password, or non-interactively using `CONFLUENT_USERNAME`, `CONFLUENT_PASSWORD`, `CONFLUENT_MDS_URL`, and `CONFLUENT_CA_CERT_PATH`. In a non-interactive login, `CONFLUENT_MDS_URL` replaces the `--url` flag, and `CONFLUENT_CA_CERT_PATH` replaces the `--ca-cert-path` flag.\n\n" +
Long: fmt.Sprintf("Log in to Confluent Cloud using your email and password, or non-interactively using the `%s` and `%s` environment variables.\n\n", pauth.ConfluentCloudEmail, pauth.ConfluentCloudPassword) +
fmt.Sprintf("You can log in to Confluent Platform with your username and password, or non-interactively using `%s`, `%s`, `%s`, and `%s`.", pauth.ConfluentPlatformUsername, pauth.ConfluentPlatformPassword, pauth.ConfluentPlatformMDSURL, pauth.ConfluentPlatformCACertPath) +
fmt.Sprintf("In a non-interactive login, `%s` replaces the `--url` flag, and `%s` replaces the `--ca-cert-path` flag.\n\n", pauth.ConfluentPlatformMDSURL, pauth.ConfluentPlatformCACertPath) +
"Even with the environment variables set, you can force an interactive login using the `--prompt` flag.",
Args: cobra.NoArgs,
RunE: pcmd.NewCLIRunE(c.login),
Expand Down Expand Up @@ -216,15 +217,11 @@ func (c *Command) loginMDS(cmd *cobra.Command, url string) error {
}

func getCACertPath(cmd *cobra.Command) (string, error) {
caCertPath, err := cmd.Flags().GetString("ca-cert-path")
if err != nil {
return "", err
}
if caCertPath != "" {
return caCertPath, nil
if path, err := cmd.Flags().GetString("ca-cert-path"); path != "" || err != nil {
return path, err
}

return os.Getenv(pauth.ConfluentCACertPathEnvVar), nil
return pauth.GetEnvWithFallback(pauth.ConfluentPlatformCACertPath, pauth.DeprecatedConfluentPlatformCACertPath), nil
}

// Order of precedence: env vars > netrc > prompt
Expand Down Expand Up @@ -264,15 +261,11 @@ func (c *Command) checkLegacyContextCACertPath(cmd *cobra.Command, contextName s
}

func (c *Command) getURL(cmd *cobra.Command) (string, error) {
url, err := cmd.Flags().GetString("url")
if err != nil {
return "", err
}
if url != "" {
return url, nil
if url, err := cmd.Flags().GetString("url"); url != "" || err != nil {
return url, err
}

if url := os.Getenv(pauth.ConfluentURLEnvVar); url != "" {
if url := pauth.GetEnvWithFallback(pauth.ConfluentPlatformMDSURL, pauth.DeprecatedConfluentPlatformMDSURL); url != "" {
return url, nil
}

Expand Down
20 changes: 4 additions & 16 deletions internal/cmd/login/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ var (

func TestCredentialsOverride(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
auth := &sdkMock.Auth{
LoginFunc: func(ctx context.Context, idToken string, username string, password string) (string, error) {
return testToken, nil
Expand Down Expand Up @@ -177,7 +176,6 @@ func TestCredentialsOverride(t *testing.T) {

func TestLoginSuccess(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
auth := &sdkMock.Auth{
LoginFunc: func(ctx context.Context, idToken string, username string, password string) (string, error) {
return testToken, nil
Expand Down Expand Up @@ -219,22 +217,21 @@ func TestLoginSuccess(t *testing.T) {
for _, s := range suite {
// Log in to the CLI control plane
if s.setEnv {
_ = os.Setenv(pauth.ConfluentURLEnvVar, "http://localhost:8090")
_ = os.Setenv(pauth.ConfluentPlatformMDSURL, "http://localhost:8090")
}
loginCmd, cfg := newLoginCmd(auth, user, s.cliName, req, mockNetrcHandler, mockAuthTokenHandler, mockLoginCredentialsManager)
output, err := pcmd.ExecuteCommand(loginCmd.Command, s.args...)
req.NoError(err)
req.NotContains(output, fmt.Sprintf(errors.LoggedInAsMsg, promptUser))
verifyLoggedInState(t, cfg, s.cliName)
if s.setEnv {
_ = os.Unsetenv(pauth.ConfluentURLEnvVar)
_ = os.Unsetenv(pauth.ConfluentPlatformMDSURL)
}
}
}

func TestLoginOrderOfPrecedence(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
netrcUser := "netrc@confleunt.io"
netrcPassword := "netrcpassword"
netrcCreds := &pauth.Credentials{
Expand Down Expand Up @@ -368,7 +365,6 @@ func TestLoginOrderOfPrecedence(t *testing.T) {

func TestPromptLoginFlag(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
wrongCreds := &pauth.Credentials{
Username: "wrong_user",
Password: "wrong_password",
Expand Down Expand Up @@ -444,7 +440,6 @@ func TestPromptLoginFlag(t *testing.T) {

func TestLoginFail(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
mockLoginCredentialsManager := &cliMock.MockLoginCredentialsManager{
GetCCloudCredentialsFromEnvVarFunc: func(cmd *cobra.Command) func() (*pauth.Credentials, error) {
return func() (*pauth.Credentials, error) {
Expand Down Expand Up @@ -498,7 +493,7 @@ func Test_SelfSignedCerts(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.setEnv {
os.Setenv(pauth.ConfluentCACertPathEnvVar, "testcert.pem")
os.Setenv(pauth.ConfluentPlatformCACertPath, "testcert.pem")
}
cfg := v3.New(&config.Params{Logger: log.New()})
var expectedCaCert string
Expand All @@ -522,7 +517,7 @@ func Test_SelfSignedCerts(t *testing.T) {

req.Equal(tt.expectedContextName, ctx.Name)
if tt.setEnv {
os.Unsetenv(pauth.ConfluentCACertPathEnvVar)
os.Unsetenv(pauth.ConfluentPlatformCACertPath)
}
})
}
Expand Down Expand Up @@ -632,7 +627,6 @@ func getNewLoginCommandForSelfSignedCertTest(req *require.Assertions, cfg *v3.Co

func TestLoginWithExistingContext(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
auth := &sdkMock.Auth{
LoginFunc: func(ctx context.Context, idToken string, username string, password string) (string, error) {
return testToken, nil
Expand Down Expand Up @@ -716,7 +710,6 @@ func TestLoginWithExistingContext(t *testing.T) {

func TestValidateUrl(t *testing.T) {
req := require.New(t)
clearCCloudDeprecatedEnvVar(req)
suite := []struct {
urlIn string
valid bool
Expand Down Expand Up @@ -849,11 +842,6 @@ func verifyLoggedOutState(t *testing.T, cfg *v3.Config, loggedOutContext string)
req.Empty(state.Auth)
}

// XX_CCLOUD_EMAIL is used for integration test hack
func clearCCloudDeprecatedEnvVar(req *require.Assertions) {
req.NoError(os.Setenv(pauth.CCloudEmailDeprecatedEnvVar, ""))
}

func TestIsCCloudURL_True(t *testing.T) {
for _, url := range []string{
"confluent.cloud",
Expand Down
3 changes: 1 addition & 2 deletions internal/cmd/logout/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ func verifyLoggedOutState(t *testing.T, cfg *v3.Config, loggedOutContext string)
req.Empty(state.Auth)
}

// XX_CCLOUD_EMAIL is used for integration test hack
func clearCCloudDeprecatedEnvVar(req *require.Assertions) {
req.NoError(os.Setenv(pauth.CCloudEmailDeprecatedEnvVar, ""))
req.NoError(os.Unsetenv(pauth.DeprecatedConfluentCloudEmail))
}
38 changes: 27 additions & 11 deletions internal/pkg/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package auth
import (
"context"
"fmt"
"os"
"strings"

"github.com/dghubble/sling"
Expand All @@ -20,19 +21,34 @@ import (
const (
CCloudURL = "https://confluent.cloud"

CCloudEmailEnvVar = "CCLOUD_EMAIL"
ConfluentUsernameEnvVar = "CONFLUENT_USERNAME"
CCloudPasswordEnvVar = "CCLOUD_PASSWORD"
ConfluentPasswordEnvVar = "CONFLUENT_PASSWORD"
ConfluentCloudEmail = "CONFLUENT_CLOUD_EMAIL"
ConfluentCloudPassword = "CONFLUENT_CLOUD_PASSWORD"
ConfluentPlatformUsername = "CONFLUENT_PLATFORM_USERNAME"
ConfluentPlatformPassword = "CONFLUENT_PLATFORM_PASSWORD"
ConfluentPlatformMDSURL = "CONFLUENT_PLATFORM_MDS_URL"
ConfluentPlatformCACertPath = "CONFLUENT_PLATFORM_CA_CERT_PATH"

DeprecatedConfluentCloudEmail = "CCLOUD_EMAIL"
DeprecatedConfluentCloudPassword = "CCLOUD_PASSWORD"
DeprecatedConfluentPlatformUsername = "CONFLUENT_USERNAME"
DeprecatedConfluentPlatformPassword = "CONFLUENT_PASSWORD"
DeprecatedConfluentPlatformMDSURL = "CONFLUENT_MDS_URL"
DeprecatedConfluentPlatformCACertPath = "CONFLUENT_CA_CERT_PATH"
)

CCloudEmailDeprecatedEnvVar = "XX_CCLOUD_EMAIL"
ConfluentUsernameDeprecatedEnvVar = "XX_CONFLUENT_USERNAME"
CCloudPasswordDeprecatedEnvVar = "XX_CCLOUD_PASSWORD"
ConfluentPasswordDeprecatedEnvVar = "XX_CONFLUENT_PASSWORD"
// GetEnvWithFallback calls os.GetEnv() twice, once for the current var and once for the deprecated var.
func GetEnvWithFallback(current, deprecated string) string {
if val := os.Getenv(current); val != "" {
return val
}

ConfluentURLEnvVar = "CONFLUENT_MDS_URL"
ConfluentCACertPathEnvVar = "CONFLUENT_CA_CERT_PATH"
)
if val := os.Getenv(deprecated); val != "" {
_, _ = fmt.Fprintf(os.Stderr, errors.DeprecatedEnvVarWarningMsg, deprecated, current)
return val
}

return ""
}

func PersistLogoutToConfig(config *v3.Config) error {
ctx := config.Context()
Expand Down
60 changes: 32 additions & 28 deletions internal/pkg/auth/login_credentials_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package auth

import (
"context"
"fmt"
"os"

flowv1 "github.com/confluentinc/cc-structs/kafka/flow/v1"
Expand Down Expand Up @@ -87,28 +88,38 @@ func NewLoginCredentialsManager(netrcHandler netrc.NetrcHandler, prompt form.Pro

func (h *LoginCredentialsManagerImpl) GetCCloudCredentialsFromEnvVar(cmd *cobra.Command) func() (*Credentials, error) {
envVars := environmentVariables{
username: CCloudEmailEnvVar,
password: CCloudPasswordEnvVar,
deprecatedUsername: CCloudEmailDeprecatedEnvVar,
deprecatedPassword: CCloudPasswordDeprecatedEnvVar,
username: ConfluentCloudEmail,
password: ConfluentCloudPassword,
deprecatedUsername: DeprecatedConfluentCloudEmail,
deprecatedPassword: DeprecatedConfluentCloudPassword,
}
return h.getCredentialsFromEnvVarFunc(cmd, envVars)
}

func (h *LoginCredentialsManagerImpl) getCredentialsFromEnvVarFunc(cmd *cobra.Command, envVars environmentVariables) func() (*Credentials, error) {
return func() (*Credentials, error) {
email, password := h.getEnvVarCredentials(cmd, envVars.username, envVars.password)

if h.isSSOUser(email) {
h.logger.Debugf("CCLOUD_EMAIL=%s belongs to an SSO user.", email)
h.logger.Debugf("%s=%s belongs to an SSO user.", ConfluentCloudEmail, email)
return &Credentials{Username: email, IsSSO: true}, nil
}
if len(email) == 0 {

if email == "" {
email, password = h.getEnvVarCredentials(cmd, envVars.deprecatedUsername, envVars.deprecatedPassword)
if email != "" {
_, _ = fmt.Fprintf(os.Stderr, errors.DeprecatedEnvVarWarningMsg, envVars.deprecatedUsername, envVars.username)
}
if password != "" {
_, _ = fmt.Fprintf(os.Stderr, errors.DeprecatedEnvVarWarningMsg, envVars.deprecatedPassword, envVars.password)
}
}
if len(password) == 0 {

if password == "" {
h.logger.Debug("Did not find full credential set from environment variables")
return nil, nil
}

return &Credentials{Username: email, Password: password}, nil
}
}
Expand All @@ -130,10 +141,10 @@ func (h *LoginCredentialsManagerImpl) getEnvVarCredentials(cmd *cobra.Command, u

func (h *LoginCredentialsManagerImpl) GetConfluentCredentialsFromEnvVar(cmd *cobra.Command) func() (*Credentials, error) {
envVars := environmentVariables{
username: ConfluentUsernameEnvVar,
password: ConfluentPasswordEnvVar,
deprecatedUsername: ConfluentUsernameDeprecatedEnvVar,
deprecatedPassword: ConfluentPasswordDeprecatedEnvVar,
username: ConfluentPlatformUsername,
password: ConfluentPlatformPassword,
deprecatedUsername: DeprecatedConfluentPlatformUsername,
deprecatedPassword: DeprecatedConfluentPlatformPassword,
}
return h.getCredentialsFromEnvVarFunc(cmd, envVars)
}
Expand Down Expand Up @@ -187,13 +198,6 @@ func (h *LoginCredentialsManagerImpl) GetConfluentCredentialsFromPrompt(cmd *cob
}

func (h *LoginCredentialsManagerImpl) promptForUser(cmd *cobra.Command, userField string) string {
// HACK: SSO integration test extracts email from env var
// TODO: remove this hack once we implement prompting for integration test
if testEmail := os.Getenv(CCloudEmailDeprecatedEnvVar); len(testEmail) > 0 {
h.logger.Debugf("Using test email \"%s\" found from env var \"%s\"", testEmail, CCloudEmailDeprecatedEnvVar)
return testEmail
}

f := form.New(form.Field{ID: userField, Prompt: userField})
if err := f.Prompt(cmd, h.prompt); err != nil {
return ""
Expand Down Expand Up @@ -236,25 +240,25 @@ func (h *LoginCredentialsManagerImpl) isSSOUser(email string) bool {
// URL and ca-cert-path (if exists) are returned in addition to username and password
func (h *LoginCredentialsManagerImpl) GetConfluentPrerunCredentialsFromEnvVar(cmd *cobra.Command) func() (*Credentials, error) {
return func() (*Credentials, error) {
url := os.Getenv(ConfluentURLEnvVar)
url := GetEnvWithFallback(ConfluentPlatformMDSURL, DeprecatedConfluentPlatformMDSURL)
if url == "" {
return nil, errors.New(errors.NoURLEnvVarErrorMsg)
}

envVars := environmentVariables{
username: ConfluentUsernameEnvVar,
password: ConfluentPasswordEnvVar,
deprecatedUsername: ConfluentUsernameDeprecatedEnvVar,
deprecatedPassword: ConfluentPasswordDeprecatedEnvVar,
}
creds, err := h.getCredentialsFromEnvVarFunc(cmd, envVars)()
if err != nil {
return nil, err
username: ConfluentPlatformUsername,
password: ConfluentPlatformPassword,
deprecatedUsername: DeprecatedConfluentPlatformUsername,
deprecatedPassword: DeprecatedConfluentPlatformPassword,
}

creds, _ := h.getCredentialsFromEnvVarFunc(cmd, envVars)()
if creds == nil {
return nil, errors.New(errors.NoCredentialsFoundErrorMsg)
}
creds.PrerunLoginURL = url
creds.PrerunLoginCaCertPath = os.Getenv(ConfluentCACertPathEnvVar)
creds.PrerunLoginCaCertPath = GetEnvWithFallback(ConfluentPlatformCACertPath, DeprecatedConfluentPlatformCACertPath)

return creds, nil
}
}
Expand Down
Loading