// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package okta import ( "encoding/json" "fmt" "os" "strings" "time" "github.com/hashicorp/go-secure-stdlib/base62" pwd "github.com/hashicorp/go-secure-stdlib/password" "github.com/hashicorp/vault/api" ) // CLIHandler struct type CLIHandler struct{} // Auth cli method func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) { mount, ok := m["mount"] if !ok { mount = "okta" } username, ok := m["username"] if !ok { return nil, fmt.Errorf("'username' var must be set") } password, ok := m["password"] if !ok { fmt.Fprintf(os.Stderr, "Password (will be hidden): ") var err error password, err = pwd.Read(os.Stdin) fmt.Fprintf(os.Stderr, "\n") if err != nil { return nil, err } } data := map[string]interface{}{ "password": password, } // Okta or Google totp code if totp, ok := m["totp"]; ok { data["totp"] = totp } // provider is an optional parameter if provider, ok := m["provider"]; ok { data["provider"] = provider } nonce := base62.MustRandom(20) data["nonce"] = nonce // Create a done channel to signal termination of the login so that we can // clean up the goroutine doneCh := make(chan struct{}) defer close(doneCh) go func() { for { timer := time.NewTimer(time.Second) select { case <-doneCh: timer.Stop() return case <-timer.C: } resp, _ := c.Logical().Read(fmt.Sprintf("auth/%s/verify/%s", mount, nonce)) if resp != nil { fmt.Fprintf(os.Stderr, "In Okta Verify, tap the number %q\n", resp.Data["correct_answer"].(json.Number)) return } } }() path := fmt.Sprintf("auth/%s/login/%s", mount, username) secret, err := c.Logical().Write(path, data) if err != nil { return nil, err } if secret == nil { return nil, fmt.Errorf("empty response from credential provider") } return secret, nil } // Help method for okta cli func (h *CLIHandler) Help() string { help := ` Usage: vault login -method=okta [CONFIG K=V...] The Okta auth method allows users to authenticate using Okta. Authenticate as "sally": $ vault login -method=okta username=sally Password (will be hidden): Authenticate as "bob": $ vault login -method=okta username=bob password=password Configuration: password= Okta password to use for authentication. If not provided, the CLI will prompt for this on stdin. username= Okta username to use for authentication. ` return strings.TrimSpace(help) }