diff --git a/internal/cmd/base/base.go b/internal/cmd/base/base.go index 01bb7613f4..4b37ae40bf 100644 --- a/internal/cmd/base/base.go +++ b/internal/cmd/base/base.go @@ -192,12 +192,15 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) { it for two subsequent calls. This then becomes a question of how/when to finalize the wrapper. Probably it needs to be stored in the base and then at the end of the command run we finalize it if it - exists. defer func() {if err := wrapper.Finalize(c.Context); err != - nil {c.UI.Error(fmt.Errorf("An error was encountered finalizing the - kms: %w", err).Error()) - } + exists. + + defer func() { + if err := wrapper.Finalize(c.Context); err != nil { + c.UI.Error(fmt.Errorf("An error was encountered finalizing the kms: %w", err).Error()) + } }() */ + c.client.SetRecoveryKmsWrapper(wrapper) case c.FlagToken != "": @@ -209,30 +212,9 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) { } os.Setenv(EnvTokenName, tokenName) if tokenName != "none" { - token, err := keyring.Get("HashiCorp Boundary Auth Token", tokenName) - if err != nil { - if err == keyring.ErrNotFound { - c.UI.Info("No saved credential found, continuing without") - } else { - c.UI.Error(fmt.Sprintf("Error reading auth token from system credential store: %s", err)) - } - token = "" - } - if token != "" { - tokenBytes, err := base64.RawStdEncoding.DecodeString(token) - switch { - case err != nil: - c.UI.Error(fmt.Errorf("Error base64-unmarshaling stored token from system credential store: %w", err).Error()) - case len(tokenBytes) == 0: - c.UI.Error("Zero length token after decoding stored token from system credential store") - default: - var authToken authtokens.AuthToken - if err := json.Unmarshal(tokenBytes, &authToken); err != nil { - c.UI.Error(fmt.Sprintf("Error unmarshaling stored token information after reading from system credential store: %s", err)) - } else { - c.client.SetToken(authToken.Token) - } - } + authToken := c.ReadTokenFromKeyring(tokenName) + if authToken != nil { + c.client.SetToken(authToken.Token) } } } @@ -244,6 +226,35 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) { return c.client, nil } +func (c *Command) ReadTokenFromKeyring(tokenName string) *authtokens.AuthToken { + token, err := keyring.Get("HashiCorp Boundary Auth Token", tokenName) + if err != nil { + if err == keyring.ErrNotFound { + c.UI.Info("No saved credential found, continuing without") + } else { + c.UI.Error(fmt.Sprintf("Error reading auth token from system credential store: %s", err)) + } + token = "" + } + if token != "" { + tokenBytes, err := base64.RawStdEncoding.DecodeString(token) + switch { + case err != nil: + c.UI.Error(fmt.Errorf("Error base64-unmarshaling stored token from system credential store: %w", err).Error()) + case len(tokenBytes) == 0: + c.UI.Error("Zero length token after decoding stored token from system credential store") + default: + var authToken authtokens.AuthToken + if err := json.Unmarshal(tokenBytes, &authToken); err != nil { + c.UI.Error(fmt.Sprintf("Error unmarshaling stored token information after reading from system credential store: %s", err)) + } else { + return &authToken + } + } + } + return nil +} + type FlagSetBit uint const ( diff --git a/internal/cmd/commands/config/token.go b/internal/cmd/commands/config/token.go index 07f7c6af91..ab63000f88 100644 --- a/internal/cmd/commands/config/token.go +++ b/internal/cmd/commands/config/token.go @@ -2,8 +2,8 @@ package config import ( "fmt" - "net/textproto" + "github.com/hashicorp/boundary/api/authtokens" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/mitchellh/cli" "github.com/posener/complete" @@ -16,10 +16,14 @@ type TokenCommand struct { *base.Command Func string + + flagUserId bool + flagAccountId bool + flagAuthMethodId bool } func (c *TokenCommand) Synopsis() string { - return fmt.Sprintf("%s sensitive values in Boundary's configuration file", textproto.CanonicalMIMEHeaderKey(c.Func)) + return fmt.Sprintf("Get the stored token, or its properties") } func (c *TokenCommand) Help() string { @@ -57,6 +61,24 @@ func (c *TokenCommand) Flags() *base.FlagSets { Usage: `If specified, the given value will be used as the name when loading the token from the system credential store. This must correspond to a name used when authenticating.`, }) + f.BoolVar(&base.BoolVar{ + Name: "user-id", + Target: &c.flagUserId, + Usage: `If specified, print out the user ID associated with the token instead of the token itself.`, + }) + + f.BoolVar(&base.BoolVar{ + Name: "account-id", + Target: &c.flagAccountId, + Usage: `If specified, print out the account ID associated with the token instead of the token itself.`, + }) + + f.BoolVar(&base.BoolVar{ + Name: "auth-method-id", + Target: &c.flagAuthMethodId, + Usage: `If specified, print out the auth method ID associated with the token instead of the token itself.`, + }) + return set } @@ -75,13 +97,70 @@ func (c *TokenCommand) Run(args []string) (ret int) { return 1 } - client, err := c.Client() - if err != nil { - c.UI.Error(err.Error()) + var optCount int + if c.flagUserId { + optCount++ + } + if c.flagAccountId { + optCount++ + } + if c.flagAuthMethodId { + optCount++ + } + + if optCount > 1 { + c.UI.Error("Only zero or one output option can be specified.") return 1 } - c.UI.Output(client.Token()) + // Read from keyring first + var authToken *authtokens.AuthToken + tokenName := "default" + if c.FlagTokenName != "" { + tokenName = c.FlagTokenName + } + if tokenName != "none" { + at := c.ReadTokenFromKeyring(tokenName) + if at != nil { + authToken = at + } + } + + if authToken == nil { + // Fallback to env/CLI + client, err := c.Client() + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + authToken = &authtokens.AuthToken{Token: client.Token()} + } + + switch { + case c.flagUserId: + if authToken.UserId == "" { + return 1 + } + c.UI.Output(authToken.UserId) + + case c.flagAccountId: + if authToken.AccountId == "" { + return 1 + } + c.UI.Output(authToken.AccountId) + + case c.flagAuthMethodId: + if authToken.AuthMethodId == "" { + return 1 + } + c.UI.Output(authToken.AuthMethodId) + + default: + if authToken.Token == "" { + return 1 + } + c.UI.Output(authToken.Token) + } return 0 }