Don't swallow errors on token functions.
This commit is contained in:
parent
9f62e942bb
commit
713d5d5307
156
api/secret.go
156
api/secret.go
|
@ -1,12 +1,12 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/helper/jsonutil"
|
"github.com/hashicorp/vault/helper/jsonutil"
|
||||||
|
"github.com/hashicorp/vault/helper/parseutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Secret is the structure returned for every secret within Vault.
|
// Secret is the structure returned for every secret within Vault.
|
||||||
|
@ -38,131 +38,125 @@ type Secret struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenID returns the standardized token ID (token) for the given secret.
|
// TokenID returns the standardized token ID (token) for the given secret.
|
||||||
func (s *Secret) TokenID() string {
|
func (s *Secret) TokenID() (string, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Auth != nil && len(s.Auth.ClientToken) > 0 {
|
if s.Auth != nil && len(s.Auth.ClientToken) > 0 {
|
||||||
return s.Auth.ClientToken
|
return s.Auth.ClientToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Data == nil || s.Data["id"] == nil {
|
if s.Data == nil || s.Data["id"] == nil {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
id, ok := s.Data["id"].(string)
|
id, ok := s.Data["id"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return "", fmt.Errorf("token found but in the wrong format")
|
||||||
}
|
}
|
||||||
|
|
||||||
return id
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenAccessor returns the standardized token accessor for the given secret.
|
// TokenAccessor returns the standardized token accessor for the given secret.
|
||||||
// If the secret is nil or does not contain an accessor, this returns the empty
|
// If the secret is nil or does not contain an accessor, this returns the empty
|
||||||
// string.
|
// string.
|
||||||
func (s *Secret) TokenAccessor() string {
|
func (s *Secret) TokenAccessor() (string, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Auth != nil && len(s.Auth.Accessor) > 0 {
|
if s.Auth != nil && len(s.Auth.Accessor) > 0 {
|
||||||
return s.Auth.Accessor
|
return s.Auth.Accessor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Data == nil || s.Data["accessor"] == nil {
|
if s.Data == nil || s.Data["accessor"] == nil {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
accessor, ok := s.Data["accessor"].(string)
|
accessor, ok := s.Data["accessor"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return "", fmt.Errorf("token found but in the wrong format")
|
||||||
}
|
}
|
||||||
|
|
||||||
return accessor
|
return accessor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenRemainingUses returns the standardized remaining uses for the given
|
// TokenRemainingUses returns the standardized remaining uses for the given
|
||||||
// secret. If the secret is nil or does not contain the "num_uses", this returns
|
// secret. If the secret is nil or does not contain the "num_uses", this
|
||||||
// 0..
|
// returns -1. On error, this will return -1 and a non-nil error.
|
||||||
func (s *Secret) TokenRemainingUses() int {
|
func (s *Secret) TokenRemainingUses() (int, error) {
|
||||||
if s == nil || s.Data == nil || s.Data["num_uses"] == nil {
|
if s == nil || s.Data == nil || s.Data["num_uses"] == nil {
|
||||||
return 0
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
usesStr, ok := s.Data["num_uses"].(json.Number)
|
uses, err := parseutil.ParseInt(s.Data["num_uses"])
|
||||||
if !ok {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(usesStr) == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
uses, err := strconv.ParseInt(string(usesStr), 10, 64)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(uses)
|
return int(uses), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenPolicies returns the standardized list of policies for the given secret.
|
// TokenPolicies returns the standardized list of policies for the given secret.
|
||||||
// If the secret is nil or does not contain any policies, this returns nil.
|
// If the secret is nil or does not contain any policies, this returns nil.
|
||||||
// Policies are usually returned as []interface{}, but this function ensures
|
func (s *Secret) TokenPolicies() ([]string, error) {
|
||||||
// they are []string.
|
|
||||||
func (s *Secret) TokenPolicies() []string {
|
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Auth != nil && len(s.Auth.Policies) > 0 {
|
if s.Auth != nil && len(s.Auth.Policies) > 0 {
|
||||||
return s.Auth.Policies
|
return s.Auth.Policies, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Data == nil || s.Data["policies"] == nil {
|
if s.Data == nil || s.Data["policies"] == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sList, ok := s.Data["policies"].([]string)
|
||||||
|
if ok {
|
||||||
|
return sList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
list, ok := s.Data["policies"].([]interface{})
|
list, ok := s.Data["policies"].([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil, fmt.Errorf("unable to convert token policies to expected format")
|
||||||
}
|
}
|
||||||
|
|
||||||
policies := make([]string, len(list))
|
policies := make([]string, len(list))
|
||||||
for i := range list {
|
for i := range list {
|
||||||
p, ok := list[i].(string)
|
p, ok := list[i].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil, fmt.Errorf("unable to convert policy %v to string", list[i])
|
||||||
}
|
}
|
||||||
policies[i] = p
|
policies[i] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
return policies
|
return policies, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenMetadata returns the map of metadata associated with this token, if any
|
// TokenMetadata returns the map of metadata associated with this token, if any
|
||||||
// exists. If the secret is nil or does not contain the "metadata" key, this
|
// exists. If the secret is nil or does not contain the "metadata" key, this
|
||||||
// returns nil.
|
// returns nil.
|
||||||
func (s *Secret) TokenMetadata() map[string]string {
|
func (s *Secret) TokenMetadata() (map[string]string, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Auth != nil && len(s.Auth.Metadata) > 0 {
|
if s.Auth != nil && len(s.Auth.Metadata) > 0 {
|
||||||
return s.Auth.Metadata
|
return s.Auth.Metadata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) {
|
if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data, ok := s.Data["metadata"].(map[string]interface{})
|
data, ok := s.Data["metadata"].(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
data, ok = s.Data["meta"].(map[string]interface{})
|
data, ok = s.Data["meta"].(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil, fmt.Errorf("unable to convert metadata field to expected format")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,99 +164,59 @@ func (s *Secret) TokenMetadata() map[string]string {
|
||||||
for k, v := range data {
|
for k, v := range data {
|
||||||
typed, ok := v.(string)
|
typed, ok := v.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil, fmt.Errorf("unable to convert metadata value %v to string", v)
|
||||||
}
|
}
|
||||||
metadata[k] = typed
|
metadata[k] = typed
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata
|
return metadata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenIsRenewable returns the standardized token renewability for the given
|
// TokenIsRenewable returns the standardized token renewability for the given
|
||||||
// secret. If the secret is nil or does not contain the "renewable" key, this
|
// secret. If the secret is nil or does not contain the "renewable" key, this
|
||||||
// returns false.
|
// returns false.
|
||||||
func (s *Secret) TokenIsRenewable() bool {
|
func (s *Secret) TokenIsRenewable() (bool, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Auth != nil && s.Auth.Renewable {
|
if s.Auth != nil && s.Auth.Renewable {
|
||||||
return s.Auth.Renewable
|
return s.Auth.Renewable, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Data == nil || s.Data["renewable"] == nil {
|
if s.Data == nil || s.Data["renewable"] == nil {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
renewable, ok := s.Data["renewable"].(bool)
|
renewable, err := parseutil.ParseBool(s.Data["renewable"])
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return renewable
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenTTLInt returns the token's TTL as an integer number of seconds.
|
|
||||||
func (s *Secret) TokenTTLInt() int {
|
|
||||||
if s == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Auth != nil && s.Auth.LeaseDuration > 0 {
|
|
||||||
return s.Auth.LeaseDuration
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Data == nil || s.Data["ttl"] == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
ttlStr, ok := s.Data["ttl"].(json.Number)
|
|
||||||
if !ok {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(ttlStr) == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
i, err := strconv.ParseInt(string(ttlStr), 0, 64)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return false, fmt.Errorf("could not convert renewable value to a boolean: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(i)
|
return renewable, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenTTL returns the standardized remaining token TTL for the given secret.
|
// TokenTTL returns the standardized remaining token TTL for the given secret.
|
||||||
// If the secret is nil or does not contain a TTL, this returns the 0.
|
// If the secret is nil or does not contain a TTL, this returns 0.
|
||||||
func (s *Secret) TokenTTL() time.Duration {
|
func (s *Secret) TokenTTL() (time.Duration, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return 0
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Auth != nil && s.Auth.LeaseDuration > 0 {
|
if s.Auth != nil && s.Auth.LeaseDuration > 0 {
|
||||||
return time.Duration(s.Auth.LeaseDuration) * time.Second
|
return time.Duration(s.Auth.LeaseDuration) * time.Second, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Data == nil || s.Data["ttl"] == nil {
|
if s.Data == nil || s.Data["ttl"] == nil {
|
||||||
return 0
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ttlStr, ok := s.Data["ttl"].(json.Number)
|
ttl, err := parseutil.ParseDurationSecond(s.Data["ttl"])
|
||||||
if !ok {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(ttlStr) == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
ttl, err := time.ParseDuration(string(ttlStr) + "s")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ttl
|
return ttl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretWrapInfo contains wrapping information if we have it. If what is
|
// SecretWrapInfo contains wrapping information if we have it. If what is
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -95,15 +95,39 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, erro
|
||||||
// Return an auth struct that "looks" like the response from an auth method.
|
// Return an auth struct that "looks" like the response from an auth method.
|
||||||
// lookup and lookup-self return their data in data, not auth. We try to
|
// lookup and lookup-self return their data in data, not auth. We try to
|
||||||
// mirror that data here.
|
// mirror that data here.
|
||||||
|
id, err := secret.TokenID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error accessing token ID: %s", err)
|
||||||
|
}
|
||||||
|
accessor, err := secret.TokenAccessor()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error accessing token accessor: %s", err)
|
||||||
|
}
|
||||||
|
policies, err := secret.TokenPolicies()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error accessing token policies: %s", err)
|
||||||
|
}
|
||||||
|
metadata, err := secret.TokenMetadata()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error accessing token metadata: %s", err)
|
||||||
|
}
|
||||||
|
dur, err := secret.TokenTTL()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error converting token TTL: %s", err)
|
||||||
|
}
|
||||||
|
renewable, err := secret.TokenIsRenewable()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error checking if token is renewable: %s", err)
|
||||||
|
}
|
||||||
return &api.Secret{
|
return &api.Secret{
|
||||||
Auth: &api.SecretAuth{
|
Auth: &api.SecretAuth{
|
||||||
ClientToken: secret.TokenID(),
|
ClientToken: id,
|
||||||
Accessor: secret.TokenAccessor(),
|
Accessor: accessor,
|
||||||
Policies: secret.TokenPolicies(),
|
Policies: policies,
|
||||||
Metadata: secret.TokenMetadata(),
|
Metadata: metadata,
|
||||||
|
|
||||||
LeaseDuration: secret.TokenTTLInt(),
|
LeaseDuration: int(dur.Seconds()),
|
||||||
Renewable: secret.TokenIsRenewable(),
|
Renewable: renewable,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
|
|
@ -478,7 +478,10 @@ func TestLoginCommand_Run(t *testing.T) {
|
||||||
|
|
||||||
// There was 1 use to start, make sure we didn't use it (verifying would
|
// There was 1 use to start, make sure we didn't use it (verifying would
|
||||||
// use it).
|
// use it).
|
||||||
uses := lookup.TokenRemainingUses()
|
uses, err := lookup.TokenRemainingUses()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
if uses != 1 {
|
if uses != 1 {
|
||||||
t.Errorf("expected %d to be %d", uses, 1)
|
t.Errorf("expected %d to be %d", uses, 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,43 @@ func ParseDurationSecond(in interface{}) (time.Duration, error) {
|
||||||
return dur, nil
|
return dur, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseInt(in interface{}) (int64, error) {
|
||||||
|
var ret int64
|
||||||
|
jsonIn, ok := in.(json.Number)
|
||||||
|
if ok {
|
||||||
|
in = jsonIn.String()
|
||||||
|
}
|
||||||
|
switch in.(type) {
|
||||||
|
case string:
|
||||||
|
inp := in.(string)
|
||||||
|
if inp == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
left, err := strconv.ParseInt(inp, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
ret = left
|
||||||
|
case int:
|
||||||
|
ret = int64(in.(int))
|
||||||
|
case int32:
|
||||||
|
ret = int64(in.(int32))
|
||||||
|
case int64:
|
||||||
|
ret = in.(int64)
|
||||||
|
case uint:
|
||||||
|
ret = int64(in.(uint))
|
||||||
|
case uint32:
|
||||||
|
ret = int64(in.(uint32))
|
||||||
|
case uint64:
|
||||||
|
ret = int64(in.(uint64))
|
||||||
|
default:
|
||||||
|
return 0, errors.New("could not parse value from input")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ParseBool(in interface{}) (bool, error) {
|
func ParseBool(in interface{}) (bool, error) {
|
||||||
var result bool
|
var result bool
|
||||||
if err := mapstructure.WeakDecode(in, &result); err != nil {
|
if err := mapstructure.WeakDecode(in, &result); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue