Add ability to pull user/account/auth-method ID from stored token (#517)

This commit is contained in:
Jeff Mitchell authored and GitHub committed 2020-10-01 01:52:08 -04:00
1 parent 6ddfe407a3
commit d851ab07d8
2 files changed
+124 -34

No files matched your search

+39 -28
View File
@@ -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 (
+85 -6
View File
@@ -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
}