This PR changes delete behavior: * On success, a 204 is returned rather than a 200 with an empty JSON object * The CLI now passes through the 404 error if encountered instead of swallowing it It also updates formatting for JSON to use the response body, which means that the item (or items) in the JSON format are actually the format across the wire, instead of being reinterpreted by unmarshaling into the Go SDK and then remarshaling.
106 lines
3.2 KiB
Go
106 lines
3.2 KiB
Go
package authenticate
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/api/authmethods"
|
|
"github.com/hashicorp/boundary/api/authtokens"
|
|
"github.com/hashicorp/boundary/internal/cmd/base"
|
|
nkeyring "github.com/jefferai/keyring"
|
|
zkeyring "github.com/zalando/go-keyring"
|
|
)
|
|
|
|
func saveAndOrPrintToken(c *base.Command, result *authmethods.AuthenticateResult) int {
|
|
token := new(authtokens.AuthToken)
|
|
if err := json.Unmarshal(result.GetRawAttributes(), token); err != nil {
|
|
c.PrintCliError(fmt.Errorf("Error trying to decode response as an auth token: %w", err))
|
|
return base.CommandCliError
|
|
}
|
|
|
|
switch base.Format(c.UI) {
|
|
case "table":
|
|
c.UI.Output(base.WrapForHelpText([]string{
|
|
"",
|
|
"Authentication information:",
|
|
fmt.Sprintf(" Account ID: %s", token.AccountId),
|
|
fmt.Sprintf(" Auth Method ID: %s", token.AuthMethodId),
|
|
fmt.Sprintf(" Expiration Time: %s", token.ExpirationTime.Local().Format(time.RFC1123)),
|
|
fmt.Sprintf(" User ID: %s", token.UserId),
|
|
}))
|
|
|
|
case "json":
|
|
if ok := c.PrintJsonItem(&dummyGenericResponse{
|
|
item: token,
|
|
response: result.GetResponse(),
|
|
}); !ok {
|
|
return base.CommandCliError
|
|
}
|
|
return base.CommandSuccess
|
|
}
|
|
|
|
var gotErr bool
|
|
keyringType, tokenName, err := c.DiscoverKeyringTokenInfo()
|
|
if err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error fetching keyring information: %s", err))
|
|
gotErr = true
|
|
} else if keyringType != "none" &&
|
|
tokenName != "none" &&
|
|
keyringType != "" &&
|
|
tokenName != "" {
|
|
marshaled, err := json.Marshal(token)
|
|
if err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error marshaling auth token to save to keyring: %s", err))
|
|
gotErr = true
|
|
} else {
|
|
switch keyringType {
|
|
case "wincred", "keychain":
|
|
if err := zkeyring.Set(base.StoredTokenName, tokenName, base64.RawStdEncoding.EncodeToString(marshaled)); err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error saving auth token to %q keyring: %s", keyringType, err))
|
|
gotErr = true
|
|
}
|
|
|
|
default:
|
|
krConfig := nkeyring.Config{
|
|
LibSecretCollectionName: "login",
|
|
PassPrefix: "HashiCorp_Boundary",
|
|
AllowedBackends: []nkeyring.BackendType{nkeyring.BackendType(keyringType)},
|
|
}
|
|
|
|
kr, err := nkeyring.Open(krConfig)
|
|
if err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error opening %q keyring: %s", keyringType, err))
|
|
gotErr = true
|
|
break
|
|
}
|
|
|
|
if err := kr.Set(nkeyring.Item{
|
|
Key: tokenName,
|
|
Data: []byte(base64.RawStdEncoding.EncodeToString(marshaled)),
|
|
}); err != nil {
|
|
c.UI.Error(fmt.Sprintf("Error storing token in %q keyring: %s", keyringType, err))
|
|
gotErr = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !gotErr {
|
|
c.UI.Output("\nThe token was successfully stored in the chosen keyring and is not displayed here.")
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case gotErr:
|
|
c.UI.Warn(fmt.Sprintf("The token was not successfully saved to a system keyring. The token is:\n\n%s\n\nIt must be manually passed in via the BOUNDARY_TOKEN env var or -token flag. Storing the token can also be disabled via -keyring-type=none.", token.Token))
|
|
case c.FlagKeyringType == "none":
|
|
c.UI.Warn("\nStoring the token in a keyring was disabled. The token is:")
|
|
c.UI.Output(token.Token)
|
|
c.UI.Warn("Please be sure to store it safely!")
|
|
}
|
|
|
|
return base.CommandSuccess
|
|
}
|