2015-03-12 00:46:25 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2017-09-02 22:48:48 +00:00
|
|
|
"encoding/json"
|
2015-03-12 00:46:25 +00:00
|
|
|
"io"
|
2017-09-02 22:48:48 +00:00
|
|
|
"strconv"
|
2016-06-07 20:01:09 +00:00
|
|
|
"time"
|
2016-07-06 16:25:40 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/vault/helper/jsonutil"
|
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"`
|
|
|
|
|
2015-10-07 19:30:54 +00:00
|
|
|
// 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 {
|
|
|
|
if s == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Auth != nil && len(s.Auth.ClientToken) > 0 {
|
|
|
|
return s.Auth.ClientToken
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Data == nil || s.Data["id"] == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
id, ok := s.Data["id"].(string)
|
|
|
|
if !ok {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
if s == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Auth != nil && len(s.Auth.Accessor) > 0 {
|
|
|
|
return s.Auth.Accessor
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Data == nil || s.Data["accessor"] == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
accessor, ok := s.Data["accessor"].(string)
|
|
|
|
if !ok {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
return accessor
|
|
|
|
}
|
|
|
|
|
|
|
|
// TokenRemainingUses returns the standardized remaining uses for the given
|
|
|
|
// secret. If the secret is nil or does not contain the "num_uses", this returns
|
|
|
|
// 0..
|
|
|
|
func (s *Secret) TokenRemainingUses() int {
|
|
|
|
if s == nil || s.Data == nil || s.Data["num_uses"] == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
usesStr, ok := s.Data["num_uses"].(json.Number)
|
|
|
|
if !ok {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(usesStr) == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
uses, err := strconv.ParseInt(string(usesStr), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(uses)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
// Policies are usually returned as []interface{}, but this function ensures
|
|
|
|
// they are []string.
|
|
|
|
func (s *Secret) TokenPolicies() []string {
|
|
|
|
if s == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Auth != nil && len(s.Auth.Policies) > 0 {
|
|
|
|
return s.Auth.Policies
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Data == nil || s.Data["policies"] == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
list, ok := s.Data["policies"].([]interface{})
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
policies := make([]string, len(list))
|
|
|
|
for i := range list {
|
|
|
|
p, ok := list[i].(string)
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
policies[i] = p
|
|
|
|
}
|
|
|
|
|
|
|
|
return policies
|
|
|
|
}
|
|
|
|
|
2017-09-08 01:55:36 +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 {
|
|
|
|
if s == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Auth != nil && len(s.Auth.Metadata) > 0 {
|
|
|
|
return s.Auth.Metadata
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
data, ok := s.Data["metadata"].(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
data, ok = s.Data["meta"].(map[string]interface{})
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
metadata := make(map[string]string, len(data))
|
|
|
|
for k, v := range data {
|
|
|
|
typed, ok := v.(string)
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
metadata[k] = typed
|
|
|
|
}
|
|
|
|
|
|
|
|
return metadata
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
if s == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Auth != nil && s.Auth.Renewable {
|
|
|
|
return s.Auth.Renewable
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Data == nil || s.Data["renewable"] == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
renewable, ok := s.Data["renewable"].(bool)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return renewable
|
|
|
|
}
|
|
|
|
|
2017-09-08 01:55:36 +00:00
|
|
|
// 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 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return int(i)
|
|
|
|
}
|
|
|
|
|
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 the 0.
|
|
|
|
func (s *Secret) TokenTTL() time.Duration {
|
|
|
|
if s == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.Auth != nil && s.Auth.LeaseDuration > 0 {
|
|
|
|
return time.Duration(s.Auth.LeaseDuration) * time.Second
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
ttl, err := time.ParseDuration(string(ttlStr) + "s")
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return ttl
|
|
|
|
}
|
|
|
|
|
2016-06-13 23:58:17 +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 {
|
2016-06-13 23:58:17 +00:00
|
|
|
Token string `json:"token"`
|
|
|
|
TTL int `json:"ttl"`
|
|
|
|
CreationTime time.Time `json:"creation_time"`
|
2017-08-02 22:28:58 +00:00
|
|
|
CreationPath string `json:"creation_path"`
|
2016-06-13 23:58:17 +00:00
|
|
|
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 {
|
2015-04-24 16:00:00 +00:00
|
|
|
ClientToken string `json:"client_token"`
|
2016-03-09 11:23:31 +00:00
|
|
|
Accessor string `json:"accessor"`
|
2015-04-04 22:40:41 +00:00
|
|
|
Policies []string `json:"policies"`
|
|
|
|
Metadata map[string]string `json:"metadata"`
|
|
|
|
|
|
|
|
LeaseDuration int `json:"lease_duration"`
|
|
|
|
Renewable bool `json:"renewable"`
|
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) {
|
|
|
|
// First decode the JSON into a map[string]interface{}
|
2015-03-16 03:35:33 +00:00
|
|
|
var secret Secret
|
2016-07-06 16:25:40 +00:00
|
|
|
if err := jsonutil.DecodeJSONFromReader(r, &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
|
|
|
}
|