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

Auth "init", "switch", "remove" Forces Lowercase #1362

Merged
merged 4 commits into from
Apr 13, 2023
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
31 changes: 25 additions & 6 deletions commands/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ To remove accounts from the configuration file, you can run ` + "`" + `doctl aut

You will need an API token, which you can generate in the control panel at https://cloud.digitalocean.com/account/api/tokens.

You can provide a name to this initialization via the `+"`"+`--context`+"`"+` flag, and then it will be saved as an "authentication context". Authentication contexts are accessible via `+"`"+`doctl auth switch`+"`"+`, which re-initializes doctl, or by providing the `+"`"+`--context`+"`"+` flag when using any doctl command (to specify that auth context for just one command). This enables you to use multiple DigitalOcean accounts with doctl, or tokens that have different authentication scopes.
You can provide a (case insensitive) name to this initialization via the `+"`"+`--context`+"`"+` flag, and then it will be saved as an "authentication context". Authentication contexts are accessible via `+"`"+`doctl auth switch`+"`"+`, which re-initializes doctl, or by providing the `+"`"+`--context`+"`"+` flag when using any doctl command (to specify that auth context for just one command). This enables you to use multiple DigitalOcean accounts with doctl, or tokens that have different authentication scopes.

If the `+"`"+`--context`+"`"+` flag is not specified, a default authentication context will be created during initialization.

Expand Down Expand Up @@ -146,9 +146,9 @@ To create new contexts, see the help for `+"`"+`doctl auth init`+"`"+`.`, Writer
func RunAuthInit(retrieveUserTokenFunc func() (string, error)) func(c *CmdConfig) error {
return func(c *CmdConfig) error {
token := c.getContextAccessToken()
context := Context
context := strings.ToLower(Context)
if context == "" {
context = viper.GetString("context")
context = strings.ToLower(viper.GetString("context"))
}

if token == "" {
Expand Down Expand Up @@ -188,7 +188,7 @@ func RunAuthInit(retrieveUserTokenFunc func() (string, error)) func(c *CmdConfig

// RunAuthRemove remove available auth contexts from the user's doctl config.
func RunAuthRemove(c *CmdConfig) error {
context := Context
context := strings.ToLower(Context)

if context == "" {
return fmt.Errorf("You must provide a context name")
Expand Down Expand Up @@ -243,9 +243,28 @@ func displayAuthContexts(out io.Writer, currentContext string, contexts map[stri
// RunAuthSwitch changes the default context and writes it to the
// configuration.
func RunAuthSwitch(c *CmdConfig) error {
context := Context
context := strings.ToLower(Context)
if context == "" {
context = viper.GetString("context")
context = strings.ToLower(viper.GetString("context"))
}

// check that context exists
contextsAvail := viper.GetStringMap("auth-contexts")
contextsAvail[doctl.ArgDefaultContext] = true
keys := make([]string, 0)
for ctx := range contextsAvail {
keys = append(keys, ctx)
}

var contextExists bool
for _, ctx := range keys {
if ctx == context {
contextExists = true
}
}

if !contextExists {
return errors.New("context does not exist")
}

// The two lines below aren't required for doctl specific functionality,
Expand Down
39 changes: 39 additions & 0 deletions commands/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,45 @@ func TestAuthInitWithProvidedToken(t *testing.T) {
})
}

func TestAuthForcesLowercase(t *testing.T) {
cfw := cfgFileWriter
viper.Set(doctl.ArgAccessToken, "valid-token")
defer func() {
cfgFileWriter = cfw
viper.Set(doctl.ArgAccessToken, nil)
}()

retrieveUserTokenFunc := func() (string, error) {
return "", errors.New("should not have called this")
}

cfgFileWriter = func() (io.WriteCloser, error) { return &nopWriteCloser{Writer: ioutil.Discard}, nil }

withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.oauth.EXPECT().TokenInfo(gomock.Any()).Return(&do.OAuthTokenInfo{}, nil)

contexts := map[string]interface{}{doctl.ArgDefaultContext: true, "TestCapitalCase": true}
context := "TestCapitalCase"
viper.Set("auth-contexts", contexts)
viper.Set("context", context)

err := RunAuthInit(retrieveUserTokenFunc)(config)
assert.NoError(t, err)

contexts = map[string]interface{}{doctl.ArgDefaultContext: true, "TestCapitalCase": true}
viper.Set("auth-contexts", contexts)
viper.Set("context", "contextDoesntExist")
err = RunAuthSwitch(config)
// should error because context doesn't exist
assert.Error(t, err)

viper.Set("context", "testcapitalcase")
err = RunAuthSwitch(config)
// should not error because context does exist
assert.NoError(t, err)
})
}

func TestAuthList(t *testing.T) {
buf := &bytes.Buffer{}
config := &CmdConfig{Out: buf}
Expand Down
1 change: 1 addition & 0 deletions commands/doit.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func initConfig() {

viper.SetDefault("output", "text")
viper.SetDefault(doctl.ArgContext, doctl.ArgDefaultContext)
Context = strings.ToLower(Context)

if _, err := os.Stat(cfgFile); err == nil {
if err := viper.ReadInConfig(); err != nil {
Expand Down