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

pull/518/head
Jeff Mitchell 6 years ago committed by GitHub
parent 6ddfe407a3
commit d851ab07d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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 (

@ -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
}

Loading…
Cancel
Save