Merge branch 'master-oss' into json-use-number

Conflicts:
	http/handler.go
	logical/framework/field_data.go
	logical/framework/wal.go
	vault/logical_passthrough.go
This commit is contained in:
vishalnayak 2016-07-15 19:21:55 -04:00
commit 5b458db104
56 changed files with 1629 additions and 289 deletions

View file

@ -18,6 +18,12 @@ FEATURES:
modified after upgrading contain a set of default key usages for increased
compatibility with OpenVPN and some other software. This set can be changed
when writing a role definition. Existing roles are unaffected. [GH-1552]
* **Request Retrying in the CLI and Go API**: Requests that fail with a `5xx`
error code will now retry after a backoff. The maximum total number of
retries (including disabling this functionality) can be set with an
environment variable. See the [environment variable
documentation](https://www.vaultproject.io/docs/commands/environment.html)
for more details. [GH-1594]
IMPROVEMENTS:
* cli: Output formatting in the presence of warnings in the response object
@ -40,6 +46,8 @@ IMPROVEMENTS:
configuration [GH-1581]
* secret/mssql,mysql,postgresql: Reading of connection settings is supported
in all the sql backends [GH-1515]
* credential/ldap, secret/cassandra, physical/consul: Clients with `tls.Config`
will have `MinVersion` set to TLS 1.2 by default.
BUG FIXES:

View file

@ -14,6 +14,7 @@ import (
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-rootcerts"
"github.com/sethgrid/pester"
)
const EnvVaultAddress = "VAULT_ADDR"
@ -24,6 +25,7 @@ const EnvVaultClientKey = "VAULT_CLIENT_KEY"
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
const EnvVaultMaxRetries = "VAULT_MAX_RETRIES"
var (
errRedirect = errors.New("redirect")
@ -49,6 +51,10 @@ type Config struct {
HttpClient *http.Client
redirectSetup sync.Once
// MaxRetries controls the maximum number of times to retry when a 5xx error
// occurs. Set to 0 or less to disable retrying.
MaxRetries int
}
// DefaultConfig returns a default configuration for the client. It is
@ -73,6 +79,8 @@ func DefaultConfig() *Config {
config.Address = v
}
config.MaxRetries = pester.DefaultClient.MaxRetries
return config
}
@ -89,6 +97,8 @@ func (c *Config) ReadEnvironment() error {
var foundInsecure bool
var envTLSServerName string
var envMaxRetries *uint64
var clientCert tls.Certificate
var foundClientCert bool
var err error
@ -96,6 +106,13 @@ func (c *Config) ReadEnvironment() error {
if v := os.Getenv(EnvVaultAddress); v != "" {
envAddress = v
}
if v := os.Getenv(EnvVaultMaxRetries); v != "" {
maxRetries, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return err
}
envMaxRetries = &maxRetries
}
if v := os.Getenv(EnvVaultCACert); v != "" {
envCACert = v
}
@ -132,11 +149,24 @@ func (c *Config) ReadEnvironment() error {
}
}
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
rootConfig := &rootcerts.Config{
CAFile: envCACert,
CAPath: envCAPath,
}
err = rootcerts.ConfigureTLS(clientTLSConfig, rootConfig)
if err != nil {
return err
}
if envAddress != "" {
c.Address = envAddress
}
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
if envMaxRetries != nil {
c.MaxRetries = int(*envMaxRetries) + 1
}
if foundInsecure {
clientTLSConfig.InsecureSkipVerify = envInsecure
}
@ -148,15 +178,6 @@ func (c *Config) ReadEnvironment() error {
clientTLSConfig.ServerName = envTLSServerName
}
rootConfig := &rootcerts.Config{
CAFile: envCACert,
CAPath: envCAPath,
}
err = rootcerts.ConfigureTLS(clientTLSConfig, rootConfig)
if err != nil {
return err
}
return nil
}
@ -273,8 +294,12 @@ START:
return nil, err
}
client := pester.NewExtendedClient(c.config.HttpClient)
client.Backoff = pester.LinearJitterBackoff
client.MaxRetries = c.config.MaxRetries
var result *Response
resp, err := c.config.HttpClient.Do(req)
resp, err := client.Do(req)
if resp != nil {
result = &Response{Response: resp}
}

View file

@ -107,16 +107,19 @@ func TestClientEnvSettings(t *testing.T) {
oldClientCert := os.Getenv(EnvVaultClientCert)
oldClientKey := os.Getenv(EnvVaultClientKey)
oldSkipVerify := os.Getenv(EnvVaultInsecure)
os.Setenv("VAULT_CACERT", cwd+"/test-fixtures/keys/cert.pem")
os.Setenv("VAULT_CAPATH", cwd+"/test-fixtures/keys")
os.Setenv("VAULT_CLIENT_CERT", cwd+"/test-fixtures/keys/cert.pem")
os.Setenv("VAULT_CLIENT_KEY", cwd+"/test-fixtures/keys/key.pem")
os.Setenv("VAULT_SKIP_VERIFY", "true")
defer os.Setenv("VAULT_CACERT", oldCACert)
defer os.Setenv("VAULT_CAPATH", oldCAPath)
defer os.Setenv("VAULT_CLIENT_CERT", oldClientCert)
defer os.Setenv("VAULT_CLIENT_KEY", oldClientKey)
defer os.Setenv("VAULT_SKIP_VERIFY", oldSkipVerify)
oldMaxRetries := os.Getenv(EnvVaultMaxRetries)
os.Setenv(EnvVaultCACert, cwd+"/test-fixtures/keys/cert.pem")
os.Setenv(EnvVaultCAPath, cwd+"/test-fixtures/keys")
os.Setenv(EnvVaultClientCert, cwd+"/test-fixtures/keys/cert.pem")
os.Setenv(EnvVaultClientKey, cwd+"/test-fixtures/keys/key.pem")
os.Setenv(EnvVaultInsecure, "true")
os.Setenv(EnvVaultMaxRetries, "5")
defer os.Setenv(EnvVaultCACert, oldCACert)
defer os.Setenv(EnvVaultCAPath, oldCAPath)
defer os.Setenv(EnvVaultClientCert, oldClientCert)
defer os.Setenv(EnvVaultClientKey, oldClientKey)
defer os.Setenv(EnvVaultInsecure, oldSkipVerify)
defer os.Setenv(EnvVaultMaxRetries, oldMaxRetries)
config := DefaultConfig()
if err := config.ReadEnvironment(); err != nil {

View file

@ -18,7 +18,7 @@ func TestCopy_auth(t *testing.T) {
expected := logical.Auth{
LeaseOptions: logical.LeaseOptions{
TTL: 1 * time.Hour,
IssueTime: time.Now().UTC(),
IssueTime: time.Now(),
},
ClientToken: "foo",
@ -109,7 +109,7 @@ func TestHashString(t *testing.T) {
}
func TestHash(t *testing.T) {
now := time.Now().UTC()
now := time.Now()
cases := []struct {
Input interface{}

View file

@ -110,7 +110,7 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {
func (b *backend) periodicFunc(req *logical.Request) error {
// Run the tidy operations for the first time. Then run it when current
// time matches the nextTidyTime.
if b.nextTidyTime.IsZero() || !time.Now().UTC().Before(b.nextTidyTime) {
if b.nextTidyTime.IsZero() || !time.Now().Before(b.nextTidyTime) {
// safety_buffer defaults to 180 days for roletag blacklist
safety_buffer := 15552000
tidyBlacklistConfigEntry, err := b.lockedConfigTidyRoleTags(req.Storage)
@ -154,7 +154,7 @@ func (b *backend) periodicFunc(req *logical.Request) error {
}
// Update the time at which to run the tidy functions again.
b.nextTidyTime = time.Now().UTC().Add(b.tidyCooldownPeriod)
b.nextTidyTime = time.Now().Add(b.tidyCooldownPeriod)
}
return nil
}

View file

@ -356,7 +356,7 @@ func (b *backend) pathLoginUpdate(
}
// Save the login attempt in the identity whitelist.
currentTime := time.Now().UTC()
currentTime := time.Now()
if storedIdentity == nil {
// Role, ClientNonce and CreationTime of the identity entry,
// once set, should never change.
@ -549,7 +549,7 @@ func (b *backend) pathLoginRenew(
}
// Only LastUpdatedTime and ExpirationTime change and all other fields remain the same.
currentTime := time.Now().UTC()
currentTime := time.Now()
storedIdentity.LastUpdatedTime = currentTime
storedIdentity.ExpirationTime = currentTime.Add(longestMaxTTL)

View file

@ -186,7 +186,7 @@ func (b *backend) pathRoletagBlacklistUpdate(
blEntry = &roleTagBlacklistEntry{}
}
currentTime := time.Now().UTC()
currentTime := time.Now()
// Check if this is a creation of blacklist entry.
if blEntry.CreationTime.IsZero() {

View file

@ -65,7 +65,7 @@ func (b *backend) tidyWhitelistIdentity(s logical.Storage, safety_buffer int) er
return err
}
if time.Now().UTC().After(result.ExpirationTime.Add(bufferDuration)) {
if time.Now().After(result.ExpirationTime.Add(bufferDuration)) {
if err := s.Delete("whitelist/identity" + instanceID); err != nil {
return fmt.Errorf("error deleting identity of instanceID %s from storage: %s", instanceID, err)
}

View file

@ -64,7 +64,7 @@ func (b *backend) tidyBlacklistRoleTag(s logical.Storage, safety_buffer int) err
return err
}
if time.Now().UTC().After(result.ExpirationTime.Add(bufferDuration)) {
if time.Now().After(result.ExpirationTime.Add(bufferDuration)) {
if err := s.Delete("blacklist/roletag" + tag); err != nil {
return fmt.Errorf("error deleting tag %s from storage: %s", tag, err)
}

View file

@ -8,7 +8,9 @@ import (
"net/url"
"strings"
"github.com/fatih/structs"
"github.com/go-ldap/ldap"
"github.com/hashicorp/vault/helper/tlsutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
@ -71,6 +73,12 @@ func pathConfig(b *backend) *framework.Path {
Type: framework.TypeBool,
Description: "Issue a StartTLS command after establishing unencrypted connection (optional)",
},
"tls_min_version": &framework.FieldSchema{
Type: framework.TypeString,
Default: "tls12",
Description: "Minimum TLS version to use. Accepted values are 'tls10', 'tls11' or 'tls12'. Defaults to 'tls12'",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
@ -111,19 +119,7 @@ func (b *backend) pathConfigRead(
}
return &logical.Response{
Data: map[string]interface{}{
"url": cfg.Url,
"userdn": cfg.UserDN,
"groupdn": cfg.GroupDN,
"upndomain": cfg.UPNDomain,
"userattr": cfg.UserAttr,
"certificate": cfg.Certificate,
"insecure_tls": cfg.InsecureTLS,
"starttls": cfg.StartTLS,
"binddn": cfg.BindDN,
"bindpass": cfg.BindPassword,
"discoverdn": cfg.DiscoverDN,
},
Data: structs.New(cfg).Map(),
}, nil
}
@ -159,6 +155,17 @@ func (b *backend) pathConfigWrite(
if insecureTLS {
cfg.InsecureTLS = insecureTLS
}
cfg.TLSMinVersion = d.Get("tls_min_version").(string)
if cfg.TLSMinVersion == "" {
return logical.ErrorResponse("failed to get 'tls_min_version' value"), nil
}
var ok bool
_, ok = tlsutil.TLSLookup[cfg.TLSMinVersion]
if !ok {
return logical.ErrorResponse("invalid 'tls_min_version'"), nil
}
startTLS := d.Get("starttls").(bool)
if startTLS {
cfg.StartTLS = startTLS
@ -200,23 +207,33 @@ func (b *backend) pathConfigWrite(
}
type ConfigEntry struct {
Url string
UserDN string
GroupDN string
UPNDomain string
UserAttr string
Certificate string
InsecureTLS bool
StartTLS bool
BindDN string
BindPassword string
DiscoverDN bool
Url string `json:"url" structs:"url" mapstructure:"url"`
UserDN string `json:"userdn" structs:"userdn" mapstructure:"userdn"`
GroupDN string `json:"groupdn" structs:"groupdn" mapstructure:"groupdn"`
UPNDomain string `json:"upndomain" structs:"upndomain" mapstructure:"upndomain"`
UserAttr string `json:"userattr" structs:"userattr" mapstructure:"userattr"`
Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"`
InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls" mapstructure:"insecure_tls"`
StartTLS bool `json:"starttls" structs:"starttls" mapstructure:"starttls"`
BindDN string `json:"binddn" structs:"binddn" mapstructure:"binddn"`
BindPassword string `json:"bindpass" structs:"bindpass" mapstructure:"bindpass"`
DiscoverDN bool `json:"discoverdn" structs:"discoverdn" mapstructure:"discoverdn"`
TLSMinVersion string `json:"tls_min_version" structs:"tls_min_version" mapstructure:"tls_min_version"`
}
func (c *ConfigEntry) GetTLSConfig(host string) (*tls.Config, error) {
tlsConfig := &tls.Config{
ServerName: host,
}
if c.TLSMinVersion != "" {
tlsMinVersion, ok := tlsutil.TLSLookup[c.TLSMinVersion]
if !ok {
return nil, fmt.Errorf("invalid 'tls_min_version' in config")
}
tlsConfig.MinVersion = tlsMinVersion
}
if c.InsecureTLS {
tlsConfig.InsecureSkipVerify = true
}

View file

@ -60,12 +60,7 @@ func genUsername(displayName, policyName, userType string) (ret string, warning
// with, so don't insert display name or policy name at all
}
ret = fmt.Sprintf(
"vault-%s%d-%d",
midString,
time.Now().Unix(),
rand.Int31n(10000))
ret = fmt.Sprintf("vault-%s%d-%d", midString, time.Now().Unix(), rand.Int31n(10000))
return
}

View file

@ -46,16 +46,17 @@ type backend struct {
}
type sessionConfig struct {
Hosts string `json:"hosts" structs:"hosts"`
Username string `json:"username" structs:"username"`
Password string `json:"password" structs:"password"`
TLS bool `json:"tls" structs:"tls"`
InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls"`
Certificate string `json:"certificate" structs:"certificate"`
PrivateKey string `json:"private_key" structs:"private_key"`
IssuingCA string `json:"issuing_ca" structs:"issuing_ca"`
ProtocolVersion int `json:"protocol_version" structs:"protocol_version"`
ConnectTimeout int `json:"connect_timeout" structs:"connect_timeout"`
Hosts string `json:"hosts" structs:"hosts" mapstructure:"hosts"`
Username string `json:"username" structs:"username" mapstructure:"username"`
Password string `json:"password" structs:"password" mapstructure:"password"`
TLS bool `json:"tls" structs:"tls" mapstructure:"tls"`
InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls" mapstructure:"insecure_tls"`
Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"`
PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"`
IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"`
ProtocolVersion int `json:"protocol_version" structs:"protocol_version" mapstructure:"protocol_version"`
ConnectTimeout int `json:"connect_timeout" structs:"connect_timeout" mapstructure:"connect_timeout"`
TLSMinVersion string `json:"tls_min_version" structs:"tls_min_version" mapstructure:"tls_min_version"`
}
// DB returns the database connection.

View file

@ -5,6 +5,7 @@ import (
"github.com/fatih/structs"
"github.com/hashicorp/vault/helper/certutil"
"github.com/hashicorp/vault/helper/tlsutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
@ -40,6 +41,12 @@ set, this is automatically set to true`,
effect if a CA certificate is provided`,
},
"tls_min_version": &framework.FieldSchema{
Type: framework.TypeString,
Default: "tls12",
Description: "Minimum TLS version to use. Accepted values are 'tls10', 'tls11' or 'tls12'. Defaults to 'tls12'",
},
"pem_bundle": &framework.FieldSchema{
Type: framework.TypeString,
Description: `PEM-format, concatenated unencrypted secret key
@ -128,6 +135,17 @@ func (b *backend) pathConnectionWrite(
ConnectTimeout: data.Get("connect_timeout").(int),
}
config.TLSMinVersion = data.Get("tls_min_version").(string)
if config.TLSMinVersion == "" {
return logical.ErrorResponse("failed to get 'tls_min_version' value"), nil
}
var ok bool
_, ok = tlsutil.TLSLookup[config.TLSMinVersion]
if !ok {
return logical.ErrorResponse("invalid 'tls_min_version'"), nil
}
if config.InsecureTLS {
config.TLS = true
}

View file

@ -8,6 +8,7 @@ import (
"github.com/gocql/gocql"
"github.com/hashicorp/vault/helper/certutil"
"github.com/hashicorp/vault/helper/tlsutil"
"github.com/hashicorp/vault/logical"
)
@ -48,10 +49,7 @@ func createSession(cfg *sessionConfig, s logical.Storage) (*gocql.Session, error
clusterConfig.Timeout = time.Duration(cfg.ConnectTimeout) * time.Second
if cfg.TLS {
tlsConfig := &tls.Config{
InsecureSkipVerify: cfg.InsecureTLS,
}
var tlsConfig *tls.Config
if len(cfg.Certificate) > 0 || len(cfg.IssuingCA) > 0 {
if len(cfg.Certificate) > 0 && len(cfg.PrivateKey) == 0 {
return nil, fmt.Errorf("Found certificate for TLS authentication but no private key")
@ -64,17 +62,29 @@ func createSession(cfg *sessionConfig, s logical.Storage) (*gocql.Session, error
}
if len(cfg.IssuingCA) > 0 {
certBundle.IssuingCA = cfg.IssuingCA
tlsConfig.InsecureSkipVerify = false
}
parsedCertBundle, err := certBundle.ToParsedCertBundle()
if err != nil {
return nil, fmt.Errorf("Error parsing certificate bundle: %s", err)
return nil, fmt.Errorf("failed to parse certificate bundle: %s", err)
}
tlsConfig, err = parsedCertBundle.GetTLSConfig(certutil.TLSClient)
if err != nil {
return nil, fmt.Errorf("Error getting TLS configuration: %s", err)
if err != nil || tlsConfig == nil {
return nil, fmt.Errorf("failed to get TLS configuration: tlsConfig:%#v err:%v", tlsConfig, err)
}
tlsConfig.InsecureSkipVerify = cfg.InsecureTLS
if cfg.TLSMinVersion != "" {
var ok bool
tlsConfig.MinVersion, ok = tlsutil.TLSLookup[cfg.TLSMinVersion]
if !ok {
return nil, fmt.Errorf("invalid 'tls_min_version' in config")
}
} else {
// MinVersion was not being set earlier. Reset it to
// zero to gracefully handle upgrades.
tlsConfig.MinVersion = 0
}
}

View file

@ -77,7 +77,7 @@ func (b *backend) pathRoleCreateRead(
if err != nil {
return nil, err
}
expiration := time.Now().UTC().
expiration := time.Now().
Add(lease.Lease).
Format("2006-01-02 15:04:05-0700")

View file

@ -345,7 +345,7 @@ func (p *Policy) Encrypt(context []byte, value string) (string, error) {
// Derive the key that should be used
key, err := p.DeriveKey(context, p.LatestVersion)
if err != nil {
return "", certutil.InternalError{Err: err.Error()}
return "", err
}
// Guard against a potentially invalid cipher-mode

View file

@ -10,6 +10,8 @@ import (
"net"
"strconv"
"sync"
"github.com/hashicorp/vault/helper/tlsutil"
)
// ListenerFactory is the factory function to create a listener.
@ -21,13 +23,6 @@ var BuiltinListeners = map[string]ListenerFactory{
"atlas": atlasListenerFactory,
}
// tlsLookup maps the tls_min_version configuration to the internal value
var tlsLookup = map[string]uint16{
"tls10": tls.VersionTLS10,
"tls11": tls.VersionTLS11,
"tls12": tls.VersionTLS12,
}
// NewListener creates a new listener of the given type with the given
// configuration. The type is looked up in the BuiltinListeners map.
func NewListener(t string, config map[string]string, logger io.Writer) (net.Listener, map[string]string, ReloadFunc, error) {
@ -81,7 +76,7 @@ func listenerWrapTLS(
tlsConf := &tls.Config{}
tlsConf.GetCertificate = cg.getCertificate
tlsConf.NextProtos = []string{"http/1.1"}
tlsConf.MinVersion, ok = tlsLookup[tlsvers]
tlsConf.MinVersion, ok = tlsutil.TLSLookup[tlsvers]
if !ok {
return nil, nil, nil, fmt.Errorf("'tls_min_version' value %s not supported, please specify one of [tls10,tls11,tls12]", tlsvers)
}

View file

@ -438,6 +438,7 @@ func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) {
tlsConfig := &tls.Config{
NextProtos: []string{"http/1.1"},
MinVersion: tls.VersionTLS12,
}
if p.Certificate != nil {

View file

@ -0,0 +1,28 @@
package duration
import (
"strconv"
"strings"
"time"
)
func ParseDurationSecond(inp string) (time.Duration, error) {
var err error
var dur time.Duration
// Look for a suffix otherwise its a plain second value
if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") {
dur, err = time.ParseDuration(inp)
if err != nil {
return dur, err
}
} else {
// Plain integer
secs, err := strconv.ParseInt(inp, 10, 64)
if err != nil {
return dur, err
}
dur = time.Duration(secs) * time.Second
}
return dur, nil
}

View file

@ -0,0 +1,23 @@
package duration
import (
"testing"
"time"
)
func Test_ParseDurationSecond(t *testing.T) {
outp, err := ParseDurationSecond("9876s")
if err != nil {
t.Fatal(err)
}
if outp != time.Duration(9876)*time.Second {
t.Fatal("not equivalent")
}
outp, err = ParseDurationSecond("9876")
if err != nil {
t.Fatal(err)
}
if outp != time.Duration(9876)*time.Second {
t.Fatal("not equivalent")
}
}

10
helper/tlsutil/tls.go Normal file
View file

@ -0,0 +1,10 @@
package tlsutil
import "crypto/tls"
// TLSLookup maps the tls_min_version configuration to the internal value
var TLSLookup = map[string]uint16{
"tls10": tls.VersionTLS10,
"tls11": tls.VersionTLS11,
"tls12": tls.VersionTLS12,
}

View file

@ -6,11 +6,10 @@ import (
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/helper/duration"
"github.com/hashicorp/vault/helper/jsonutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/vault"
@ -167,23 +166,14 @@ func requestWrapTTL(r *http.Request, req *logical.Request) (*logical.Request, er
}
// If it has an allowed suffix parse as a duration string
if strings.HasSuffix(wrapTTL, "s") || strings.HasSuffix(wrapTTL, "m") || strings.HasSuffix(wrapTTL, "h") {
dur, err := time.ParseDuration(wrapTTL)
if err != nil {
return req, err
}
req.WrapTTL = dur
} else {
// Parse as a straight number of seconds
seconds, err := strconv.ParseInt(wrapTTL, 10, 64)
if err != nil {
return req, err
}
req.WrapTTL = time.Duration(seconds) * time.Second
dur, err := duration.ParseDurationSecond(wrapTTL)
if err != nil {
return req, err
}
if int64(req.WrapTTL) < 0 {
if int64(dur) < 0 {
return req, fmt.Errorf("requested wrap ttl cannot be negative")
}
req.WrapTTL = dur
return req, nil
}

View file

@ -31,7 +31,7 @@ func TestSysHealth_get(t *testing.T) {
testResponseBody(t, resp, &actual)
expected["server_time_utc"] = actual["server_time_utc"]
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
}
core.Seal(root)
@ -51,7 +51,7 @@ func TestSysHealth_get(t *testing.T) {
testResponseBody(t, resp, &actual)
expected["server_time_utc"] = actual["server_time_utc"]
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
}
}
@ -80,7 +80,7 @@ func TestSysHealth_customcodes(t *testing.T) {
expected["server_time_utc"] = actual["server_time_utc"]
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
}
core.Seal(root)
@ -104,7 +104,7 @@ func TestSysHealth_customcodes(t *testing.T) {
testResponseBody(t, resp, &actual)
expected["server_time_utc"] = actual["server_time_utc"]
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
}
}
@ -113,7 +113,7 @@ func TestSysHealth_head(t *testing.T) {
ln, addr := TestServer(t, core)
defer ln.Close()
testData := []struct{
testData := []struct {
uri string
code int
}{

View file

@ -450,9 +450,9 @@ func (b *Backend) handleWALRollback(
if age == 0 {
age = 10 * time.Minute
}
minAge := time.Now().UTC().Add(-1 * age)
minAge := time.Now().Add(-1 * age)
if _, ok := req.Data["immediate"]; ok {
minAge = time.Now().UTC().Add(1000 * time.Hour)
minAge = time.Now().Add(1000 * time.Hour)
}
for _, k := range keys {

View file

@ -263,7 +263,7 @@ func TestBackendHandleRequest_renewExtend(t *testing.T) {
}
req := logical.RenewRequest("/foo", secret.Response(nil, nil).Secret, nil)
req.Secret.IssueTime = time.Now().UTC()
req.Secret.IssueTime = time.Now()
req.Secret.Increment = 1 * time.Hour
resp, err := b.HandleRequest(req)
if err != nil {

View file

@ -3,10 +3,8 @@ package framework
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/hashicorp/vault/helper/duration"
"github.com/mitchellh/mapstructure"
)
@ -163,21 +161,11 @@ func (d *FieldData) getPrimitive(
case float64:
result = int(inp)
case string:
// Look for a suffix otherwise its a plain second value
if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") {
dur, err := time.ParseDuration(inp)
if err != nil {
return nil, true, err
}
result = int(dur.Seconds())
} else {
// Plain integer
val, err := strconv.ParseInt(inp, 10, 64)
if err != nil {
return nil, true, err
}
result = int(val)
dur, err := duration.ParseDurationSecond(inp)
if err != nil {
return nil, true, err
}
result = int(dur.Seconds())
case json.Number:
valInt64, err := inp.Int64()
if err != nil {

View file

@ -45,10 +45,10 @@ func LeaseExtend(backendIncrement, backendMax time.Duration, systemView logical.
}
// We cannot go past this time
maxValidTime := leaseOpts.IssueTime.UTC().Add(max)
maxValidTime := leaseOpts.IssueTime.Add(max)
// Get the current time
now := time.Now().UTC()
now := time.Now()
// If we are past the max TTL, we shouldn't be in this function...but
// fast path out if we are

View file

@ -14,7 +14,7 @@ func TestLeaseExtend(t *testing.T) {
MaxLeaseTTLVal: 30 * time.Hour,
}
now := time.Now().UTC().Round(time.Hour)
now := time.Now().Round(time.Hour)
cases := map[string]struct {
BackendDefault time.Duration

View file

@ -5,6 +5,7 @@ import (
"strings"
"time"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/helper/jsonutil"
"github.com/hashicorp/vault/logical"
)
@ -44,7 +45,7 @@ func PutWAL(s logical.Storage, kind string, data interface{}) (string, error) {
return "", err
}
id, err := logical.UUID()
id, err := uuid.GenerateUUID()
if err != nil {
return "", err
}

View file

@ -20,7 +20,7 @@ type LeaseOptions struct {
// IssueTime is the time of issue for the original lease. This is
// only available on a Renew operation and has no effect when returning
// a response. It can be used to enforce maximum lease periods by
// a logical backend. This time will always be in UTC.
// a logical backend.
IssueTime time.Time `json:"-"`
}
@ -42,7 +42,7 @@ func (l *LeaseOptions) LeaseTotal() time.Duration {
func (l *LeaseOptions) ExpirationTime() time.Time {
var expireTime time.Time
if l.LeaseEnabled() {
expireTime = time.Now().UTC().Add(l.LeaseTotal())
expireTime = time.Now().Add(l.LeaseTotal())
}
return expireTime
}

View file

@ -41,7 +41,7 @@ func TestLeaseOptionsExpirationTime(t *testing.T) {
var l LeaseOptions
l.TTL = 1 * time.Hour
limit := time.Now().UTC().Add(time.Hour)
limit := time.Now().Add(time.Hour)
exp := l.ExpirationTime()
if exp.Before(limit) {
t.Fatalf("bad: %s", exp)

View file

@ -108,11 +108,11 @@ type TestTeardownFunc func() error
// the "-test.v" flag) is set. Because some acceptance tests take quite
// long, we require the verbose flag so users are able to see progress
// output.
func Test(t TestT, c TestCase) {
func Test(tt TestT, c TestCase) {
// We only run acceptance tests if an env var is set because they're
// slow and generally require some outside configuration.
if c.AcceptanceTest && os.Getenv(TestEnvVar) == "" {
t.Skip(fmt.Sprintf(
tt.Skip(fmt.Sprintf(
"Acceptance tests skipped unless env '%s' set",
TestEnvVar))
return
@ -120,7 +120,7 @@ func Test(t TestT, c TestCase) {
// We require verbose mode so that the user knows what is going on.
if c.AcceptanceTest && !testTesting && !testing.Verbose() {
t.Fatal("Acceptance tests must be run with the -v flag on tests")
tt.Fatal("Acceptance tests must be run with the -v flag on tests")
return
}
@ -131,7 +131,8 @@ func Test(t TestT, c TestCase) {
// Check that something is provided
if c.Backend == nil && c.Factory == nil {
t.Fatal("Must provide either Backend or Factory")
tt.Fatal("Must provide either Backend or Factory")
return
}
// Create an in-memory Vault core
@ -148,7 +149,7 @@ func Test(t TestT, c TestCase) {
DisableMlock: true,
})
if err != nil {
t.Fatal("error initializing core: ", err)
tt.Fatal("error initializing core: ", err)
return
}
@ -158,15 +159,16 @@ func Test(t TestT, c TestCase) {
SecretThreshold: 1,
}, nil)
if err != nil {
t.Fatal("error initializing core: ", err)
tt.Fatal("error initializing core: ", err)
return
}
// Unseal the core
if unsealed, err := core.Unseal(init.SecretShares[0]); err != nil {
t.Fatal("error unsealing core: ", err)
tt.Fatal("error unsealing core: ", err)
return
} else if !unsealed {
t.Fatal("vault shouldn't be sealed")
tt.Fatal("vault shouldn't be sealed")
return
}
@ -177,7 +179,7 @@ func Test(t TestT, c TestCase) {
clientConfig.Address = addr
client, err := api.NewClient(clientConfig)
if err != nil {
t.Fatal("error initializing HTTP client: ", err)
tt.Fatal("error initializing HTTP client: ", err)
return
}
@ -191,7 +193,7 @@ func Test(t TestT, c TestCase) {
Description: "acceptance test",
}
if err := client.Sys().Mount(prefix, mountInfo); err != nil {
t.Fatal("error mounting backend: ", err)
tt.Fatal("error mounting backend: ", err)
return
}
@ -220,7 +222,7 @@ func Test(t TestT, c TestCase) {
ct := req.ClientToken
req.ClientToken = ""
if err := s.PreFlight(req); err != nil {
t.Error(fmt.Sprintf("Failed preflight for step %d: %s", i+1, err))
tt.Error(fmt.Sprintf("Failed preflight for step %d: %s", i+1, err))
break
}
req.ClientToken = ct
@ -249,7 +251,7 @@ func Test(t TestT, c TestCase) {
err = nil
} else {
// If the error is not expected, fail right away.
t.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
tt.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
break
}
}
@ -272,7 +274,7 @@ func Test(t TestT, c TestCase) {
}
if err != nil {
t.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
tt.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
break
}
}
@ -288,7 +290,7 @@ func Test(t TestT, c TestCase) {
}
if err != nil {
failedRevokes = append(failedRevokes, req.Secret)
t.Error(fmt.Sprintf("[ERR] Revoke error: %s", err))
tt.Error(fmt.Sprintf("[ERR] Revoke error: %s", err))
}
}
@ -305,14 +307,14 @@ func Test(t TestT, c TestCase) {
}
if err != nil {
if !errwrap.Contains(err, logical.ErrUnsupportedOperation.Error()) {
t.Error(fmt.Sprintf("[ERR] Rollback error: %s", err))
tt.Error(fmt.Sprintf("[ERR] Rollback error: %s", err))
}
}
// If we have any failed revokes, log it.
if len(failedRevokes) > 0 {
for _, s := range failedRevokes {
t.Error(fmt.Sprintf(
tt.Error(fmt.Sprintf(
"WARNING: Revoking the following secret failed. It may\n"+
"still exist. Please verify:\n\n%#v",
s))

View file

@ -1,21 +0,0 @@
package logical
import (
"crypto/rand"
"fmt"
"time"
)
// UUID returns a UUID.
func UUID() (string, error) {
unix := uint32(time.Now().UTC().Unix())
var b [12]byte
if _, err := rand.Read(b[:]); err != nil {
return "", err
}
return fmt.Sprintf("%08x-%04x-%04x-%04x-%04x%08x",
unix, b[0:2], b[2:4], b[4:6], b[6:8], b[8:]),
nil
}

View file

@ -20,6 +20,7 @@ import (
"github.com/hashicorp/consul/lib"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/helper/tlsutil"
)
const (
@ -190,7 +191,19 @@ func setupTLSConfig(conf map[string]string) (*tls.Config, error) {
insecureSkipVerify = true
}
tlsMinVersionStr, ok := conf["tls_min_version"]
if !ok {
// Set the default value
tlsMinVersionStr = "tls12"
}
tlsMinVersion, ok := tlsutil.TLSLookup[tlsMinVersionStr]
if !ok {
return nil, fmt.Errorf("invalid 'tls_min_version'")
}
tlsClientConfig := &tls.Config{
MinVersion: tlsMinVersion,
InsecureSkipVerify: insecureSkipVerify,
ServerName: serverName[0],
}

View file

@ -142,7 +142,7 @@ func (m *ExpirationManager) Restore() error {
}
// Determine the remaining time to expiration
expires := le.ExpireTime.Sub(time.Now().UTC())
expires := le.ExpireTime.Sub(time.Now())
if expires <= 0 {
expires = minRevokeDelay
}
@ -335,7 +335,7 @@ func (m *ExpirationManager) Renew(leaseID string, increment time.Duration) (*log
le.Data = resp.Data
le.Secret = resp.Secret
le.ExpireTime = resp.Secret.ExpirationTime()
le.LastRenewalTime = time.Now().UTC()
le.LastRenewalTime = time.Now()
if err := m.persistEntry(le); err != nil {
return nil, err
}
@ -364,7 +364,7 @@ func (m *ExpirationManager) RenewToken(req *logical.Request, source string, toke
// Check if the lease is renewable. Note that this also checks for a nil
// lease and errors in that case as well.
if err := le.renewable(); err != nil {
return nil, err
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
// Attempt to renew the auth entry
@ -396,7 +396,7 @@ func (m *ExpirationManager) RenewToken(req *logical.Request, source string, toke
// Update the lease entry
le.Auth = resp.Auth
le.ExpireTime = resp.Auth.ExpirationTime()
le.LastRenewalTime = time.Now().UTC()
le.LastRenewalTime = time.Now()
if err := m.persistEntry(le); err != nil {
return nil, err
}
@ -434,7 +434,7 @@ func (m *ExpirationManager) Register(req *logical.Request, resp *logical.Respons
Path: req.Path,
Data: resp.Data,
Secret: resp.Secret,
IssueTime: time.Now().UTC(),
IssueTime: time.Now(),
ExpireTime: resp.Secret.ExpirationTime(),
}
@ -467,7 +467,7 @@ func (m *ExpirationManager) RegisterAuth(source string, auth *logical.Auth) erro
ClientToken: auth.ClientToken,
Auth: auth,
Path: source,
IssueTime: time.Now().UTC(),
IssueTime: time.Now(),
ExpireTime: auth.ExpirationTime(),
}
@ -763,7 +763,7 @@ func (le *leaseEntry) renewable() error {
}
// Determine if the lease is expired
if le.ExpireTime.Before(time.Now().UTC()) {
if le.ExpireTime.Before(time.Now()) {
return fmt.Errorf("lease expired")
}

View file

@ -158,9 +158,12 @@ func TestExpiration_RegisterAuth_NoLease(t *testing.T) {
}
// Should not be able to renew, no expiration
_, err = exp.RenewToken(&logical.Request{}, "auth/github/login", root.ID, 0)
if err.Error() != "lease not found or lease is not renewable" {
t.Fatalf("err: %v", err)
resp, err := exp.RenewToken(&logical.Request{}, "auth/github/login", root.ID, 0)
if err != nil && (err != logical.ErrInvalidRequest || (resp != nil && resp.IsError() && resp.Error().Error() != "lease not found or lease is not renewable")) {
t.Fatalf("bad: err:%v resp:%#v", err, resp)
}
if resp == nil {
t.Fatal("expected a response")
}
// Wait and check token is not invalidated
@ -455,10 +458,14 @@ func TestExpiration_RenewToken_NotRenewable(t *testing.T) {
}
// Attempt to renew the token
_, err = exp.RenewToken(&logical.Request{}, "auth/github/login", root.ID, 0)
if err.Error() != "lease is not renewable" {
t.Fatalf("err: %v", err)
resp, err := exp.RenewToken(&logical.Request{}, "auth/github/login", root.ID, 0)
if err != nil && (err != logical.ErrInvalidRequest || (resp != nil && resp.IsError() && resp.Error().Error() != "lease is not renewable")) {
t.Fatalf("bad: err:%v resp:%#v", err, resp)
}
if resp == nil {
t.Fatal("expected a response")
}
}
func TestExpiration_Renew(t *testing.T) {
@ -899,9 +906,9 @@ func TestExpiration_PersistLoadDelete(t *testing.T) {
TTL: time.Minute,
},
},
IssueTime: time.Now().UTC(),
ExpireTime: time.Now().UTC(),
LastRenewalTime: time.Time{}.UTC(),
IssueTime: time.Now(),
ExpireTime: time.Now(),
LastRenewalTime: time.Time{},
}
if err := exp.persistEntry(le); err != nil {
t.Fatalf("err: %v", err)
@ -911,8 +918,9 @@ func TestExpiration_PersistLoadDelete(t *testing.T) {
if err != nil {
t.Fatalf("err: %v", err)
}
le.LastRenewalTime = out.LastRenewalTime
if !reflect.DeepEqual(out, le) {
t.Fatalf("\nout: %#v\nexpect: %#v\n", out, le)
t.Fatalf("bad: expected:%#v\nactual:%#v", le, out)
}
err = exp.deleteEntry("foo/bar/1234")
@ -941,8 +949,8 @@ func TestLeaseEntry(t *testing.T) {
TTL: time.Minute,
},
},
IssueTime: time.Now().UTC(),
ExpireTime: time.Now().UTC(),
IssueTime: time.Now(),
ExpireTime: time.Now(),
}
enc, err := le.encode()

View file

@ -140,8 +140,8 @@ func TestKeyring_Serialize(t *testing.T) {
testKey := []byte("testing")
testSecond := []byte("second")
k, _ = k.AddKey(&Key{Term: 1, Version: 1, Value: testKey, InstallTime: time.Now().UTC()})
k, _ = k.AddKey(&Key{Term: 2, Version: 1, Value: testSecond, InstallTime: time.Now().UTC()})
k, _ = k.AddKey(&Key{Term: 1, Version: 1, Value: testKey, InstallTime: time.Now()})
k, _ = k.AddKey(&Key{Term: 2, Version: 1, Value: testSecond, InstallTime: time.Now()})
buf, err := k.Serialize()
if err != nil {
@ -177,7 +177,7 @@ func TestKey_Serialize(t *testing.T) {
Term: 10,
Version: 1,
Value: []byte("foobarbaz"),
InstallTime: time.Now().UTC(),
InstallTime: time.Now(),
}
buf, err := k.Serialize()

View file

@ -3,10 +3,9 @@ package vault
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/hashicorp/vault/helper/duration"
"github.com/hashicorp/vault/helper/jsonutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
@ -134,19 +133,9 @@ func (b *PassthroughBackend) handleRead(
}
ttlDuration := b.System().DefaultLeaseTTL()
if len(ttl) != 0 {
// Parse as a duration string if it has an appropriate suffix
if strings.HasSuffix(ttl, "s") || strings.HasSuffix(ttl, "m") || strings.HasSuffix(ttl, "h") {
dur, err := time.ParseDuration(ttl)
if err == nil {
ttlDuration = dur
}
} else {
// Parse as a straight number of seconds
seconds, err := strconv.ParseInt(ttl, 10, 64)
if err == nil {
ttlDuration = time.Duration(seconds) * time.Second
}
dur, err := duration.ParseDurationSecond(ttl)
if err == nil {
ttlDuration = dur
}
if b.generateLeases {

View file

@ -6,6 +6,7 @@ import (
"sync"
"time"
"github.com/hashicorp/vault/helper/duration"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
"github.com/mitchellh/mapstructure"
@ -702,7 +703,7 @@ func (b *SystemBackend) handleMount(
case "":
case "system":
default:
tmpDef, err := time.ParseDuration(apiConfig.DefaultLeaseTTL)
tmpDef, err := duration.ParseDurationSecond(apiConfig.DefaultLeaseTTL)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf(
"unable to parse default TTL of %s: %s", apiConfig.DefaultLeaseTTL, err)),
@ -715,7 +716,7 @@ func (b *SystemBackend) handleMount(
case "":
case "system":
default:
tmpMax, err := time.ParseDuration(apiConfig.MaxLeaseTTL)
tmpMax, err := duration.ParseDurationSecond(apiConfig.MaxLeaseTTL)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf(
"unable to parse max TTL of %s: %s", apiConfig.MaxLeaseTTL, err)),
@ -927,7 +928,7 @@ func (b *SystemBackend) handleTuneWriteCommon(
tmpDef := time.Duration(0)
newDefault = &tmpDef
default:
tmpDef, err := time.ParseDuration(defTTL)
tmpDef, err := duration.ParseDurationSecond(defTTL)
if err != nil {
return handleError(err)
}
@ -941,7 +942,7 @@ func (b *SystemBackend) handleTuneWriteCommon(
tmpMax := time.Duration(0)
newMax = &tmpMax
default:
tmpMax, err := time.ParseDuration(maxTTL)
tmpMax, err := duration.ParseDurationSecond(maxTTL)
if err != nil {
return handleError(err)
}

View file

@ -415,18 +415,41 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error)
// TokenEntry is used to represent a given token
type TokenEntry struct {
ID string // ID of this entry, generally a random UUID
Accessor string // Accessor for this token, a random UUID
Parent string // Parent token, used for revocation trees
Policies []string // Which named policies should be used
Path string // Used for audit trails, this is something like "auth/user/login"
Meta map[string]string // Used for auditing. This could include things like "source", "user", "ip"
DisplayName string // Used for operators to be able to associate with the source
NumUses int // Used to restrict the number of uses (zero is unlimited). This is to support one-time-tokens (generalized).
CreationTime int64 // Time of token creation
TTL time.Duration // Duration set when token was created
ExplicitMaxTTL time.Duration // Explicit maximum TTL on the token
Role string // If set, the role that was used for parameters at creation time
// ID of this entry, generally a random UUID
ID string `json:"id" mapstructure:"id" structs:"id"`
// Accessor for this token, a random UUID
Accessor string `json:"accessor" mapstructure:"accessor" structs:"accessor"`
// Parent token, used for revocation trees
Parent string `json:"parent" mapstructure:"parent" structs:"parent"`
// Which named policies should be used
Policies []string `json:"policies" mapstructure:"policies" structs:"policies"`
// Used for audit trails, this is something like "auth/user/login"
Path string `json:"path" mapstructure:"path" structs:"path"`
// Used for auditing. This could include things like "source", "user", "ip"
Meta map[string]string `json:"meta" mapstructure:"meta" structs:"meta"`
// Used for operators to be able to associate with the source
DisplayName string `json:"display_name" mapstructure:"display_name" structs:"display_name"`
// Used to restrict the number of uses (zero is unlimited). This is to support one-time-tokens (generalized).
NumUses int `json:"num_uses" mapstructure:"num_uses" structs:"num_uses"`
// Time of token creation
CreationTime int64 `json:"creation_time" mapstructure:"creation_time" structs:"creation_time"`
// Duration set when token was created
TTL time.Duration `json:"ttl" mapstructure:"ttl" structs:"ttl"`
// Explicit maximum TTL on the token
ExplicitMaxTTL time.Duration `json:"" mapstructure:"" structs:""`
// If set, the role that was used for parameters at creation time
Role string `json:"role" mapstructure:"role" structs:"role"`
}
// tsRoleEntry contains token store role information

View file

@ -156,7 +156,7 @@ func TestTokenStore_RootToken(t *testing.T) {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, te) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", te, out)
}
}
@ -176,7 +176,7 @@ func TestTokenStore_CreateLookup(t *testing.T) {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, ent) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", ent, out)
}
// New store should share the salt
@ -191,7 +191,7 @@ func TestTokenStore_CreateLookup(t *testing.T) {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, ent) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", ent, out)
}
}
@ -207,7 +207,7 @@ func TestTokenStore_CreateLookup_ProvidedID(t *testing.T) {
t.Fatalf("err: %v", err)
}
if ent.ID != "foobarbaz" {
t.Fatalf("bad: %#v", ent)
t.Fatalf("bad: ent.ID: expected:\"foobarbaz\"\n actual:%s", ent.ID)
}
out, err := ts.Lookup(ent.ID)
@ -215,7 +215,7 @@ func TestTokenStore_CreateLookup_ProvidedID(t *testing.T) {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, ent) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", ent, out)
}
// New store should share the salt
@ -230,7 +230,7 @@ func TestTokenStore_CreateLookup_ProvidedID(t *testing.T) {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, ent) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", ent, out)
}
}
@ -259,7 +259,7 @@ func TestTokenStore_UseToken(t *testing.T) {
}
if !reflect.DeepEqual(ent, ent2) {
t.Fatalf("bad: %#v %#v", ent, ent2)
t.Fatalf("bad: ent:%#v ent2:%#v", ent, ent2)
}
// Create a retstricted token
@ -412,7 +412,7 @@ func TestTokenStore_Revoke_Orphan(t *testing.T) {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(out, ent2) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", ent2, out)
}
}
@ -530,7 +530,7 @@ func TestTokenStore_HandleRequest_CreateToken_DisplayName(t *testing.T) {
}
expected.CreationTime = out.CreationTime
if !reflect.DeepEqual(out, expected) {
t.Fatalf("bad:\ngot:\n%#v\nexpected:\n%#v\n", out, expected)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, out)
}
}
@ -562,7 +562,7 @@ func TestTokenStore_HandleRequest_CreateToken_NumUses(t *testing.T) {
}
expected.CreationTime = out.CreationTime
if !reflect.DeepEqual(out, expected) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, out)
}
}
@ -625,7 +625,7 @@ func TestTokenStore_HandleRequest_CreateToken_NoPolicy(t *testing.T) {
}
expected.CreationTime = out.CreationTime
if !reflect.DeepEqual(out, expected) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, out)
}
}
@ -812,7 +812,7 @@ func TestTokenStore_HandleRequest_CreateToken_Metadata(t *testing.T) {
out, _ := ts.Lookup(resp.Auth.ClientToken)
if !reflect.DeepEqual(out.Meta, meta) {
t.Fatalf("bad: %#v", out)
t.Fatalf("bad: expected:%#v\nactual:%#v", meta, out.Meta)
}
}
@ -988,7 +988,7 @@ func TestTokenStore_HandleRequest_Lookup(t *testing.T) {
delete(resp.Data, "creation_time")
if !reflect.DeepEqual(resp.Data, exp) {
t.Fatalf("bad:\n%#v\nexp:\n%#v\n", resp.Data, exp)
t.Fatalf("bad: expected:%#v\nactual:%#v", exp, resp.Data)
}
testCoreMakeToken(t, c, root, "client", "3600s", []string{"foo"})
@ -1030,7 +1030,7 @@ func TestTokenStore_HandleRequest_Lookup(t *testing.T) {
}
if !reflect.DeepEqual(resp.Data, exp) {
t.Fatalf("bad:\n%#v\nexp:\n%#v\n", resp.Data, exp)
t.Fatalf("bad: expected:%#v\nactual:%#v", exp, resp.Data)
}
// Test via POST
@ -1073,7 +1073,7 @@ func TestTokenStore_HandleRequest_Lookup(t *testing.T) {
}
if !reflect.DeepEqual(resp.Data, exp) {
t.Fatalf("bad:\n%#v\nexp:\n%#v\n", resp.Data, exp)
t.Fatalf("bad: expected:%#v\nactual:%#v", exp, resp.Data)
}
// Test last_renewal_time functionality
@ -1133,7 +1133,7 @@ func TestTokenStore_HandleRequest_LookupSelf(t *testing.T) {
delete(resp.Data, "creation_time")
if !reflect.DeepEqual(resp.Data, exp) {
t.Fatalf("bad:\ngot %#v\nexpected: %#v\n", resp.Data, exp)
t.Fatalf("bad: expected:%#v\nactual:%#v", exp, resp.Data)
}
}
@ -1163,7 +1163,7 @@ func TestTokenStore_HandleRequest_Renew(t *testing.T) {
// Get the original expire time to compare
originalExpire := auth.ExpirationTime()
beforeRenew := time.Now().UTC()
beforeRenew := time.Now()
req := logical.TestRequest(t, logical.UpdateOperation, "renew/"+root.ID)
req.Data["increment"] = "3600s"
resp, err := ts.HandleRequest(req)
@ -1207,7 +1207,7 @@ func TestTokenStore_HandleRequest_RenewSelf(t *testing.T) {
// Get the original expire time to compare
originalExpire := auth.ExpirationTime()
beforeRenew := time.Now().UTC()
beforeRenew := time.Now()
req := logical.TestRequest(t, logical.UpdateOperation, "renew-self")
req.ClientToken = auth.ClientToken
req.Data["increment"] = "3600s"
@ -1279,7 +1279,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
if !reflect.DeepEqual(expected, resp.Data) {
t.Fatalf("expected:\n%v\nactual:\n%v\n", expected, resp.Data)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, resp.Data)
}
// Now test updating; this should be set to an UpdateOperation
@ -1322,7 +1322,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
if !reflect.DeepEqual(expected, resp.Data) {
t.Fatalf("expected:\n%v\nactual:\n%v\n", expected, resp.Data)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, resp.Data)
}
// Now test setting explicit max ttl at the same time as period, which
@ -1370,7 +1370,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
}
if !reflect.DeepEqual(expected, resp.Data) {
t.Fatalf("expected:\n%v\nactual:\n%v\n", expected, resp.Data)
t.Fatalf("bad: expected:%#v\nactual:%#v", expected, resp.Data)
}
req.Operation = logical.ListOperation

363
vendor/github.com/hashicorp/go-retryablehttp/LICENSE generated vendored Normal file
View file

@ -0,0 +1,363 @@
Mozilla Public License, version 2.0
1. Definitions
1.1. "Contributor"
means each individual or legal entity that creates, contributes to the
creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used by a
Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached the
notice in Exhibit A, the Executable Form of such Source Code Form, and
Modifications of such Source Code Form, in each case including portions
thereof.
1.5. "Incompatible With Secondary Licenses"
means
a. that the initial Contributor has attached the notice described in
Exhibit B to the Covered Software; or
b. that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the terms of
a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in a
separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible, whether
at the time of the initial grant or subsequently, any and all of the
rights conveyed by this License.
1.10. "Modifications"
means any of the following:
a. any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered Software; or
b. any new file in Source Code Form that contains any Covered Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the License,
by the making, using, selling, offering for sale, having made, import,
or transfer of either its Contributions or its Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU Lesser
General Public License, Version 2.1, the GNU Affero General Public
License, Version 3.0, or any later versions of those licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that controls, is
controlled by, or is under common control with You. For purposes of this
definition, "control" means (a) the power, direct or indirect, to cause
the direction or management of such entity, whether by contract or
otherwise, or (b) ownership of more than fifty percent (50%) of the
outstanding shares or beneficial ownership of such entity.
2. License Grants and Conditions
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
a. under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
b. under Patent Claims of such Contributor to make, use, sell, offer for
sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
a. for any code that a Contributor has removed from Covered Software; or
b. for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
c. under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights to
grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
Section 2.1.
3. Responsibilities
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
a. such Covered Software must also be made available in Source Code Form,
as described in Section 3.1, and You must inform recipients of the
Executable Form how they can obtain a copy of such Source Code Form by
reasonable means in a timely manner, at a charge no more than the cost
of distribution to the recipient; and
b. You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter the
recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty, or
limitations of liability) contained within the Source Code Form of the
Covered Software, except that You may alter any license notices to the
extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
If it is impossible for You to comply with any of the terms of this License
with respect to some or all of the Covered Software due to statute,
judicial order, or regulation then You must: (a) comply with the terms of
this License to the maximum extent possible; and (b) describe the
limitations and the code they affect. Such description must be placed in a
text file included with all distributions of the Covered Software under
this License. Except to the extent prohibited by statute or regulation,
such description must be sufficiently detailed for a recipient of ordinary
skill to be able to understand it.
5. Termination
5.1. The rights granted under this License will terminate automatically if You
fail to comply with any of its terms. However, if You become compliant,
then the rights granted under this License from a particular Contributor
are reinstated (a) provisionally, unless and until such Contributor
explicitly and finally terminates Your grants, and (b) on an ongoing
basis, if such Contributor fails to notify You of the non-compliance by
some reasonable means prior to 60 days after You have come back into
compliance. Moreover, Your grants from a particular Contributor are
reinstated on an ongoing basis if such Contributor notifies You of the
non-compliance by some reasonable means, this is the first time You have
received notice of non-compliance with this License from such
Contributor, and You become compliant prior to 30 days after Your receipt
of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
license agreements (excluding distributors and resellers) which have been
validly granted by You or Your distributors under this License prior to
termination shall survive termination.
6. Disclaimer of Warranty
Covered Software is provided under this License on an "as is" basis,
without warranty of any kind, either expressed, implied, or statutory,
including, without limitation, warranties that the Covered Software is free
of defects, merchantable, fit for a particular purpose or non-infringing.
The entire risk as to the quality and performance of the Covered Software
is with You. Should any Covered Software prove defective in any respect,
You (not any Contributor) assume the cost of any necessary servicing,
repair, or correction. This disclaimer of warranty constitutes an essential
part of this License. No use of any Covered Software is authorized under
this License except under this disclaimer.
7. Limitation of Liability
Under no circumstances and under no legal theory, whether tort (including
negligence), contract, or otherwise, shall any Contributor, or anyone who
distributes Covered Software as permitted above, be liable to You for any
direct, indirect, special, incidental, or consequential damages of any
character including, without limitation, damages for lost profits, loss of
goodwill, work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses, even if such party shall have been
informed of the possibility of such damages. This limitation of liability
shall not apply to liability for death or personal injury resulting from
such party's negligence to the extent applicable law prohibits such
limitation. Some jurisdictions do not allow the exclusion or limitation of
incidental or consequential damages, so this exclusion and limitation may
not apply to You.
8. Litigation
Any litigation relating to this License may be brought only in the courts
of a jurisdiction where the defendant maintains its principal place of
business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions. Nothing
in this Section shall prevent a party's ability to bring cross-claims or
counter-claims.
9. Miscellaneous
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides that
the language of a contract shall be construed against the drafter shall not
be used to construe this License against a Contributor.
10. Versions of the License
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses If You choose to distribute Source Code Form that is
Incompatible With Secondary Licenses under the terms of this version of
the License, the notice described in Exhibit B of this License must be
attached.
Exhibit A - Source Code Form License Notice
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file,
then You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a
notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
This Source Code Form is "Incompatible
With Secondary Licenses", as defined by
the Mozilla Public License, v. 2.0.

11
vendor/github.com/hashicorp/go-retryablehttp/Makefile generated vendored Normal file
View file

@ -0,0 +1,11 @@
default: test
test:
go vet ./...
go test -race ./...
updatedeps:
go get -f -t -u ./...
go get -f -u ./...
.PHONY: default test updatedeps

43
vendor/github.com/hashicorp/go-retryablehttp/README.md generated vendored Normal file
View file

@ -0,0 +1,43 @@
go-retryablehttp
================
[![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis]
[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]
[travis]: http://travis-ci.org/hashicorp/go-retryablehttp
[godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp
The `retryablehttp` package provides a familiar HTTP client interface with
automatic retries and exponential backoff. It is a thin wrapper over the
standard `net/http` client library and exposes nearly the same public API. This
makes `retryablehttp` very easy to drop into existing programs.
`retryablehttp` performs automatic retries under certain conditions. Mainly, if
an error is returned by the client (connection errors, etc.), or if a 500-range
response code is received, then a retry is invoked after a wait period.
Otherwise, the response is returned and left to the caller to interpret.
The main difference from `net/http` is that requests which take a request body
(POST/PUT et. al) require an `io.ReadSeeker` to be provided. This enables the
request body to be "rewound" if the initial request fails so that the full
request can be attempted again.
Example Use
===========
Using this library should look almost identical to what you would do with
`net/http`. The most simple example of a GET request is shown below:
```go
resp, err := retryablehttp.Get("/foo")
if err != nil {
panic(err)
}
```
The returned response object is an `*http.Response`, the same thing you would
usually get from `net/http`. Had the request failed one or more times, the above
call would block and retry with exponential backoff.
For more usage and examples see the
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp).

234
vendor/github.com/hashicorp/go-retryablehttp/client.go generated vendored Normal file
View file

@ -0,0 +1,234 @@
// The retryablehttp package provides a familiar HTTP client interface with
// automatic retries and exponential backoff. It is a thin wrapper over the
// standard net/http client library and exposes nearly the same public API.
// This makes retryablehttp very easy to drop into existing programs.
//
// retryablehttp performs automatic retries under certain conditions. Mainly, if
// an error is returned by the client (connection errors etc), or if a 500-range
// response is received, then a retry is invoked. Otherwise, the response is
// returned and left to the caller to interpret.
//
// The main difference from net/http is that requests which take a request body
// (POST/PUT et. al) require an io.ReadSeeker to be provided. This enables the
// request body to be "rewound" if the initial request fails so that the full
// request can be attempted again.
package retryablehttp
import (
"fmt"
"io"
"io/ioutil"
"log"
"math"
"net/http"
"net/url"
"os"
"strings"
"time"
"github.com/hashicorp/go-cleanhttp"
)
var (
// Default retry configuration
defaultRetryWaitMin = 1 * time.Second
defaultRetryWaitMax = 5 * time.Minute
defaultRetryMax = 32
// defaultClient is used for performing requests without explicitly making
// a new client. It is purposely private to avoid modifications.
defaultClient = NewClient()
)
// LenReader is an interface implemented by many in-memory io.Reader's. Used
// for automatically sending the right Content-Length header when possible.
type LenReader interface {
Len() int
}
// Request wraps the metadata needed to create HTTP requests.
type Request struct {
// body is a seekable reader over the request body payload. This is
// used to rewind the request data in between retries.
body io.ReadSeeker
// Embed an HTTP request directly. This makes a *Request act exactly
// like an *http.Request so that all meta methods are supported.
*http.Request
}
// NewRequest creates a new wrapped request.
func NewRequest(method, url string, body io.ReadSeeker) (*Request, error) {
// Wrap the body in a noop ReadCloser if non-nil. This prevents the
// reader from being closed by the HTTP client.
var rcBody io.ReadCloser
if body != nil {
rcBody = ioutil.NopCloser(body)
}
// Make the request with the noop-closer for the body.
httpReq, err := http.NewRequest(method, url, rcBody)
if err != nil {
return nil, err
}
// Check if we can set the Content-Length automatically.
if lr, ok := body.(LenReader); ok {
httpReq.ContentLength = int64(lr.Len())
}
return &Request{body, httpReq}, nil
}
// RequestLogHook allows a function to run before each retry. The HTTP
// request which will be made, and the retry number (0 for the initial
// request) are available to users. The internal logger is exposed to
// consumers.
type RequestLogHook func(*log.Logger, *http.Request, int)
// Client is used to make HTTP requests. It adds additional functionality
// like automatic retries to tolerate minor outages.
type Client struct {
HTTPClient *http.Client // Internal HTTP client.
Logger *log.Logger // Customer logger instance.
RetryWaitMin time.Duration // Minimum time to wait
RetryWaitMax time.Duration // Maximum time to wait
RetryMax int // Maximum number of retries
// RequestLogHook allows a user-supplied function to be called
// before each retry.
RequestLogHook RequestLogHook
}
// NewClient creates a new Client with default settings.
func NewClient() *Client {
return &Client{
HTTPClient: cleanhttp.DefaultClient(),
Logger: log.New(os.Stderr, "", log.LstdFlags),
RetryWaitMin: defaultRetryWaitMin,
RetryWaitMax: defaultRetryWaitMax,
RetryMax: defaultRetryMax,
}
}
// Do wraps calling an HTTP method with retries.
func (c *Client) Do(req *Request) (*http.Response, error) {
c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL)
for i := 0; ; i++ {
var code int // HTTP response code
// Always rewind the request body when non-nil.
if req.body != nil {
if _, err := req.body.Seek(0, 0); err != nil {
return nil, fmt.Errorf("failed to seek body: %v", err)
}
}
if c.RequestLogHook != nil {
c.RequestLogHook(c.Logger, req.Request, i)
}
// Attempt the request
resp, err := c.HTTPClient.Do(req.Request)
if err != nil {
c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err)
goto RETRY
}
code = resp.StatusCode
// Check the response code. We retry on 500-range responses to allow
// the server time to recover, as 500's are typically not permanent
// errors and may relate to outages on the server side.
if code%500 < 100 {
resp.Body.Close()
goto RETRY
}
return resp, nil
RETRY:
remain := c.RetryMax - i
if remain == 0 {
break
}
wait := backoff(c.RetryWaitMin, c.RetryWaitMax, i)
desc := fmt.Sprintf("%s %s", req.Method, req.URL)
if code > 0 {
desc = fmt.Sprintf("%s (status: %d)", desc, code)
}
c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain)
time.Sleep(wait)
}
// Return an error if we fall out of the retry loop
return nil, fmt.Errorf("%s %s giving up after %d attempts",
req.Method, req.URL, c.RetryMax+1)
}
// Get is a shortcut for doing a GET request without making a new client.
func Get(url string) (*http.Response, error) {
return defaultClient.Get(url)
}
// Get is a convenience helper for doing simple GET requests.
func (c *Client) Get(url string) (*http.Response, error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
// Head is a shortcut for doing a HEAD request without making a new client.
func Head(url string) (*http.Response, error) {
return defaultClient.Head(url)
}
// Head is a convenience method for doing simple HEAD requests.
func (c *Client) Head(url string) (*http.Response, error) {
req, err := NewRequest("HEAD", url, nil)
if err != nil {
return nil, err
}
return c.Do(req)
}
// Post is a shortcut for doing a POST request without making a new client.
func Post(url, bodyType string, body io.ReadSeeker) (*http.Response, error) {
return defaultClient.Post(url, bodyType, body)
}
// Post is a convenience method for doing simple POST requests.
func (c *Client) Post(url, bodyType string, body io.ReadSeeker) (*http.Response, error) {
req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", bodyType)
return c.Do(req)
}
// PostForm is a shortcut to perform a POST with form data without creating
// a new client.
func PostForm(url string, data url.Values) (*http.Response, error) {
return defaultClient.PostForm(url, data)
}
// PostForm is a convenience method for doing simple POST operations using
// pre-filled url.Values form data.
func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
// backoff is used to calculate how long to sleep before retrying
// after observing failures. It takes the minimum/maximum wait time and
// iteration, and returns the duration to wait.
func backoff(min, max time.Duration, iter int) time.Duration {
mult := math.Pow(2, float64(iter)) * float64(min)
sleep := time.Duration(mult)
if float64(sleep) != mult || sleep > max {
sleep = max
}
return sleep
}

21
vendor/github.com/sethgrid/pester/LICENSE.md generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) [2016] [Seth Ammons]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

126
vendor/github.com/sethgrid/pester/README.md generated vendored Normal file
View file

@ -0,0 +1,126 @@
# pester
`pester` wraps Go's standard lib http client to provide several options to increase resiliency in your request. If you experience poor network conditions or requests could experience varied delays, you can now pester the endpoint for data.
- Send out multiple requests and get the first back (only used for GET calls)
- Retry on errors
- Backoff
### Simple Example
Use `pester` where you would use the http client calls. By default, pester will use a concurrency of 1, and retry the endpoint 3 times with the `DefaultBackoff` strategy of waiting 1 second between retries.
```go
/* swap in replacement, just switch
http.{Get|Post|PostForm|Head|Do} to
pester.{Get|Post|PostForm|Head|Do}
*/
resp, err := pester.Get("http://sethammons.com")
```
### Backoff Strategy
Provide your own backoff strategy, or use one of the provided built in strategies:
- `DefaultBackoff`: 1 second
- `LinearBackoff`: n seconds where n is the retry number
- `LinearJitterBackoff`: n seconds where n is the retry number, +/- 0-33%
- `ExponentialBackoff`: n seconds where n is 2^(retry number)
- `ExponentialJitterBackoff`: n seconds where n is 2^(retry number), +/- 0-33%
```go
client := pester.New()
client.Backoff = func(retry int) time.Duration {
// set up something dynamic or use a look up table
return time.Duration(retry) * time.Minute
}
```
### Complete example
For a complete and working example, see the sample directory.
`pester` allows you to use a constructor to control:
- backoff strategy
- reties
- concurrency
- keeping a log for debugging
```go
package main
import (
"log"
"net/http"
"strings"
"github.com/sethgrid/pester"
)
func main() {
log.Println("Starting...")
{ // drop in replacement for http.Get and other client methods
resp, err := pester.Get("http://example.com")
if err != nil {
log.Println("error GETing example.com", err)
}
defer resp.Body.Close()
log.Printf("example.com %s", resp.Status)
}
{ // control the resiliency
client := pester.New()
client.Concurrency = 3
client.MaxRetries = 5
client.Backoff = pester.ExponentialBackoff
client.KeepLog = true
resp, err := client.Get("http://example.com")
if err != nil {
log.Println("error GETing example.com", client.LogString())
}
defer resp.Body.Close()
log.Printf("example.com %s", resp.Status)
}
{ // use the pester version of http.Client.Do
req, err := http.NewRequest("POST", "http://example.com", strings.NewReader("data"))
if err != nil {
log.Fatal("Unable to create a new http request", err)
}
resp, err := pester.Do(req)
if err != nil {
log.Println("error POSTing example.com", err)
}
defer resp.Body.Close()
log.Printf("example.com %s", resp.Status)
}
}
```
### Example Log
`pester` also allows you to control the resiliency and can optionally log the errors.
```go
c := pester.New()
c.KeepLog = true
nonExistantURL := "http://localhost:9000/foo"
_, _ = c.Get(nonExistantURL)
fmt.Println(c.LogString())
/*
Output:
1432402837 Get [GET] http://localhost:9000/foo request-0 retry-0 error: Get http://localhost:9000/foo: dial tcp 127.0.0.1:9000: connection refused
1432402838 Get [GET] http://localhost:9000/foo request-0 retry-1 error: Get http://localhost:9000/foo: dial tcp 127.0.0.1:9000: connection refused
1432402839 Get [GET] http://localhost:9000/foo request-0 retry-2 error: Get http://localhost:9000/foo: dial tcp 127.0.0.1:9000: connection refused
*/
```
### Tests
You can run tests in the root directory with `$ go test`. There is a benchmark-like test available with `$ cd benchmarks; go test`.
You can see `pester` in action with `$ cd sample; go run main.go`.
For watching open file descriptors, you can run `watch "lsof -i -P | grep main"` if you started the app with `go run main.go`.
I did this for watching for FD leaks. My method was to alter `sample/main.go` to only run one case (`pester.Get with set backoff stategy, concurrency and retries increased`)
and adding a sleep after the result came back. This let me verify if FDs were getting left open when they should have closed. If you know a better way, let me know!
I was able to see that FDs are now closing when they should :)
![Are we there yet?](http://butchbellah.com/wp-content/uploads/2012/06/Are-We-There-Yet.jpg)
Are we there yet? Are we there yet? Are we there yet? Are we there yet? ...

423
vendor/github.com/sethgrid/pester/main.go generated vendored Normal file
View file

@ -0,0 +1,423 @@
package pester
// pester provides additional resiliency over the standard http client methods by
// allowing you to control concurrency, retries, and a backoff strategy.
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"math/rand"
"net/http"
"net/url"
"sync"
"time"
)
// Client wraps the http client and exposes all the functionality of the http.Client.
// Additionally, Client provides pester specific values for handling resiliency.
type Client struct {
// wrap it to provide access to http built ins
hc *http.Client
Transport http.RoundTripper
CheckRedirect func(req *http.Request, via []*http.Request) error
Jar http.CookieJar
Timeout time.Duration
// pester specific
Concurrency int
MaxRetries int
Backoff BackoffStrategy
KeepLog bool
SuccessReqNum int
SuccessRetryNum int
wg *sync.WaitGroup
sync.Mutex
ErrLog []ErrEntry
}
// ErrEntry is used to provide the LogString() data and is populated
// each time an error happens if KeepLog is set.
// ErrEntry.Retry is deprecated in favor of ErrEntry.Attempt
type ErrEntry struct {
Time time.Time
Method string
URL string
Verb string
Request int
Retry int
Attempt int
Err error
}
// result simplifies the channel communication for concurrent request handling
type result struct {
resp *http.Response
err error
req int
retry int
}
// params represents all the params needed to run http client calls and pester errors
type params struct {
method string
verb string
req *http.Request
url string
bodyType string
body io.Reader
data url.Values
}
// New constructs a new DefaultClient with sensible default values
func New() *Client {
return &Client{
Concurrency: DefaultClient.Concurrency,
MaxRetries: DefaultClient.MaxRetries,
Backoff: DefaultClient.Backoff,
ErrLog: DefaultClient.ErrLog,
wg: &sync.WaitGroup{},
}
}
// NewExtendedClient allows you to pass in an http.Client that is previously set up
// and extends it to have Pester's features of concurrency and retries.
func NewExtendedClient(hc *http.Client) *Client {
c := New()
c.hc = hc
return c
}
// BackoffStrategy is used to determine how long a retry request should wait until attempted
type BackoffStrategy func(retry int) time.Duration
// DefaultClient provides sensible defaults
var DefaultClient = &Client{Concurrency: 1, MaxRetries: 3, Backoff: DefaultBackoff, ErrLog: []ErrEntry{}}
// DefaultBackoff always returns 1 second
func DefaultBackoff(_ int) time.Duration {
return 1 * time.Second
}
// ExponentialBackoff returns ever increasing backoffs by a power of 2
func ExponentialBackoff(i int) time.Duration {
return time.Duration(math.Pow(2, float64(i))) * time.Second
}
// ExponentialJitterBackoff returns ever increasing backoffs by a power of 2
// with +/- 0-33% to prevent sychronized reuqests.
func ExponentialJitterBackoff(i int) time.Duration {
return jitter(int(math.Pow(2, float64(i))))
}
// LinearBackoff returns increasing durations, each a second longer than the last
func LinearBackoff(i int) time.Duration {
return time.Duration(i) * time.Second
}
// LinearJitterBackoff returns increasing durations, each a second longer than the last
// with +/- 0-33% to prevent sychronized reuqests.
func LinearJitterBackoff(i int) time.Duration {
return jitter(i)
}
// jitter keeps the +/- 0-33% logic in one place
func jitter(i int) time.Duration {
ms := i * 1000
maxJitter := ms / 3
rand.Seed(time.Now().Unix())
jitter := rand.Intn(maxJitter + 1)
if rand.Intn(2) == 1 {
ms = ms + jitter
} else {
ms = ms - jitter
}
// a jitter of 0 messes up the time.Tick chan
if ms <= 0 {
ms = 1
}
return time.Duration(ms) * time.Millisecond
}
// Wait blocks until all pester requests have returned
// Probably not that useful outside of testing.
func (c *Client) Wait() {
c.wg.Wait()
}
// pester provides all the logic of retries, concurrency, backoff, and logging
func (c *Client) pester(p params) (*http.Response, error) {
resultCh := make(chan result)
multiplexCh := make(chan result)
finishCh := make(chan struct{})
// track all requests that go out so we can close the late listener routine that closes late incoming response bodies
totalSentRequests := &sync.WaitGroup{}
totalSentRequests.Add(1)
defer totalSentRequests.Done()
allRequestsBackCh := make(chan struct{})
go func() {
totalSentRequests.Wait()
close(allRequestsBackCh)
}()
// GET calls should be idempotent and can make use
// of concurrency. Other verbs can mutate and should not
// make use of the concurrency feature
concurrency := c.Concurrency
if p.verb != "GET" {
concurrency = 1
}
c.Lock()
if c.hc == nil {
c.hc = &http.Client{}
c.hc.Transport = c.Transport
c.hc.CheckRedirect = c.CheckRedirect
c.hc.Jar = c.Jar
c.hc.Timeout = c.Timeout
}
c.Unlock()
// re-create the http client so we can leverage the std lib
httpClient := http.Client{
Transport: c.hc.Transport,
CheckRedirect: c.hc.CheckRedirect,
Jar: c.hc.Jar,
Timeout: c.hc.Timeout,
}
// if we have a request body, we need to save it for later
var originalRequestBody []byte
var originalBody []byte
var err error
if p.req != nil && p.req.Body != nil {
originalRequestBody, err = ioutil.ReadAll(p.req.Body)
if err != nil {
return &http.Response{}, errors.New("error reading request body")
}
p.req.Body.Close()
}
if p.body != nil {
originalBody, err = ioutil.ReadAll(p.body)
if err != nil {
return &http.Response{}, errors.New("error reading body")
}
}
AttemptLimit := c.MaxRetries
if AttemptLimit <= 0 {
AttemptLimit = 1
}
for req := 0; req < concurrency; req++ {
c.wg.Add(1)
totalSentRequests.Add(1)
go func(n int, p params) {
defer c.wg.Done()
defer totalSentRequests.Done()
var err error
for i := 1; i <= AttemptLimit; i++ {
c.wg.Add(1)
defer c.wg.Done()
select {
case <-finishCh:
return
default:
}
resp := &http.Response{}
// rehydrate the body (it is drained each read)
if len(originalRequestBody) > 0 {
p.req.Body = ioutil.NopCloser(bytes.NewBuffer(originalRequestBody))
}
if len(originalBody) > 0 {
p.body = bytes.NewBuffer(originalBody)
}
// route the calls
switch p.method {
case "Do":
resp, err = httpClient.Do(p.req)
case "Get":
resp, err = httpClient.Get(p.url)
case "Head":
resp, err = httpClient.Head(p.url)
case "Post":
resp, err = httpClient.Post(p.url, p.bodyType, p.body)
case "PostForm":
resp, err = httpClient.PostForm(p.url, p.data)
}
// Early return if we have a valid result
// Only retry (ie, continue the loop) on 5xx status codes
if err == nil && resp.StatusCode < 500 {
multiplexCh <- result{resp: resp, err: err, req: n, retry: i}
return
}
c.log(ErrEntry{
Time: time.Now(),
Method: p.method,
Verb: p.verb,
URL: p.url,
Request: n,
Retry: i + 1, // would remove, but would break backward compatibility
Attempt: i,
Err: err,
})
// if it is the last iteration, grab the result (which is an error at this point)
if i == AttemptLimit {
multiplexCh <- result{resp: resp, err: err}
return
}
// if we are retrying, we should close this response body to free the fd
if resp != nil {
resp.Body.Close()
}
// prevent a 0 from causing the tick to block, pass additional microsecond
<-time.Tick(c.Backoff(i) + 1*time.Microsecond)
}
}(req, p)
}
// spin off the go routine so it can continually listen in on late results and close the response bodies
go func() {
gotFirstResult := false
for {
select {
case res := <-multiplexCh:
if !gotFirstResult {
gotFirstResult = true
close(finishCh)
resultCh <- res
} else if res.resp != nil {
// we only return one result to the caller; close all other response bodies that come back
// drain the body before close as to not prevent keepalive. see https://gist.github.com/mholt/eba0f2cc96658be0f717
io.Copy(ioutil.Discard, res.resp.Body)
res.resp.Body.Close()
}
case <-allRequestsBackCh:
// don't leave this goroutine running
return
}
}
}()
select {
case res := <-resultCh:
c.Lock()
defer c.Unlock()
c.SuccessReqNum = res.req
c.SuccessRetryNum = res.retry
return res.resp, res.err
}
}
// LogString provides a string representation of the errors the client has seen
func (c *Client) LogString() string {
c.Lock()
defer c.Unlock()
var res string
for _, e := range c.ErrLog {
res += fmt.Sprintf("%d %s [%s] %s request-%d retry-%d error: %s\n",
e.Time.Unix(), e.Method, e.Verb, e.URL, e.Request, e.Retry, e.Err)
}
return res
}
// LogErrCount is a helper method used primarily for test validation
func (c *Client) LogErrCount() int {
c.Lock()
defer c.Unlock()
return len(c.ErrLog)
}
// EmbedHTTPClient allows you to extend an existing Pester client with an
// underlying http.Client, such as https://godoc.org/golang.org/x/oauth2/google#DefaultClient
func (c *Client) EmbedHTTPClient(hc *http.Client) {
c.hc = hc
}
func (c *Client) log(e ErrEntry) {
if c.KeepLog {
c.Lock()
c.ErrLog = append(c.ErrLog, e)
c.Unlock()
}
}
// Do provides the same functionality as http.Client.Do
func (c *Client) Do(req *http.Request) (resp *http.Response, err error) {
return c.pester(params{method: "Do", req: req, verb: req.Method, url: req.URL.String()})
}
// Get provides the same functionality as http.Client.Get
func (c *Client) Get(url string) (resp *http.Response, err error) {
return c.pester(params{method: "Get", url: url, verb: "GET"})
}
// Head provides the same functionality as http.Client.Head
func (c *Client) Head(url string) (resp *http.Response, err error) {
return c.pester(params{method: "Head", url: url, verb: "HEAD"})
}
// Post provides the same functionality as http.Client.Post
func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *http.Response, err error) {
return c.pester(params{method: "Post", url: url, bodyType: bodyType, body: body, verb: "POST"})
}
// PostForm provides the same functionality as http.Client.PostForm
func (c *Client) PostForm(url string, data url.Values) (resp *http.Response, err error) {
return c.pester(params{method: "PostForm", url: url, data: data, verb: "POST"})
}
////////////////////////////////////////
// Provide self-constructing variants //
////////////////////////////////////////
// Do provides the same functionality as http.Client.Do and creates its own constructor
func Do(req *http.Request) (resp *http.Response, err error) {
c := New()
return c.Do(req)
}
// Get provides the same functionality as http.Client.Get and creates its own constructor
func Get(url string) (resp *http.Response, err error) {
c := New()
return c.Get(url)
}
// Head provides the same functionality as http.Client.Head and creates its own constructor
func Head(url string) (resp *http.Response, err error) {
c := New()
return c.Head(url)
}
// Post provides the same functionality as http.Client.Post and creates its own constructor
func Post(url string, bodyType string, body io.Reader) (resp *http.Response, err error) {
c := New()
return c.Post(url, bodyType, body)
}
// PostForm provides the same functionality as http.Client.PostForm and creates its own constructor
func PostForm(url string, data url.Values) (resp *http.Response, err error) {
c := New()
return c.PostForm(url, data)
}

12
vendor/vendor.json vendored
View file

@ -442,6 +442,12 @@
"revision": "d30f09973e19c1dfcd120b2d9c4f168e68d6b5d5",
"revisionTime": "2015-09-16T20:57:42Z"
},
{
"checksumSHA1": "9xZ1B0JppYRwKYtkT3PqQ255wqs=",
"path": "github.com/hashicorp/go-retryablehttp",
"revision": "0ef03300cde2dd0e2604ecc4e95ee7c76751be89",
"revisionTime": "2016-05-09T16:28:51Z"
},
{
"checksumSHA1": "A1PcINvF3UiwHRKn8UcgARgvGRs=",
"path": "github.com/hashicorp/go-rootcerts",
@ -658,6 +664,12 @@
"revision": "e64db453f3512cade908163702045e0f31137843",
"revisionTime": "2016-06-16T02:49:54Z"
},
{
"checksumSHA1": "8Lm8nsMCFz4+gr9EvQLqK8+w+Ks=",
"path": "github.com/sethgrid/pester",
"revision": "8053687f99650573b28fb75cddf3f295082704d7",
"revisionTime": "2016-04-29T17:20:22Z"
},
{
"checksumSHA1": "UADS3X1kxl+/qqeGcmTo0rBiXlQ=",
"path": "github.com/ugorji/go/codec",

View file

@ -313,7 +313,7 @@ curl -X POST -H "x-vault-token:123" "http://127.0.0.1:8200/v1/auth/aws-ec2/role/
#### Perform the login operation
```
curl -X POST "http://127.0.0.1:8200/v1/auth/aws-ec2/login" -d '{"role":"dev-role","pkcs7":"MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCAJIAEggGmewogICJkZXZwYXlQcm9kdWN0Q29kZXMiIDogbnVsbCwKICAicHJpdmF0ZUlwIiA6ICIxNzIuMzEuNjMuNjAiLAogICJhdmFpbGFiaWxpdHlab25lIiA6ICJ1cy1lYXN0LTFjIiwKICAidmVyc2lvbiIgOiAiMjAxMC0wOC0zMSIsCiAgImluc3RhbmNlSWQiIDogImktZGUwZjEzNDQiLAogICJiaWxsaW5nUHJvZHVjdHMiIDogbnVsbCwKICAiaW5zdGFuY2VUeXBlIiA6ICJ0Mi5taWNybyIsCiAgImFjY291bnRJZCIgOiAiMjQxNjU2NjE1ODU5IiwKICAiaW1hZ2VJZCIgOiAiYW1pLWZjZTNjNjk2IiwKICAicGVuZGluZ1RpbWUiIDogIjIwMTYtMDQtMDVUMTY6MjY6NTVaIiwKICAiYXJjaGl0ZWN0dXJlIiA6ICJ4ODZfNjQiLAogICJrZXJuZWxJZCIgOiBudWxsLAogICJyYW1kaXNrSWQiIDogbnVsbCwKICAicmVnaW9uIiA6ICJ1cy1lYXN0LTEiCn0AAAAAAAAxggEXMIIBEwIBATBpMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQwIJAJa6SNnlXhpnMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNjA0MDUxNjI3MDBaMCMGCSqGSIb3DQEJBDEWBBRtiynzMTNfTw1TV/d8NvfgVw+XfTAJBgcqhkjOOAQDBC4wLAIUVfpVcNYoOKzN1c+h1Vsm/c5U0tQCFAK/K72idWrONIqMOVJ8Uen0wYg4AAAAAAAA","nonce":"vault-client-nonce"}'
curl -X POST "http://127.0.0.1:8200/v1/auth/aws-ec2/login" -d '{"role":"dev-role","pkcs7":"$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/pkcs7 | tr -d '\n')","nonce":"vault-client-nonce"}'
```
@ -1107,7 +1107,7 @@ in its identity document to match the one specified by this parameter.
<li>
<span class="param">pkcs7</span>
<span class="param-flags">required</span>
PKCS7 signature of the identity document.
PKCS7 signature of the identity document with all `\n` characters removed.
</li>
</ul>
<ul>

View file

@ -486,7 +486,7 @@ of the header should be "X-Vault-Token" and the value should be the token.
</dd>
<dt>Method</dt>
<dd>GET</dd>
<dd>DELETE</dd>
<dt>URL</dt>
<dd>`/auth/token/roles/<role_name>`</dd>

View file

@ -46,6 +46,10 @@ The following table describes them:
<td><tt>VAULT_CLIENT_KEY</tt></td>
<td>Path to an unencrypted PEM-encoded private key matching the client certificate.</td>
</tr>
<tr>
<td><tt>VAULT_MAX_RETRIES</tt></td>
<td>The maximum number of retries when a `5xx` error code is encountered. Default is `2`, for three total tries; set to `0` or less to disable retrying.</td>
</tr>
<tr>
<td><tt>VAULT_SKIP_VERIFY</tt></td>
<td>If set, do not verify Vault's presented certificate before communicating with it. Setting this variable is not recommended except during testing.</td>

View file

@ -125,41 +125,10 @@ For tokens, they are associated at creation time with `vault token-create`
and the `-policy` flags. Child tokens can be associated with a subset of
a parent's policies. Root users can assign any policies.
There is no way to modify the policies associated with an active
identity. The identity must be revoked and reauthenticated to receive
the new policy list.
If an _existing_ policy is modified, the modifications propagate
to all associated users instantly. The above paragraph is more specifically
stating that you can't add new or remove policies associated with an
active identity.
## Changes from 0.1
In Vault versions prior to 0.2, the ACL policy language had a slightly
different specification and semantics. The current specification requires
that glob behavior explicitly be specified by adding the `*` character to
the end of a path. Previously, all paths were glob based matches and no
exact match could be specified.
The other change is that deny had the lowest precedence. This meant if there
were two policies being merged (e.g. "ops" and "prod") and they had a conflicting
policy like:
```
path "sys/seal" {
policy = "deny"
}
path "sys/seal" {
policy = "read"
}
```
The merge would previously give the "read" higher precedence. The current
version of Vault prioritizes the explicit deny, so that the "deny" would
take precedence.
To make all Vault 0.1 policies compatible with Vault 0.2+, the explicit
glob character must be added to all the path prefixes.
There is no way to modify the policies associated with a token once the token
has been issued. The token must be revoked and a new one acquired to receive a
new set of policies.
However, the _contents_ of policies are parsed in real-time at every token use.
As a result, if a policy is modified, the modified rules will be in force the
next time a token with that policy attached is used to make a call to Vault.

View file

@ -75,7 +75,7 @@ Disabling `mlock` is not recommended unless the systems running Vault only
use encrypted swap or do not use swap at all. Vault only supports memory
locking on UNIX-like systems (Linux, FreeBSD, Darwin, etc). Non-UNIX like
systems (e.g. Windows, NaCL, Android) lack the primitives to keep a process's
entire memory address space from spilling disk and is therefore automatically
entire memory address space from spilling to disk and is therefore automatically
disabled on unsupported platforms.
On Linux, to give the Vault executable the ability to use the `mlock` syscall
@ -223,6 +223,9 @@ For Consul, the following options are supported:
* `tls_skip_verify` (optional) - If non-empty, then TLS host verification
will be disabled for Consul communication. Defaults to false.
* `tls_min_version` (optional) - Minimum TLS version to use. Accepted values
are 'tls10', 'tls11' or 'tls12'. Defaults to 'tls12'.
The following settings should be set according to your [Consul encryption
settings](https://www.consul.io/docs/agent/encryption.html):

View file

@ -56,7 +56,7 @@ The key features of Vault are:
having to design their own encryption methods.
* **Leasing and Renewal**: All secrets in Vault have a _lease_ associated
with it. At the end of the lease, Vault will automatically revoke that
with them. At the end of the lease, Vault will automatically revoke that
secret. Clients are able to renew leases via built-in renew APIs.
* **Revocation**: Vault has built-in support for secret revocation. Vault

View file

@ -25,6 +25,9 @@
<li<%= sidebar_current("docs-install-upgrade-to-0.5.1") %>>
<a href="/docs/install/upgrade-to-0.5.1.html">Upgrade to 0.5.1</a>
</li>
<li<%= sidebar_current("docs-install-upgrade-to-0.6") %>>
<a href="/docs/install/upgrade-to-0.6.html">Upgrade to 0.6</a>
</li>
</ul>
</li>
</ul>