open-vault/api/secret.go

321 lines
8.2 KiB
Go
Raw Normal View History

2015-03-12 00:46:25 +00:00
package api
import (
2018-07-12 14:18:50 +00:00
"bytes"
"fmt"
2015-03-12 00:46:25 +00:00
"io"
"time"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/logical"
2015-03-12 00:46:25 +00:00
)
// Secret is the structure returned for every secret within Vault.
type Secret struct {
2016-07-27 13:25:04 +00:00
// The request ID that generated this response
RequestID string `json:"request_id"`
2015-04-14 00:40:05 +00:00
LeaseID string `json:"lease_id"`
LeaseDuration int `json:"lease_duration"`
Renewable bool `json:"renewable"`
// Data is the actual contents of the secret. The format of the data
// is arbitrary and up to the secret backend.
Data map[string]interface{} `json:"data"`
// Warnings contains any warnings related to the operation. These
// are not issues that caused the command to fail, but that the
// client should be aware of.
Warnings []string `json:"warnings"`
2015-04-14 00:40:05 +00:00
// Auth, if non-nil, means that there was authentication information
// attached to this response.
Auth *SecretAuth `json:"auth,omitempty"`
2016-05-02 05:58:58 +00:00
// WrapInfo, if non-nil, means that the initial response was wrapped in the
// cubbyhole of the given token (which has a TTL of the given number of
// seconds)
WrapInfo *SecretWrapInfo `json:"wrap_info,omitempty"`
}
2017-09-02 22:48:48 +00:00
// TokenID returns the standardized token ID (token) for the given secret.
func (s *Secret) TokenID() (string, error) {
2017-09-02 22:48:48 +00:00
if s == nil {
return "", nil
2017-09-02 22:48:48 +00:00
}
if s.Auth != nil && len(s.Auth.ClientToken) > 0 {
return s.Auth.ClientToken, nil
2017-09-02 22:48:48 +00:00
}
if s.Data == nil || s.Data["id"] == nil {
return "", nil
2017-09-02 22:48:48 +00:00
}
id, ok := s.Data["id"].(string)
if !ok {
return "", fmt.Errorf("token found but in the wrong format")
2017-09-02 22:48:48 +00:00
}
return id, nil
2017-09-02 22:48:48 +00:00
}
// 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
// string.
func (s *Secret) TokenAccessor() (string, error) {
2017-09-02 22:48:48 +00:00
if s == nil {
return "", nil
2017-09-02 22:48:48 +00:00
}
if s.Auth != nil && len(s.Auth.Accessor) > 0 {
return s.Auth.Accessor, nil
2017-09-02 22:48:48 +00:00
}
if s.Data == nil || s.Data["accessor"] == nil {
return "", nil
2017-09-02 22:48:48 +00:00
}
accessor, ok := s.Data["accessor"].(string)
if !ok {
return "", fmt.Errorf("token found but in the wrong format")
2017-09-02 22:48:48 +00:00
}
return accessor, nil
2017-09-02 22:48:48 +00:00
}
// TokenRemainingUses returns the standardized remaining uses for the given
// secret. If the secret is nil or does not contain the "num_uses", this
// returns -1. On error, this will return -1 and a non-nil error.
func (s *Secret) TokenRemainingUses() (int, error) {
2017-09-02 22:48:48 +00:00
if s == nil || s.Data == nil || s.Data["num_uses"] == nil {
return -1, nil
2017-09-02 22:48:48 +00:00
}
return parseutil.SafeParseInt(s.Data["num_uses"])
2017-09-02 22:48:48 +00:00
}
// 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. It
// also populates the secret's Auth info with identity/token policy info.
func (s *Secret) TokenPolicies() ([]string, error) {
2017-09-02 22:48:48 +00:00
if s == nil {
return nil, nil
2017-09-02 22:48:48 +00:00
}
if s.Auth != nil && len(s.Auth.Policies) > 0 {
return s.Auth.Policies, nil
2017-09-02 22:48:48 +00:00
}
if s.Data == nil || s.Data["policies"] == nil {
return nil, nil
}
var tokenPolicies []string
2017-09-02 22:48:48 +00:00
// Token policies
{
_, ok := s.Data["policies"]
if !ok {
goto TOKEN_DONE
}
sList, ok := s.Data["policies"].([]string)
if ok {
tokenPolicies = sList
goto TOKEN_DONE
}
list, ok := s.Data["policies"].([]interface{})
if !ok {
return nil, fmt.Errorf("unable to convert token policies to expected format")
}
for _, v := range list {
p, ok := v.(string)
if !ok {
return nil, fmt.Errorf("unable to convert policy %v to string", v)
}
tokenPolicies = append(tokenPolicies, p)
}
2017-09-02 22:48:48 +00:00
}
TOKEN_DONE:
var identityPolicies []string
// Identity policies
{
_, ok := s.Data["identity_policies"]
2017-09-02 22:48:48 +00:00
if !ok {
goto DONE
}
sList, ok := s.Data["identity_policies"].([]string)
if ok {
identityPolicies = sList
goto DONE
}
list, ok := s.Data["identity_policies"].([]interface{})
if !ok {
return nil, fmt.Errorf("unable to convert identity policies to expected format")
}
for _, v := range list {
p, ok := v.(string)
if !ok {
return nil, fmt.Errorf("unable to convert policy %v to string", v)
}
identityPolicies = append(identityPolicies, p)
2017-09-02 22:48:48 +00:00
}
}
DONE:
if s.Auth == nil {
s.Auth = &SecretAuth{}
}
policies := append(tokenPolicies, identityPolicies...)
s.Auth.TokenPolicies = tokenPolicies
s.Auth.IdentityPolicies = identityPolicies
s.Auth.Policies = policies
return policies, nil
2017-09-02 22:48:48 +00:00
}
// 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
// returns nil.
func (s *Secret) TokenMetadata() (map[string]string, error) {
if s == nil {
return nil, nil
}
if s.Auth != nil && len(s.Auth.Metadata) > 0 {
return s.Auth.Metadata, nil
}
if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) {
return nil, nil
}
data, ok := s.Data["metadata"].(map[string]interface{})
if !ok {
data, ok = s.Data["meta"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("unable to convert metadata field to expected format")
}
}
metadata := make(map[string]string, len(data))
for k, v := range data {
typed, ok := v.(string)
if !ok {
return nil, fmt.Errorf("unable to convert metadata value %v to string", v)
}
metadata[k] = typed
}
return metadata, nil
}
2017-09-02 22:48:48 +00:00
// TokenIsRenewable returns the standardized token renewability for the given
// secret. If the secret is nil or does not contain the "renewable" key, this
// returns false.
func (s *Secret) TokenIsRenewable() (bool, error) {
2017-09-02 22:48:48 +00:00
if s == nil {
return false, nil
2017-09-02 22:48:48 +00:00
}
if s.Auth != nil && s.Auth.Renewable {
return s.Auth.Renewable, nil
2017-09-02 22:48:48 +00:00
}
if s.Data == nil || s.Data["renewable"] == nil {
return false, nil
}
renewable, err := parseutil.ParseBool(s.Data["renewable"])
if err != nil {
return false, errwrap.Wrapf("could not convert renewable value to a boolean: {{err}}", err)
}
return renewable, nil
}
2017-09-02 22:48:48 +00:00
// TokenTTL returns the standardized remaining token TTL for the given secret.
// If the secret is nil or does not contain a TTL, this returns 0.
func (s *Secret) TokenTTL() (time.Duration, error) {
2017-09-02 22:48:48 +00:00
if s == nil {
return 0, nil
2017-09-02 22:48:48 +00:00
}
if s.Auth != nil && s.Auth.LeaseDuration > 0 {
return time.Duration(s.Auth.LeaseDuration) * time.Second, nil
2017-09-02 22:48:48 +00:00
}
if s.Data == nil || s.Data["ttl"] == nil {
return 0, nil
2017-09-02 22:48:48 +00:00
}
ttl, err := parseutil.ParseDurationSecond(s.Data["ttl"])
2017-09-02 22:48:48 +00:00
if err != nil {
return 0, err
2017-09-02 22:48:48 +00:00
}
return ttl, nil
2017-09-02 22:48:48 +00:00
}
// SecretWrapInfo contains wrapping information if we have it. If what is
// contained is an authentication token, the accessor for the token will be
// available in WrappedAccessor.
2016-05-02 05:58:58 +00:00
type SecretWrapInfo struct {
Token string `json:"token"`
2017-11-13 20:31:32 +00:00
Accessor string `json:"accessor"`
TTL int `json:"ttl"`
CreationTime time.Time `json:"creation_time"`
CreationPath string `json:"creation_path"`
WrappedAccessor string `json:"wrapped_accessor"`
2015-04-04 22:40:41 +00:00
}
2015-09-29 07:35:16 +00:00
// SecretAuth is the structure containing auth information if we have it.
2015-04-04 22:40:41 +00:00
type SecretAuth struct {
ClientToken string `json:"client_token"`
Accessor string `json:"accessor"`
Policies []string `json:"policies"`
TokenPolicies []string `json:"token_policies"`
IdentityPolicies []string `json:"identity_policies"`
Metadata map[string]string `json:"metadata"`
Orphan bool `json:"orphan"`
EntityID string `json:"entity_id"`
2015-04-04 22:40:41 +00:00
LeaseDuration int `json:"lease_duration"`
Renewable bool `json:"renewable"`
MFARequirement *logical.MFARequirement `json:"mfa_requirement"`
2015-03-12 00:46:25 +00:00
}
// ParseSecret is used to parse a secret value from JSON from an io.Reader.
func ParseSecret(r io.Reader) (*Secret, error) {
2018-07-12 14:18:50 +00:00
// First read the data into a buffer. Not super efficient but we want to
// know if we actually have a body or not.
var buf bytes.Buffer
_, err := buf.ReadFrom(r)
if err != nil {
return nil, err
}
if buf.Len() == 0 {
return nil, nil
}
2015-03-12 00:46:25 +00:00
// First decode the JSON into a map[string]interface{}
2015-03-16 03:35:33 +00:00
var secret Secret
2018-07-12 14:18:50 +00:00
if err := jsonutil.DecodeJSONFromReader(&buf, &secret); err != nil {
2015-03-12 00:46:25 +00:00
return nil, err
}
2015-03-16 03:35:33 +00:00
return &secret, nil
2015-03-12 00:46:25 +00:00
}