open-vault/vault/core_test.go

3373 lines
85 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2015-03-11 18:52:01 +00:00
package vault
import (
"context"
"fmt"
2015-03-11 18:57:05 +00:00
"reflect"
"strings"
"sync"
"sync/atomic"
2015-03-11 18:52:01 +00:00
"testing"
"time"
2015-03-11 18:52:01 +00:00
"github.com/hashicorp/vault/command/server"
logicalKv "github.com/hashicorp/vault-plugin-secrets-kv"
logicalDb "github.com/hashicorp/vault/builtin/logical/database"
"github.com/hashicorp/vault/builtin/plugin"
"github.com/hashicorp/vault/builtin/audit/syslog"
"github.com/hashicorp/vault/builtin/audit/file"
"github.com/hashicorp/vault/builtin/audit/socket"
"github.com/stretchr/testify/require"
2018-10-23 06:34:02 +00:00
"github.com/go-test/deep"
"github.com/hashicorp/errwrap"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/audit"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/sdk/physical/inmem"
"github.com/hashicorp/vault/version"
"github.com/sasha-s/go-deadlock"
2015-03-11 18:52:01 +00:00
)
// invalidKey is used to test Unseal
var invalidKey = []byte("abcdefghijklmnopqrstuvwxyz")[:17]
2015-03-12 18:20:27 +00:00
// TestNewCore_configureAuditBackends ensures that we are able to configure the
// supplied audit backends when getting a NewCore.
func TestNewCore_configureAuditBackends(t *testing.T) {
t.Parallel()
tests := map[string]struct {
backends map[string]audit.Factory
}{
"none": {
backends: nil,
},
"file": {
backends: map[string]audit.Factory{
"file": file.Factory,
},
},
"socket": {
backends: map[string]audit.Factory{
"socket": socket.Factory,
},
},
"syslog": {
backends: map[string]audit.Factory{
"syslog": syslog.Factory,
},
},
"all": {
backends: map[string]audit.Factory{
"file": file.Factory,
"socket": socket.Factory,
"syslog": syslog.Factory,
},
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
core := &Core{}
require.Len(t, core.auditBackends, 0)
core.configureAuditBackends(tc.backends)
require.Len(t, core.auditBackends, len(tc.backends))
for k := range tc.backends {
require.Contains(t, core.auditBackends, k)
}
})
}
}
// TestNewCore_configureCredentialsBackends ensures that we are able to configure the
// supplied credential backends, in addition to defaults, when getting a NewCore.
func TestNewCore_configureCredentialsBackends(t *testing.T) {
t.Parallel()
tests := map[string]struct {
backends map[string]logical.Factory
}{
"none": {
backends: nil,
},
"plugin": {
backends: map[string]logical.Factory{
"plugin": plugin.Factory,
},
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
core := &Core{}
require.Len(t, core.credentialBackends, 0)
core.configureCredentialsBackends(tc.backends, corehelpers.NewTestLogger(t))
require.GreaterOrEqual(t, len(core.credentialBackends), len(tc.backends)+1) // token + ent
for k := range tc.backends {
require.Contains(t, core.credentialBackends, k)
}
})
}
}
// TestNewCore_configureLogicalBackends ensures that we are able to configure the
// supplied logical backends, in addition to defaults, when getting a NewCore.
func TestNewCore_configureLogicalBackends(t *testing.T) {
t.Parallel()
// configureLogicalBackends will add some default backends for us:
// cubbyhole
// identity
// kv
// system
// In addition Enterprise versions of Vault may add additional engines.
tests := map[string]struct {
backends map[string]logical.Factory
adminNamespacePath string
expectedNonEntBackends int
}{
"none": {
backends: nil,
expectedNonEntBackends: 0,
},
"database": {
backends: map[string]logical.Factory{
"database": logicalDb.Factory,
},
adminNamespacePath: "foo",
expectedNonEntBackends: 5, // database + defaults
},
"kv": {
backends: map[string]logical.Factory{
"kv": logicalKv.Factory,
},
adminNamespacePath: "foo",
expectedNonEntBackends: 4, // kv + defaults (kv is a default)
},
"plugin": {
backends: map[string]logical.Factory{
"plugin": plugin.Factory,
},
adminNamespacePath: "foo",
expectedNonEntBackends: 5, // plugin + defaults
},
"all": {
backends: map[string]logical.Factory{
"database": logicalDb.Factory,
"kv": logicalKv.Factory,
"plugin": plugin.Factory,
},
adminNamespacePath: "foo",
expectedNonEntBackends: 6, // database, plugin + defaults
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
core := &Core{}
require.Len(t, core.logicalBackends, 0)
core.configureLogicalBackends(tc.backends, corehelpers.NewTestLogger(t), tc.adminNamespacePath)
require.GreaterOrEqual(t, len(core.logicalBackends), tc.expectedNonEntBackends)
require.Contains(t, core.logicalBackends, mountTypeKV)
require.Contains(t, core.logicalBackends, mountTypeCubbyhole)
require.Contains(t, core.logicalBackends, mountTypeSystem)
require.Contains(t, core.logicalBackends, mountTypeIdentity)
for k := range tc.backends {
require.Contains(t, core.logicalBackends, k)
}
})
}
}
// TestNewCore_configureLogRequestLevel ensures that we are able to configure the
// supplied logging level when getting a NewCore.
func TestNewCore_configureLogRequestLevel(t *testing.T) {
t.Parallel()
tests := map[string]struct {
level string
expectedLevel log.Level
}{
"none": {
level: "",
expectedLevel: log.NoLevel,
},
"trace": {
level: "trace",
expectedLevel: log.Trace,
},
"debug": {
level: "debug",
expectedLevel: log.Debug,
},
"info": {
level: "info",
expectedLevel: log.Info,
},
"warn": {
level: "warn",
expectedLevel: log.Warn,
},
"error": {
level: "error",
expectedLevel: log.Error,
},
"bad": {
level: "foo",
expectedLevel: log.NoLevel,
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
// We need to supply a logger, as configureLogRequestLevel emits
// warnings to the logs in certain circumstances.
core := &Core{
logger: corehelpers.NewTestLogger(t),
}
core.configureLogRequestLevel(tc.level)
require.Equal(t, tc.expectedLevel, log.Level(core.logRequestsLevel.Load()))
})
}
}
// TestNewCore_configureListeners tests that we are able to configure listeners
// on a NewCore via config.
func TestNewCore_configureListeners(t *testing.T) {
// We would usually expect CoreConfig to come from server.NewConfig().
// However, we want to fiddle to give us some granular control over the config.
tests := map[string]struct {
config *CoreConfig
expectedListeners []*ListenerCustomHeaders
}{
"nil-listeners": {
config: &CoreConfig{
RawConfig: &server.Config{
SharedConfig: &configutil.SharedConfig{},
},
},
expectedListeners: nil,
},
"listeners-empty": {
config: &CoreConfig{
RawConfig: &server.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*configutil.Listener{},
},
},
},
expectedListeners: nil,
},
"listeners-some": {
config: &CoreConfig{
RawConfig: &server.Config{
SharedConfig: &configutil.SharedConfig{
Listeners: []*configutil.Listener{
{Address: "foo"},
},
},
},
},
expectedListeners: []*ListenerCustomHeaders{
{Address: "foo"},
},
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
// We need to init some values ourselves, usually CreateCore does this for us.
logger := corehelpers.NewTestLogger(t)
backend, err := inmem.NewInmem(nil, logger)
require.NoError(t, err)
storage := &logical.InmemStorage{}
core := &Core{
clusterListener: new(atomic.Value),
customListenerHeader: new(atomic.Value),
uiConfig: NewUIConfig(false, backend, storage),
}
err = core.configureListeners(tc.config)
require.NoError(t, err)
switch tc.expectedListeners {
case nil:
require.Nil(t, core.customListenerHeader.Load())
default:
for i, v := range core.customListenerHeader.Load().([]*ListenerCustomHeaders) {
require.Equal(t, v.Address, tc.config.RawConfig.Listeners[i].Address)
}
}
})
}
}
func TestNewCore_badRedirectAddr(t *testing.T) {
logger = logging.NewVaultLogger(log.Trace)
2016-08-19 20:45:17 +00:00
inm, err := inmem.NewInmem(nil, logger)
if err != nil {
t.Fatal(err)
}
conf := &CoreConfig{
RedirectAddr: "127.0.0.1:8200",
Physical: inm,
DisableMlock: true,
}
_, err = NewCore(conf)
if err == nil {
t.Fatal("should error")
}
}
func TestSealConfig_Invalid(t *testing.T) {
s := &SealConfig{
SecretShares: 2,
SecretThreshold: 1,
}
err := s.Validate()
if err == nil {
t.Fatalf("expected err")
}
}
// TestCore_HasVaultVersion checks that versionHistory is correct and initialized
// after a core has been unsealed.
func TestCore_HasVaultVersion(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
if c.versionHistory == nil {
t.Fatalf("Version timestamps for core were not initialized for a new core")
}
versionEntry, ok := c.versionHistory[version.Version]
if !ok {
t.Fatalf("%s upgrade time not found", version.Version)
}
upgradeTime := versionEntry.TimestampInstalled
if upgradeTime.After(time.Now()) || upgradeTime.Before(time.Now().Add(-1*time.Hour)) {
t.Fatalf("upgrade time isn't within reasonable bounds of new core initialization. " +
fmt.Sprintf("time is: %+v, upgrade time is %+v", time.Now(), upgradeTime))
}
}
2015-03-11 21:25:16 +00:00
func TestCore_Unseal_MultiShare(t *testing.T) {
c := TestCore(t)
2015-03-11 21:25:16 +00:00
_, err := TestCoreUnseal(c, invalidKey)
2015-03-11 21:25:16 +00:00
if err != ErrNotInit {
t.Fatalf("err: %v", err)
}
sealConf := &SealConfig{
SecretShares: 5,
SecretThreshold: 3,
}
2018-09-18 03:03:00 +00:00
res, err := c.Initialize(namespace.RootContext(nil), &InitParams{
BarrierConfig: sealConf,
RecoveryConfig: nil,
})
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !c.Sealed() {
2015-03-11 21:25:16 +00:00
t.Fatalf("should be sealed")
}
if prog, _ := c.SecretProgress(true); prog != 0 {
2015-03-11 21:25:16 +00:00
t.Fatalf("bad progress: %d", prog)
}
for i := 0; i < 5; i++ {
unseal, err := TestCoreUnseal(c, res.SecretShares[i])
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Ignore redundant
_, err = TestCoreUnseal(c, res.SecretShares[i])
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if i >= 2 {
if !unseal {
t.Fatalf("should be unsealed")
}
if prog, _ := c.SecretProgress(true); prog != 0 {
2015-03-11 21:25:16 +00:00
t.Fatalf("bad progress: %d", prog)
}
} else {
if unseal {
t.Fatalf("should not be unsealed")
}
if prog, _ := c.SecretProgress(true); prog != i+1 {
2015-03-11 21:25:16 +00:00
t.Fatalf("bad progress: %d", prog)
}
}
}
if c.Sealed() {
2015-03-11 21:25:16 +00:00
t.Fatalf("should not be sealed")
}
2015-03-31 16:59:02 +00:00
err = c.Seal(res.RootToken)
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Ignore redundant
2015-03-31 16:59:02 +00:00
err = c.Seal(res.RootToken)
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !c.Sealed() {
2015-03-11 21:25:16 +00:00
t.Fatalf("should be sealed")
}
}
// TestCore_UseSSCTokenToggleOn will check that the root SSC
// token can be used even when disableSSCTokens is toggled on
func TestCore_UseSSCTokenToggleOn(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
c.disableSSCTokens = true
req := &logical.Request{
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: root,
}
ctx := namespace.RootContext(nil)
resp, err := c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(ctx, req)
if err != nil {
t.Fatalf("err: %s", err)
}
resp, err = c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil || resp.Secret == nil || resp.Data == nil {
t.Fatalf("bad: %#v", resp)
}
if resp.Secret.TTL != time.Hour {
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Secret.LeaseID == "" {
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Data["foo"] != "bar" {
t.Fatalf("bad: %#v", resp.Data)
}
}
// TestCore_UseNonSSCTokenToggleOff will check that the root
// non-SSC token can be used even when disableSSCTokens is toggled
// off.
func TestCore_UseNonSSCTokenToggleOff(t *testing.T) {
coreConfig := &CoreConfig{
DisableSSCTokens: true,
}
c, _, root := TestCoreUnsealedWithConfig(t, coreConfig)
if len(root) > TokenLength+OldTokenPrefixLength || !strings.HasPrefix(root, consts.LegacyServiceTokenPrefix) {
t.Fatalf("token is not an old token type: %s, %d", root, len(root))
}
c.disableSSCTokens = false
req := &logical.Request{
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: root,
}
ctx := namespace.RootContext(nil)
resp, err := c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(ctx, req)
if err != nil {
t.Fatalf("err: %s", err)
}
resp, err = c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil || resp.Secret == nil || resp.Data == nil {
t.Fatalf("bad: %#v", resp)
}
if resp.Secret.TTL != time.Hour {
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Secret.LeaseID == "" {
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Data["foo"] != "bar" {
t.Fatalf("bad: %#v", resp.Data)
}
}
2015-03-11 21:25:16 +00:00
func TestCore_Unseal_Single(t *testing.T) {
c := TestCore(t)
2015-03-11 21:25:16 +00:00
_, err := TestCoreUnseal(c, invalidKey)
2015-03-11 21:25:16 +00:00
if err != ErrNotInit {
t.Fatalf("err: %v", err)
}
sealConf := &SealConfig{
SecretShares: 1,
SecretThreshold: 1,
}
2018-09-18 03:03:00 +00:00
res, err := c.Initialize(namespace.RootContext(nil), &InitParams{
BarrierConfig: sealConf,
RecoveryConfig: nil,
})
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !c.Sealed() {
2015-03-11 21:25:16 +00:00
t.Fatalf("should be sealed")
}
if prog, _ := c.SecretProgress(true); prog != 0 {
2015-03-11 21:25:16 +00:00
t.Fatalf("bad progress: %d", prog)
}
unseal, err := TestCoreUnseal(c, res.SecretShares[0])
2015-03-11 21:25:16 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !unseal {
t.Fatalf("should be unsealed")
}
if prog, _ := c.SecretProgress(true); prog != 0 {
2015-03-11 21:25:16 +00:00
t.Fatalf("bad progress: %d", prog)
}
if c.Sealed() {
2015-03-11 21:25:16 +00:00
t.Fatalf("should not be sealed")
}
}
2015-03-11 21:31:55 +00:00
func TestCore_Route_Sealed(t *testing.T) {
c := TestCore(t)
2015-03-11 21:31:55 +00:00
sealConf := &SealConfig{
SecretShares: 1,
SecretThreshold: 1,
}
2018-09-18 03:03:00 +00:00
ctx := namespace.RootContext(nil)
2015-03-11 21:31:55 +00:00
// Should not route anything
req := &logical.Request{
Operation: logical.ReadOperation,
2015-03-11 22:19:41 +00:00
Path: "sys/mounts",
2015-03-11 21:31:55 +00:00
}
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(ctx, req)
if err != consts.ErrSealed {
2015-03-11 21:31:55 +00:00
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
res, err := c.Initialize(ctx, &InitParams{
BarrierConfig: sealConf,
RecoveryConfig: nil,
})
2015-03-11 21:31:55 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
unseal, err := TestCoreUnseal(c, res.SecretShares[0])
2015-03-11 21:31:55 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !unseal {
t.Fatalf("should be unsealed")
}
// Should not error after unseal
2015-03-24 18:37:07 +00:00
req.ClientToken = res.RootToken
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(ctx, req)
2015-03-11 21:31:55 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
}
2015-03-13 18:16:24 +00:00
// Attempt to unseal after doing a first seal
func TestCore_SealUnseal(t *testing.T) {
2017-01-17 20:43:10 +00:00
c, keys, root := TestCoreUnsealed(t)
2015-03-31 16:59:02 +00:00
if err := c.Seal(root); err != nil {
2015-03-13 18:16:24 +00:00
t.Fatalf("err: %v", err)
}
2017-01-17 20:43:10 +00:00
for i, key := range keys {
unseal, err := TestCoreUnseal(c, key)
if err != nil {
t.Fatalf("err: %v", err)
}
if i+1 == len(keys) && !unseal {
t.Fatalf("err: should be unsealed")
}
2015-03-13 18:16:24 +00:00
}
}
// TestCore_RunLockedUserUpdatesForStaleEntry tests that stale locked user entries
// get deleted upon unseal
func TestCore_RunLockedUserUpdatesForStaleEntry(t *testing.T) {
core, keys, root := TestCoreUnsealed(t)
storageUserLockoutPath := fmt.Sprintf(coreLockedUsersPath + "ns1/mountAccessor1/aliasName1")
// cleanup
defer core.barrier.Delete(context.Background(), storageUserLockoutPath)
// create invalid entry in storage to test stale entries get deleted on unseal
// last failed login time for this path is 1970-01-01 00:00:00 +0000 UTC
// since user lockout configurations are not configured, lockout duration will
// be set to default (15m) internally
compressedBytes, err := jsonutil.EncodeJSONAndCompress(int(time.Unix(0, 0).Unix()), nil)
if err != nil {
t.Fatal(err)
}
// Create an entry
entry := &logical.StorageEntry{
Key: storageUserLockoutPath,
Value: compressedBytes,
}
// Write to the physical backend
err = core.barrier.Put(context.Background(), entry)
if err != nil {
t.Fatalf("failed to write invalid locked user entry, err: %v", err)
}
// seal and unseal vault
if err := core.Seal(root); err != nil {
t.Fatalf("err: %v", err)
}
for i, key := range keys {
unseal, err := TestCoreUnseal(core, key)
if err != nil {
t.Fatalf("err: %v", err)
}
if i+1 == len(keys) && !unseal {
t.Fatalf("err: should be unsealed")
}
}
// locked user entry must be deleted upon unseal as it is stale
lastFailedLoginRaw, err := core.barrier.Get(context.Background(), storageUserLockoutPath)
if err != nil {
t.Fatal(err)
}
if lastFailedLoginRaw != nil {
t.Fatal("err: stale locked user entry exists")
}
}
// TestCore_RunLockedUserUpdatesForValidEntry tests that valid locked user entries
// do not get removed on unseal
// Also tests that the userFailedLoginInfo map gets updated with correct information
func TestCore_RunLockedUserUpdatesForValidEntry(t *testing.T) {
core, keys, root := TestCoreUnsealed(t)
storageUserLockoutPath := fmt.Sprintf(coreLockedUsersPath + "ns1/mountAccessor1/aliasName1")
// cleanup
defer core.barrier.Delete(context.Background(), storageUserLockoutPath)
// create valid storage entry for locked user
lastFailedLoginTime := int(time.Now().Unix())
compressedBytes, err := jsonutil.EncodeJSONAndCompress(lastFailedLoginTime, nil)
if err != nil {
t.Fatal(err)
}
// Create an entry
entry := &logical.StorageEntry{
Key: storageUserLockoutPath,
Value: compressedBytes,
}
// Write to the physical backend
err = core.barrier.Put(context.Background(), entry)
if err != nil {
t.Fatalf("failed to write invalid locked user entry, err: %v", err)
}
// seal and unseal vault
if err := core.Seal(root); err != nil {
t.Fatalf("err: %v", err)
}
for i, key := range keys {
unseal, err := TestCoreUnseal(core, key)
if err != nil {
t.Fatalf("err: %v", err)
}
if i+1 == len(keys) && !unseal {
t.Fatalf("err: should be unsealed")
}
}
// locked user entry must exist as it is still valid
existingEntry, err := core.barrier.Get(context.Background(), storageUserLockoutPath)
if err != nil {
t.Fatal(err)
}
if existingEntry == nil {
t.Fatalf("err: entry must exist for locked user in storage")
}
// userFailedLoginInfo map should have the correct information for locked user
loginUserInfoKey := FailedLoginUser{
aliasName: "aliasName1",
mountAccessor: "mountAccessor1",
}
failedLoginInfoFromMap := core.LocalGetUserFailedLoginInfo(context.Background(), loginUserInfoKey)
if failedLoginInfoFromMap == nil {
t.Fatalf("err: entry must exist for locked user in userFailedLoginInfo map")
}
if failedLoginInfoFromMap.lastFailedLoginTime != lastFailedLoginTime {
t.Fatalf("err: incorrect failed login time information for locked user updated in userFailedLoginInfo map")
}
if int(failedLoginInfoFromMap.count) != configutil.UserLockoutThresholdDefault {
t.Fatalf("err: incorrect failed login count information for locked user updated in userFailedLoginInfo map")
}
}
2015-06-18 01:23:59 +00:00
// Attempt to shutdown after unseal
func TestCore_Shutdown(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
if err := c.Shutdown(); err != nil {
t.Fatalf("err: %v", err)
}
if !c.Sealed() {
t.Fatal("wasn't sealed")
2015-06-18 01:23:59 +00:00
}
}
// verify the channel returned by ShutdownDone is closed after Finalize
func TestCore_ShutdownDone(t *testing.T) {
c := TestCoreWithSealAndUINoCleanup(t, &CoreConfig{})
testCoreUnsealed(t, c)
doneCh := c.ShutdownDone()
go func() {
time.Sleep(100 * time.Millisecond)
err := c.Shutdown()
if err != nil {
t.Fatal(err)
}
}()
select {
case <-doneCh:
if !c.Sealed() {
t.Fatalf("shutdown done called prematurely!")
}
case <-time.After(5 * time.Second):
t.Fatalf("shutdown notification not received")
}
}
2015-03-31 17:00:04 +00:00
// Attempt to seal bad token
func TestCore_Seal_BadToken(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
if err := c.Seal("foo"); err == nil {
t.Fatalf("err: %v", err)
}
if c.Sealed() {
t.Fatal("was sealed")
2015-03-31 17:00:04 +00:00
}
}
func TestCore_PreOneTen_BatchTokens(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
// load up some versions and ensure that 1.9 is the most recent one by timestamp (even though this isn't realistic)
upgradeTimePlusEpsilon := time.Now().UTC()
versionEntries := []VaultVersion{
{Version: "1.10.1", TimestampInstalled: upgradeTimePlusEpsilon.Add(-4 * time.Hour)},
{Version: "1.9.2", TimestampInstalled: upgradeTimePlusEpsilon.Add(2 * time.Hour)},
}
for _, entry := range versionEntries {
_, err := c.storeVersionEntry(context.Background(), &entry, false)
if err != nil {
t.Fatalf("failed to write version entry %#v, err: %s", entry, err.Error())
}
}
err := c.loadVersionHistory(c.activeContext)
if err != nil {
t.Fatalf("failed to populate version history cache, err: %s", err.Error())
}
// double check that we're working with 1.9
v, _, err := c.FindNewestVersionTimestamp()
if err != nil {
t.Fatal(err)
}
if v != "1.9.2" {
t.Fatalf("expected 1.9.2, found: %s", v)
}
// generate a batch token
te := &logical.TokenEntry{
NumUses: 1,
Policies: []string{"root"},
NamespaceID: namespace.RootNamespaceID,
Type: logical.TokenTypeBatch,
}
err = c.tokenStore.create(namespace.RootContext(nil), te)
if err != nil {
t.Fatal(err)
}
// verify it uses the legacy prefix
if !strings.HasPrefix(te.ID, consts.LegacyBatchTokenPrefix) {
t.Fatalf("expected 1.9 batch token IDs to start with b. but it didn't: %s", te.ID)
}
}
func TestCore_OneTenPlus_BatchTokens(t *testing.T) {
c, _, _ := TestCoreUnsealed(t)
// load up some versions and ensure that 1.10 is the most recent version
upgradeTimePlusEpsilon := time.Now().UTC()
versionEntries := []VaultVersion{
{Version: "1.9.2", TimestampInstalled: upgradeTimePlusEpsilon.Add(-4 * time.Hour)},
{Version: "1.10.1", TimestampInstalled: upgradeTimePlusEpsilon.Add(2 * time.Hour)},
}
for _, entry := range versionEntries {
_, err := c.storeVersionEntry(context.Background(), &entry, false)
if err != nil {
t.Fatalf("failed to write version entry %#v, err: %s", entry, err.Error())
}
}
err := c.loadVersionHistory(c.activeContext)
if err != nil {
t.Fatalf("failed to populate version history cache, err: %s", err.Error())
}
// double check that we're working with 1.10
v, _, err := c.FindNewestVersionTimestamp()
if err != nil {
t.Fatal(err)
}
if v != "1.10.1" {
t.Fatalf("expected 1.10.1, found: %s", v)
}
// generate a batch token
te := &logical.TokenEntry{
NumUses: 1,
Policies: []string{"root"},
NamespaceID: namespace.RootNamespaceID,
Type: logical.TokenTypeBatch,
}
err = c.tokenStore.create(namespace.RootContext(nil), te)
if err != nil {
t.Fatal(err)
}
// verify it uses the legacy prefix
if !strings.HasPrefix(te.ID, consts.BatchTokenPrefix) {
t.Fatalf("expected 1.10 batch token IDs to start with hvb. but it didn't: %s", te.ID)
}
}
// GH-3497
func TestCore_Seal_SingleUse(t *testing.T) {
c, keys, _ := TestCoreUnsealed(t)
2018-09-18 03:03:00 +00:00
c.tokenStore.create(namespace.RootContext(nil), &logical.TokenEntry{
ID: "foo",
NumUses: 1,
Policies: []string{"root"},
NamespaceID: namespace.RootNamespaceID,
})
if err := c.Seal("foo"); err != nil {
t.Fatalf("err: %v", err)
}
if !c.Sealed() {
t.Fatal("not sealed")
}
for i, key := range keys {
unseal, err := TestCoreUnseal(c, key)
if err != nil {
t.Fatalf("err: %v", err)
}
if i+1 == len(keys) && !unseal {
t.Fatalf("err: should be unsealed")
}
}
if err := c.Seal("foo"); err == nil {
t.Fatal("expected error from revoked token")
}
2018-09-18 03:03:00 +00:00
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), "foo")
if err != nil {
t.Fatal(err)
}
if te != nil {
t.Fatalf("expected nil token entry, got %#v", *te)
}
}
// Ensure we get a LeaseID
func TestCore_HandleRequest_Lease(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, root := TestCoreUnsealed(t)
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
2015-03-24 18:37:07 +00:00
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
ctx := namespace.RootContext(nil)
resp, err := c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(ctx, req)
if err != nil {
t.Fatalf("err: %s", err)
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
if resp == nil || resp.Secret == nil || resp.Data == nil {
t.Fatalf("bad: %#v", resp)
}
if resp.Secret.TTL != time.Hour {
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Secret.LeaseID == "" {
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Data["foo"] != "bar" {
t.Fatalf("bad: %#v", resp.Data)
}
}
2015-03-23 20:56:43 +00:00
func TestCore_HandleRequest_Lease_MaxLength(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1000h",
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
ctx := namespace.RootContext(nil)
resp, err := c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(ctx, req)
if err != nil {
t.Fatalf("err: %s", err)
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil || resp.Secret == nil || resp.Data == nil {
t.Fatalf("bad: %#v", resp)
}
if resp.Secret.TTL != c.maxLeaseTTL {
t.Fatalf("bad: %#v, %d", resp.Secret, c.maxLeaseTTL)
}
if resp.Secret.LeaseID == "" {
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Data["foo"] != "bar" {
t.Fatalf("bad: %#v", resp.Data)
}
}
func TestCore_HandleRequest_Lease_DefaultLength(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "0h",
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
ctx := namespace.RootContext(nil)
resp, err := c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(ctx, req)
if err != nil {
t.Fatalf("err: %s", err)
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(ctx, req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil || resp.Secret == nil || resp.Data == nil {
t.Fatalf("bad: %#v", resp)
}
if resp.Secret.TTL != c.defaultLeaseTTL {
2018-10-15 16:56:24 +00:00
t.Fatalf("bad: %d, %d", resp.Secret.TTL/time.Second, c.defaultLeaseTTL/time.Second)
}
if resp.Secret.LeaseID == "" {
t.Fatalf("bad: %#v", resp.Secret)
}
if resp.Data["foo"] != "bar" {
t.Fatalf("bad: %#v", resp.Data)
}
}
2015-03-24 18:57:08 +00:00
func TestCore_HandleRequest_MissingToken(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, _ := TestCoreUnsealed(t)
2015-03-24 18:57:08 +00:00
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-03-24 18:57:08 +00:00
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
2015-03-24 18:57:08 +00:00
t.Fatalf("err: %v", err)
}
if resp.Data["error"] != logical.ErrPermissionDenied.Error() {
2015-03-24 18:57:08 +00:00
t.Fatalf("bad: %#v", resp)
}
}
func TestCore_HandleRequest_InvalidToken(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, _ := TestCoreUnsealed(t)
2015-03-24 18:57:08 +00:00
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-03-24 18:57:08 +00:00
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: "foobarbaz",
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
2015-03-24 18:57:08 +00:00
t.Fatalf("err: %v", err)
}
if resp.Data["error"] != "permission denied" {
2015-03-24 18:57:08 +00:00
t.Fatalf("bad: %#v", resp)
}
}
// Check that standard permissions work
func TestCore_HandleRequest_NoSlash(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
req := &logical.Request{
Operation: logical.HelpOperation,
Path: "secret",
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v, resp: %v", err, resp)
}
if _, ok := resp.Data["help"]; !ok {
t.Fatalf("resp: %v", resp)
}
}
// Test a root path is denied if non-root
func TestCore_HandleRequest_RootPath(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, root := TestCoreUnsealed(t)
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaCore(t, c, root, "child", "", []string{"test"})
req := &logical.Request{
Operation: logical.ReadOperation,
Path: "sys/policy", // root protected!
ClientToken: "child",
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
2015-03-31 16:59:02 +00:00
t.Fatalf("err: %v, resp: %v", err, resp)
}
}
// Test a root path is allowed if non-root but with sudo
func TestCore_HandleRequest_RootPath_WithSudo(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, root := TestCoreUnsealed(t)
// Set the 'test' policy object to permit access to sys/policy
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "sys/policy/test", // root protected!
Data: map[string]interface{}{
"rules": `path "sys/policy" { policy = "sudo" }`,
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
2017-10-23 20:03:36 +00:00
if resp != nil && (resp.IsError() || len(resp.Data) > 0) {
t.Fatalf("bad: %#v", resp)
}
// Child token (non-root) but with 'test' policy should have access
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaCore(t, c, root, "child", "", []string{"test"})
req = &logical.Request{
Operation: logical.ReadOperation,
Path: "sys/policy", // root protected!
ClientToken: "child",
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil {
t.Fatalf("bad: %#v", resp)
}
}
2015-03-24 18:57:08 +00:00
2015-03-24 22:55:27 +00:00
// Check that standard permissions work
func TestCore_HandleRequest_PermissionDenied(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, root := TestCoreUnsealed(t)
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaCore(t, c, root, "child", "", []string{"test"})
2015-03-24 22:55:27 +00:00
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-03-24 22:55:27 +00:00
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: "child",
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
2015-03-31 16:59:02 +00:00
t.Fatalf("err: %v, resp: %v", err, resp)
2015-03-24 22:55:27 +00:00
}
}
// Check that standard permissions work
func TestCore_HandleRequest_PermissionAllowed(t *testing.T) {
2015-03-29 23:18:08 +00:00
c, _, root := TestCoreUnsealed(t)
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaCore(t, c, root, "child", "", []string{"test"})
2015-03-24 22:55:27 +00:00
// Set the 'test' policy object to permit access to secret/
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-03-24 22:55:27 +00:00
Path: "sys/policy/test",
Data: map[string]interface{}{
2015-07-05 23:31:41 +00:00
"rules": `path "secret/*" { policy = "write" }`,
2015-03-24 22:55:27 +00:00
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-03-24 22:55:27 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2017-10-23 20:03:36 +00:00
if resp != nil && (resp.IsError() || len(resp.Data) > 0) {
2015-03-24 22:55:27 +00:00
t.Fatalf("bad: %#v", resp)
}
// Write should work now
req = &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-03-24 22:55:27 +00:00
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: "child",
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
2015-03-24 22:55:27 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
}
2015-03-24 18:57:08 +00:00
func TestCore_HandleRequest_NoClientToken(t *testing.T) {
noop := &NoopBackend{
Response: &logical.Response{},
}
c, _, root := TestCoreUnsealed(t)
c.logicalBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the logical backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
req.Data["type"] = "noop"
req.Data["description"] = "foo"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to request with connection data
req = &logical.Request{
Path: "foo/login",
}
req.ClientToken = root
2018-09-18 03:03:00 +00:00
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
t.Fatalf("err: %v", err)
}
ct := noop.Requests[0].ClientToken
if ct == "" || ct == root {
t.Fatalf("bad: %#v", noop.Requests)
}
}
func TestCore_HandleRequest_ConnOnLogin(t *testing.T) {
noop := &NoopBackend{
2018-11-07 01:21:24 +00:00
Login: []string{"login"},
Response: &logical.Response{},
BackendType: logical.TypeCredential,
}
c, _, root := TestCoreUnsealed(t)
c.credentialBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to request with connection data
req = &logical.Request{
Path: "auth/foo/login",
Connection: &logical.Connection{},
}
2018-09-18 03:03:00 +00:00
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
t.Fatalf("err: %v", err)
}
if noop.Requests[0].Connection == nil {
t.Fatalf("bad: %#v", noop.Requests)
}
}
2015-03-23 20:56:43 +00:00
// Ensure we get a client token
func TestCore_HandleLogin_Token(t *testing.T) {
noop := &NoopBackend{
2015-03-23 20:56:43 +00:00
Login: []string{"login"},
Response: &logical.Response{
Auth: &logical.Auth{
Policies: []string{"foo", "bar"},
Metadata: map[string]string{
"user": "armon",
},
2015-04-15 21:12:34 +00:00
DisplayName: "armon",
},
2015-03-23 20:56:43 +00:00
},
2018-11-07 01:21:24 +00:00
BackendType: logical.TypeCredential,
2015-03-23 20:56:43 +00:00
}
2015-03-29 23:18:08 +00:00
c, _, root := TestCoreUnsealed(t)
c.credentialBackends["noop"] = func(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
2015-03-23 20:56:43 +00:00
return noop, nil
}
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
2015-03-23 20:56:43 +00:00
req.Data["type"] = "noop"
2015-03-24 18:37:07 +00:00
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-03-23 20:56:43 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to login
2015-03-31 03:26:39 +00:00
lreq := &logical.Request{
2015-03-23 20:56:43 +00:00
Path: "auth/foo/login",
}
2018-09-18 03:03:00 +00:00
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
2015-03-23 20:56:43 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure we got a client token back
2015-03-31 03:26:39 +00:00
clientToken := lresp.Auth.ClientToken
if clientToken == "" {
2015-03-23 20:56:43 +00:00
t.Fatalf("bad: %#v", lresp)
}
// Check the policy and metadata
innerToken, _ := c.DecodeSSCToken(clientToken)
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), innerToken)
if err != nil || te == nil {
t.Fatalf("tok: %s, err: %v", clientToken, err)
2015-03-23 20:56:43 +00:00
}
expectedID, _ := c.DecodeSSCToken(clientToken)
expect := &logical.TokenEntry{
ID: expectedID,
2016-03-09 18:45:36 +00:00
Accessor: te.Accessor,
2015-03-23 20:56:43 +00:00
Parent: "",
Policies: []string{"bar", "default", "foo"},
2015-03-23 20:56:43 +00:00
Path: "auth/foo/login",
2015-03-31 03:26:39 +00:00
Meta: map[string]string{
2015-03-23 20:56:43 +00:00
"user": "armon",
},
DisplayName: "foo-armon",
TTL: time.Hour * 24,
CreationTime: te.CreationTime,
2018-09-18 03:03:00 +00:00
NamespaceID: namespace.RootNamespaceID,
2018-10-23 06:34:02 +00:00
CubbyholeID: te.CubbyholeID,
2018-10-15 16:56:24 +00:00
Type: logical.TokenTypeService,
2015-03-23 20:56:43 +00:00
}
2018-10-23 06:34:02 +00:00
if diff := deep.Equal(te, expect); diff != nil {
t.Fatal(diff)
2015-03-23 20:56:43 +00:00
}
// Check that we have a lease with default duration
if lresp.Auth.TTL != noop.System().DefaultLeaseTTL() {
t.Fatalf("bad: %#v, defaultLeaseTTL: %#v", lresp.Auth, c.defaultLeaseTTL)
2015-03-23 20:56:43 +00:00
}
}
func TestCore_HandleRequest_AuditTrail(t *testing.T) {
// Create a noop audit backend
noop := &corehelpers.NoopAudit{}
c, _, root := TestCoreUnsealed(t)
c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) {
noop = &corehelpers.NoopAudit{
Config: config,
}
return noop, nil
}
// Enable the audit backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/audit/noop")
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Make a request
req = &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: root,
}
req.ClientToken = root
2018-09-18 03:03:00 +00:00
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
t.Fatalf("err: %v", err)
}
// Check the audit trail on request and response
if len(noop.ReqAuth) != 1 {
t.Fatalf("bad: %#v", noop)
}
auth := noop.ReqAuth[0]
if auth.ClientToken != root {
t.Fatalf("bad client token: %#v", auth)
}
if len(auth.Policies) != 1 || auth.Policies[0] != "root" {
t.Fatalf("bad: %#v", auth)
}
if len(noop.Req) != 1 || !reflect.DeepEqual(noop.Req[0], req) {
t.Fatalf("Bad: %#v", noop.Req[0])
}
if len(noop.RespAuth) != 2 {
t.Fatalf("bad: %#v", noop)
}
if !reflect.DeepEqual(noop.RespAuth[1], auth) {
t.Fatalf("bad: %#v, vs %#v", auth, noop.RespAuth)
}
if len(noop.RespReq) != 2 || !reflect.DeepEqual(noop.RespReq[1], req) {
t.Fatalf("Bad: %#v", noop.RespReq[1])
}
if len(noop.Resp) != 2 || !reflect.DeepEqual(noop.Resp[1], resp) {
t.Fatalf("Bad: %#v", noop.Resp[1])
}
}
2015-04-01 21:48:37 +00:00
func TestCore_HandleRequest_AuditTrail_noHMACKeys(t *testing.T) {
// Create a noop audit backend
var noop *corehelpers.NoopAudit
c, _, root := TestCoreUnsealed(t)
c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) {
noop = &corehelpers.NoopAudit{
Config: config,
}
return noop, nil
}
// Specify some keys to not HMAC
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/secret/tune")
req.Data["audit_non_hmac_request_keys"] = "foo"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
req = logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/secret/tune")
req.Data["audit_non_hmac_response_keys"] = "baz"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Enable the audit backend
req = logical.TestRequest(t, logical.UpdateOperation, "sys/audit/noop")
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Make a request
req = &logical.Request{
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
},
ClientToken: root,
}
req.ClientToken = root
2018-09-18 03:03:00 +00:00
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
t.Fatalf("err: %v", err)
}
// Check the audit trail on request and response
if len(noop.ReqAuth) != 1 {
t.Fatalf("bad: %#v", noop)
}
auth := noop.ReqAuth[0]
if auth.ClientToken != root {
t.Fatalf("bad client token: %#v", auth)
}
if len(auth.Policies) != 1 || auth.Policies[0] != "root" {
t.Fatalf("bad: %#v", auth)
}
if len(noop.Req) != 1 || !reflect.DeepEqual(noop.Req[0], req) {
t.Fatalf("Bad: %#v", noop.Req[0])
}
if len(noop.ReqNonHMACKeys) != 1 || noop.ReqNonHMACKeys[0] != "foo" {
t.Fatalf("Bad: %#v", noop.ReqNonHMACKeys)
}
if len(noop.RespAuth) != 2 {
t.Fatalf("bad: %#v", noop)
}
if !reflect.DeepEqual(noop.RespAuth[1], auth) {
t.Fatalf("bad: %#v", auth)
}
if len(noop.RespReq) != 2 || !reflect.DeepEqual(noop.RespReq[1], req) {
t.Fatalf("Bad: %#v", noop.RespReq[1])
}
if len(noop.Resp) != 2 || !reflect.DeepEqual(noop.Resp[1], resp) {
t.Fatalf("Bad: %#v", noop.Resp[1])
}
// Test for response keys
// Make a request
req = &logical.Request{
Operation: logical.ReadOperation,
Path: "secret/test",
ClientToken: root,
}
req.ClientToken = root
err = c.PopulateTokenEntry(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %s", err)
}
2018-09-18 03:03:00 +00:00
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
t.Fatalf("err: %v", err)
}
if len(noop.RespNonHMACKeys) != 1 || !strutil.EquivalentSlices(noop.RespNonHMACKeys[0], []string{"baz"}) {
t.Fatalf("Bad: %#v", noop.RespNonHMACKeys)
}
if len(noop.RespReqNonHMACKeys) != 1 || !strutil.EquivalentSlices(noop.RespReqNonHMACKeys[0], []string{"foo"}) {
t.Fatalf("Bad: %#v", noop.RespReqNonHMACKeys)
}
}
2015-04-01 21:48:37 +00:00
func TestCore_HandleLogin_AuditTrail(t *testing.T) {
// Create a badass credential backend that always logs in as armon
noop := &corehelpers.NoopAudit{}
2015-04-01 21:48:37 +00:00
noopBack := &NoopBackend{
Login: []string{"login"},
Response: &logical.Response{
Auth: &logical.Auth{
LeaseOptions: logical.LeaseOptions{
TTL: time.Hour,
},
2015-04-01 21:48:37 +00:00
Policies: []string{"foo", "bar"},
Metadata: map[string]string{
"user": "armon",
},
},
},
2018-11-07 01:21:24 +00:00
BackendType: logical.TypeCredential,
2015-04-01 21:48:37 +00:00
}
c, _, root := TestCoreUnsealed(t)
c.credentialBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
2015-04-01 21:48:37 +00:00
return noopBack, nil
}
c.auditBackends["noop"] = func(ctx context.Context, config *audit.BackendConfig) (audit.Backend, error) {
noop = &corehelpers.NoopAudit{
Config: config,
}
2015-04-01 21:48:37 +00:00
return noop, nil
}
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
2015-04-01 21:48:37 +00:00
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-04-01 21:48:37 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Enable the audit backend
2016-01-07 15:30:47 +00:00
req = logical.TestRequest(t, logical.UpdateOperation, "sys/audit/noop")
2015-04-01 21:48:37 +00:00
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), req)
2015-04-01 21:48:37 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to login
lreq := &logical.Request{
Path: "auth/foo/login",
}
2018-09-18 03:03:00 +00:00
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
2015-04-01 21:48:37 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure we got a client token back
clientToken := lresp.Auth.ClientToken
if clientToken == "" {
t.Fatalf("bad: %#v", lresp)
}
// Check the audit trail on request and response
if len(noop.ReqAuth) != 1 {
t.Fatalf("bad: %#v", noop)
}
if len(noop.Req) != 1 || !reflect.DeepEqual(noop.Req[0], lreq) {
t.Fatalf("Bad: %#v %#v", noop.Req[0], lreq)
}
if len(noop.RespAuth) != 2 {
t.Fatalf("bad: %#v", noop)
}
auth := noop.RespAuth[1]
if auth.ClientToken != clientToken {
t.Fatalf("bad client token: %#v", auth)
}
if len(auth.Policies) != 3 || auth.Policies[0] != "bar" || auth.Policies[1] != "default" || auth.Policies[2] != "foo" {
2015-04-01 21:48:37 +00:00
t.Fatalf("bad: %#v", auth)
}
if len(noop.RespReq) != 2 || !reflect.DeepEqual(noop.RespReq[1], lreq) {
t.Fatalf("Bad: %#v", noop.RespReq[1])
}
if len(noop.Resp) != 2 || !reflect.DeepEqual(noop.Resp[1], lresp) {
2015-04-01 22:48:56 +00:00
t.Fatalf("Bad: %#v %#v", noop.Resp[1], lresp)
2015-04-01 21:48:37 +00:00
}
}
2015-04-03 01:05:23 +00:00
// Check that we register a lease for new tokens
func TestCore_HandleRequest_CreateToken_Lease(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
// Create a new credential
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/create")
2015-04-03 01:05:23 +00:00
req.ClientToken = root
req.Data["policies"] = []string{"foo"}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-04-03 01:05:23 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure we got a new client token back
2017-10-23 20:03:36 +00:00
if resp.IsError() {
t.Fatalf("err: %v %v", err, *resp)
}
2015-04-03 01:05:23 +00:00
clientToken := resp.Auth.ClientToken
if clientToken == "" {
t.Fatalf("bad: %#v", resp)
}
// Check the policy and metadata
2018-09-18 03:03:00 +00:00
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), clientToken)
2015-04-03 01:05:23 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
expectedID, _ := c.DecodeSSCToken(clientToken)
expectedRootID, _ := c.DecodeSSCToken(root)
expect := &logical.TokenEntry{
ID: expectedID,
2016-03-09 18:45:36 +00:00
Accessor: te.Accessor,
Parent: expectedRootID,
Policies: []string{"default", "foo"},
Path: "auth/token/create",
DisplayName: "token",
CreationTime: te.CreationTime,
TTL: time.Hour * 24 * 32,
2018-09-18 03:03:00 +00:00
NamespaceID: namespace.RootNamespaceID,
2018-10-23 06:34:02 +00:00
CubbyholeID: te.CubbyholeID,
2018-10-15 16:56:24 +00:00
Type: logical.TokenTypeService,
2015-04-03 01:05:23 +00:00
}
2018-10-23 06:34:02 +00:00
if diff := deep.Equal(te, expect); diff != nil {
t.Fatal(diff)
2015-04-03 01:05:23 +00:00
}
// Check that we have a lease with default duration
if resp.Auth.TTL != c.defaultLeaseTTL {
2015-04-03 01:05:23 +00:00
t.Fatalf("bad: %#v", resp.Auth)
}
}
2015-04-14 23:06:58 +00:00
// Check that we handle excluding the default policy
func TestCore_HandleRequest_CreateToken_NoDefaultPolicy(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
// Create a new credential
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/create")
req.ClientToken = root
req.Data["policies"] = []string{"foo"}
req.Data["no_default_policy"] = true
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure we got a new client token back
clientToken := resp.Auth.ClientToken
if clientToken == "" {
t.Fatalf("bad: %#v", resp)
}
// Check the policy and metadata
2018-09-18 03:03:00 +00:00
te, err := c.tokenStore.Lookup(namespace.RootContext(nil), clientToken)
if err != nil {
t.Fatalf("err: %v", err)
}
expectedID, _ := c.DecodeSSCToken(clientToken)
expectedRootID, _ := c.DecodeSSCToken(root)
expect := &logical.TokenEntry{
ID: expectedID,
2016-03-09 18:45:36 +00:00
Accessor: te.Accessor,
Parent: expectedRootID,
Policies: []string{"foo"},
Path: "auth/token/create",
DisplayName: "token",
CreationTime: te.CreationTime,
TTL: time.Hour * 24 * 32,
2018-09-18 03:03:00 +00:00
NamespaceID: namespace.RootNamespaceID,
2018-10-23 06:34:02 +00:00
CubbyholeID: te.CubbyholeID,
2018-10-15 16:56:24 +00:00
Type: logical.TokenTypeService,
}
2018-10-23 06:34:02 +00:00
if diff := deep.Equal(te, expect); diff != nil {
t.Fatal(diff)
}
}
func TestCore_LimitedUseToken(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
// Create a new credential
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "auth/token/create")
req.ClientToken = root
req.Data["num_uses"] = "1"
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Put a secret
req = &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "secret/foo",
Data: map[string]interface{}{
"foo": "bar",
},
ClientToken: resp.Auth.ClientToken,
}
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Second operation should fail
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), req)
if err == nil || !errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
t.Fatalf("err: %v", err)
}
}
2016-02-03 17:28:01 +00:00
func TestCore_Standby_Seal(t *testing.T) {
// Create the first core and initialize it
logger = logging.NewVaultLogger(log.Trace)
2016-08-19 20:45:17 +00:00
inm, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
redirectOriginal := "http://127.0.0.1:8200"
2016-02-03 17:28:01 +00:00
core, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal,
DisableMlock: true,
2016-02-03 17:28:01 +00:00
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core.Shutdown()
2017-01-17 20:43:10 +00:00
keys, root := TestCoreInit(t, core)
for _, key := range keys {
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
2016-02-03 17:28:01 +00:00
}
// Verify unsealed
if core.Sealed() {
2016-02-03 17:28:01 +00:00
t.Fatal("should not be sealed")
}
// Wait for core to become active
TestWaitActive(t, core)
2016-02-03 17:28:01 +00:00
// Check the leader is local
isLeader, advertise, _, err := core.Leader()
2016-02-03 17:28:01 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
2016-02-03 17:28:01 +00:00
}
// Create the second core and initialize it
redirectOriginal2 := "http://127.0.0.1:8500"
2016-02-03 17:28:01 +00:00
core2, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal2,
DisableMlock: true,
2016-02-03 17:28:01 +00:00
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core2.Shutdown()
2017-01-17 20:43:10 +00:00
for _, key := range keys {
if _, err := TestCoreUnseal(core2, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
2016-02-03 17:28:01 +00:00
}
// Verify unsealed
if core2.Sealed() {
2016-02-03 17:28:01 +00:00
t.Fatal("should not be sealed")
}
// Core2 should be in standby
standby, err := core2.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Check the leader is not local
isLeader, advertise, _, err = core2.Leader()
2016-02-03 17:28:01 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if isLeader {
t.Fatalf("should not be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
2016-02-03 17:28:01 +00:00
}
// Seal the standby core with the correct token. Shouldn't go down
err = core2.Seal(root)
if err == nil {
t.Fatal("should not be sealed")
2016-02-03 17:28:01 +00:00
}
keyUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
// Seal the standby core with an invalid token. Shouldn't go down
err = core2.Seal(keyUUID)
if err == nil {
t.Fatal("should not be sealed")
2016-02-03 17:28:01 +00:00
}
}
func TestCore_StepDown(t *testing.T) {
// Create the first core and initialize it
logger = logging.NewVaultLogger(log.Trace).Named(t.Name())
2016-08-19 20:45:17 +00:00
inm, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
redirectOriginal := "http://127.0.0.1:8200"
core, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal,
DisableMlock: true,
Logger: logger.Named("core1"),
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core.Shutdown()
2017-01-17 20:43:10 +00:00
keys, root := TestCoreInit(t, core)
for _, key := range keys {
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
// Verify unsealed
if core.Sealed() {
t.Fatal("should not be sealed")
}
// Wait for core to become active
TestWaitActive(t, core)
// Check the leader is local
isLeader, advertise, _, err := core.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
}
// Create the second core and initialize it
redirectOriginal2 := "http://127.0.0.1:8500"
core2, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal2,
DisableMlock: true,
Logger: logger.Named("core2"),
})
defer core2.Shutdown()
if err != nil {
t.Fatalf("err: %v", err)
}
2017-01-17 20:43:10 +00:00
for _, key := range keys {
if _, err := TestCoreUnseal(core2, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
// Verify unsealed
if core2.Sealed() {
t.Fatal("should not be sealed")
}
// Core2 should be in standby
standby, err := core2.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Check the leader is not local
isLeader, advertise, _, err = core2.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if isLeader {
t.Fatalf("should not be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
}
req := &logical.Request{
ClientToken: root,
Path: "sys/step-down",
}
2016-07-24 01:46:28 +00:00
// Create an identifier for the request
req.ID, err = uuid.GenerateUUID()
if err != nil {
t.Fatalf("failed to generate identifier for the request: path: %s err: %v", req.Path, err)
}
// Step down core
2018-09-18 03:03:00 +00:00
err = core.StepDown(namespace.RootContext(nil), req)
if err != nil {
t.Fatal("error stepping down core 1")
}
// Give time to switch leaders
time.Sleep(5 * time.Second)
// Core1 should be in standby
standby, err = core.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Check the leader is core2
isLeader, advertise, _, err = core2.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal2 {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal2)
}
// Check the leader is not local
isLeader, advertise, _, err = core.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if isLeader {
t.Fatalf("should not be leader")
}
if advertise != redirectOriginal2 {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal2)
}
// Step down core2
2018-09-18 03:03:00 +00:00
err = core2.StepDown(namespace.RootContext(nil), req)
if err != nil {
t.Fatal("error stepping down core 1")
}
2016-02-29 02:35:32 +00:00
// Give time to switch leaders -- core 1 will still be waiting on its
// cooling off period so give it a full 10 seconds to recover
time.Sleep(10 * time.Second)
// Core2 should be in standby
standby, err = core2.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Check the leader is core1
isLeader, advertise, _, err = core.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
}
// Check the leader is not local
isLeader, advertise, _, err = core2.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if isLeader {
t.Fatalf("should not be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
}
}
func TestCore_CleanLeaderPrefix(t *testing.T) {
// Create the first core and initialize it
logger = logging.NewVaultLogger(log.Trace)
2016-08-19 20:45:17 +00:00
inm, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
redirectOriginal := "http://127.0.0.1:8200"
core, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal,
DisableMlock: true,
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core.Shutdown()
2017-01-17 20:43:10 +00:00
keys, root := TestCoreInit(t, core)
for _, key := range keys {
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
// Verify unsealed
if core.Sealed() {
t.Fatal("should not be sealed")
}
// Wait for core to become active
TestWaitActive(t, core)
// Ensure that the original clean function has stopped running
time.Sleep(2 * time.Second)
// Put several random entries
for i := 0; i < 5; i++ {
keyUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
valueUUID, err := uuid.GenerateUUID()
if err != nil {
t.Fatal(err)
}
core.barrier.Put(namespace.RootContext(nil), &logical.StorageEntry{
Key: coreLeaderPrefix + keyUUID,
Value: []byte(valueUUID),
})
}
2018-09-18 03:03:00 +00:00
entries, err := core.barrier.List(namespace.RootContext(nil), coreLeaderPrefix)
if err != nil {
t.Fatalf("err: %v", err)
}
if len(entries) != 6 {
t.Fatalf("wrong number of core leader prefix entries, got %d", len(entries))
}
// Check the leader is local
isLeader, advertise, _, err := core.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
}
// Create a second core, attached to same in-memory store
redirectOriginal2 := "http://127.0.0.1:8500"
core2, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal2,
DisableMlock: true,
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core2.Shutdown()
2017-01-17 20:43:10 +00:00
for _, key := range keys {
if _, err := TestCoreUnseal(core2, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
// Verify unsealed
if core2.Sealed() {
t.Fatal("should not be sealed")
}
// Core2 should be in standby
standby, err := core2.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Check the leader is not local
isLeader, advertise, _, err = core2.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if isLeader {
t.Fatalf("should not be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
}
// Seal the first core, should step down
err = core.Seal(root)
if err != nil {
t.Fatalf("err: %v", err)
}
// Core should be in standby
standby, err = core.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Wait for core2 to become active
TestWaitActive(t, core2)
// Check the leader is local
isLeader, advertise, _, err = core2.Leader()
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal2 {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal2)
}
// Give time for the entries to clear out; it is conservative at 1/second
2015-10-08 18:34:10 +00:00
time.Sleep(10 * leaderPrefixCleanDelay)
2018-09-18 03:03:00 +00:00
entries, err = core2.barrier.List(namespace.RootContext(nil), coreLeaderPrefix)
if err != nil {
t.Fatalf("err: %v", err)
}
if len(entries) != 1 {
t.Fatalf("wrong number of core leader prefix entries, got %d", len(entries))
}
}
2015-04-14 23:06:58 +00:00
func TestCore_Standby(t *testing.T) {
logger = logging.NewVaultLogger(log.Trace)
2016-08-19 20:45:17 +00:00
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
testCore_Standby_Common(t, inmha, inmha.(physical.HABackend))
2015-12-14 22:58:30 +00:00
}
func TestCore_Standby_SeparateHA(t *testing.T) {
logger = logging.NewVaultLogger(log.Trace)
2016-08-19 20:45:17 +00:00
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
inmha2, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
testCore_Standby_Common(t, inmha, inmha2.(physical.HABackend))
2015-12-14 22:58:30 +00:00
}
func testCore_Standby_Common(t *testing.T, inm physical.Backend, inmha physical.HABackend) {
// Create the first core and initialize it
redirectOriginal := "http://127.0.0.1:8200"
2015-04-29 01:12:57 +00:00
core, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha,
RedirectAddr: redirectOriginal,
DisableMlock: true,
BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(),
2015-04-29 01:12:57 +00:00
})
2015-04-14 23:06:58 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
defer core.Shutdown()
2017-01-17 20:43:10 +00:00
keys, root := TestCoreInit(t, core)
for _, key := range keys {
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
2015-04-14 23:06:58 +00:00
}
// Verify unsealed
if core.Sealed() {
2015-04-14 23:06:58 +00:00
t.Fatal("should not be sealed")
}
// Wait for core to become active
TestWaitActive(t, core)
2015-04-14 23:06:58 +00:00
testCoreAddSecretMount(t, core, root)
2015-04-14 23:06:58 +00:00
// Put a secret
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-04-14 23:06:58 +00:00
Path: "secret/foo",
Data: map[string]interface{}{
"foo": "bar",
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
_, err = core.HandleRequest(namespace.RootContext(nil), req)
2015-04-14 23:06:58 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2015-04-14 23:53:40 +00:00
// Check the leader is local
isLeader, advertise, _, err := core.Leader()
2015-04-14 23:53:40 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
2015-04-14 23:53:40 +00:00
}
2015-04-14 23:06:58 +00:00
// Create a second core, attached to same in-memory store
redirectOriginal2 := "http://127.0.0.1:8500"
2015-04-29 01:12:57 +00:00
core2, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha,
RedirectAddr: redirectOriginal2,
DisableMlock: true,
2015-04-29 01:12:57 +00:00
})
2015-04-14 23:06:58 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
defer core2.Shutdown()
2017-01-17 20:43:10 +00:00
for _, key := range keys {
if _, err := TestCoreUnseal(core2, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
2015-04-14 23:06:58 +00:00
}
// Verify unsealed
if core2.Sealed() {
2015-04-14 23:06:58 +00:00
t.Fatal("should not be sealed")
}
// Core2 should be in standby
standby, err := core2.Standby()
2015-04-14 23:06:58 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
2015-04-14 23:08:14 +00:00
// Request should fail in standby mode
2018-09-18 03:03:00 +00:00
_, err = core2.HandleRequest(namespace.RootContext(nil), req)
if err != consts.ErrStandby {
2015-04-14 23:08:14 +00:00
t.Fatalf("err: %v", err)
}
2015-04-14 23:53:40 +00:00
// Check the leader is not local
isLeader, advertise, _, err = core2.Leader()
2015-04-14 23:53:40 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if isLeader {
t.Fatalf("should not be leader")
}
if advertise != redirectOriginal {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal)
2015-04-14 23:53:40 +00:00
}
2015-04-14 23:06:58 +00:00
// Seal the first core, should step down
err = core.Seal(root)
if err != nil {
t.Fatalf("err: %v", err)
}
// Core should be in standby
standby, err = core.Standby()
if err != nil {
t.Fatalf("err: %v", err)
}
if !standby {
t.Fatalf("should be standby")
}
// Wait for core2 to become active
TestWaitActive(t, core2)
2015-04-14 23:06:58 +00:00
// Read the secret
req = &logical.Request{
Operation: logical.ReadOperation,
Path: "secret/foo",
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := core2.HandleRequest(namespace.RootContext(nil), req)
2015-04-14 23:06:58 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Verify the response
if resp.Data["foo"] != "bar" {
t.Fatalf("bad: %#v", resp)
}
2015-04-14 23:53:40 +00:00
// Check the leader is local
isLeader, advertise, _, err = core2.Leader()
2015-04-14 23:53:40 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if !isLeader {
t.Fatalf("should be leader")
}
if advertise != redirectOriginal2 {
t.Fatalf("Bad advertise: %v, orig is %v", advertise, redirectOriginal2)
2015-04-14 23:53:40 +00:00
}
if inm.(*inmem.InmemHABackend) == inmha.(*inmem.InmemHABackend) {
lockSize := inm.(*inmem.InmemHABackend).LockMapSize()
if lockSize == 0 {
t.Fatalf("locks not used with only one HA backend")
}
} else {
lockSize := inmha.(*inmem.InmemHABackend).LockMapSize()
if lockSize == 0 {
t.Fatalf("locks not used with expected HA backend")
}
lockSize = inm.(*inmem.InmemHABackend).LockMapSize()
if lockSize != 0 {
t.Fatalf("locks used with unexpected HA backend")
}
}
2015-04-14 23:06:58 +00:00
}
// Ensure that InternalData is never returned
func TestCore_HandleRequest_Login_InternalData(t *testing.T) {
noop := &NoopBackend{
Login: []string{"login"},
Response: &logical.Response{
Auth: &logical.Auth{
Policies: []string{"foo", "bar"},
InternalData: map[string]interface{}{
"foo": "bar",
},
},
},
2018-11-07 01:21:24 +00:00
BackendType: logical.TypeCredential,
}
c, _, root := TestCoreUnsealed(t)
c.credentialBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to login
lreq := &logical.Request{
Path: "auth/foo/login",
}
2018-09-18 03:03:00 +00:00
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure we do not get the internal data
if lresp.Auth.InternalData != nil {
t.Fatalf("bad: %#v", lresp)
}
}
// Ensure that InternalData is never returned
func TestCore_HandleRequest_InternalData(t *testing.T) {
noop := &NoopBackend{
Response: &logical.Response{
Secret: &logical.Secret{
InternalData: map[string]interface{}{
"foo": "bar",
},
},
Data: map[string]interface{}{
"foo": "bar",
},
},
}
c, _, root := TestCoreUnsealed(t)
c.logicalBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to read
lreq := &logical.Request{
Operation: logical.ReadOperation,
Path: "foo/test",
ClientToken: root,
}
2018-10-15 16:56:24 +00:00
lreq.SetTokenEntry(&logical.TokenEntry{ID: root, NamespaceID: "root", Policies: []string{"root"}})
2018-09-18 03:03:00 +00:00
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
if err != nil {
t.Fatalf("err: %v", err)
}
// Ensure we do not get the internal data
if lresp.Secret.InternalData != nil {
t.Fatalf("bad: %#v", lresp)
}
}
2015-05-11 18:16:21 +00:00
// Ensure login does not return a secret
func TestCore_HandleLogin_ReturnSecret(t *testing.T) {
// Create a badass credential backend that always logs in as armon
noopBack := &NoopBackend{
Login: []string{"login"},
Response: &logical.Response{
Secret: &logical.Secret{},
Auth: &logical.Auth{
Policies: []string{"foo", "bar"},
},
},
2018-11-07 01:21:24 +00:00
BackendType: logical.TypeCredential,
2015-05-11 18:16:21 +00:00
}
c, _, root := TestCoreUnsealed(t)
c.credentialBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
2015-05-11 18:16:21 +00:00
return noopBack, nil
}
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
2015-05-11 18:16:21 +00:00
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-05-11 18:16:21 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to login
lreq := &logical.Request{
Path: "auth/foo/login",
}
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), lreq)
2015-05-11 18:16:21 +00:00
if err != ErrInternalError {
t.Fatalf("err: %v", err)
}
}
2015-05-16 00:19:41 +00:00
// Renew should return the same lease back
func TestCore_RenewSameLease(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
// Create a leasable secret
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %s", err)
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil || resp.Secret == nil || resp.Secret.LeaseID == "" {
t.Fatalf("bad: %#v", resp.Secret)
}
original := resp.Secret.LeaseID
// Renew the lease
2016-01-07 15:30:47 +00:00
req = logical.TestRequest(t, logical.UpdateOperation, "sys/renew/"+resp.Secret.LeaseID)
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Verify the lease did not change
if resp.Secret.LeaseID != original {
t.Fatalf("lease id changed: %s %s", original, resp.Secret.LeaseID)
}
// Renew the lease (alternate path)
req = logical.TestRequest(t, logical.UpdateOperation, "sys/leases/renew/"+resp.Secret.LeaseID)
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Verify the lease did not change
if resp.Secret.LeaseID != original {
t.Fatalf("lease id changed: %s %s", original, resp.Secret.LeaseID)
}
}
// Renew of a token should not create a new lease
func TestCore_RenewToken_SingleRegister(t *testing.T) {
c, _, root := TestCoreUnsealed(t)
// Create a new token
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "auth/token/create",
Data: map[string]interface{}{
"lease": "1h",
},
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
newClient := resp.Auth.ClientToken
// Renew the token
2016-08-24 19:59:43 +00:00
req = logical.TestRequest(t, logical.UpdateOperation, "auth/token/renew")
req.ClientToken = newClient
2016-08-24 19:59:43 +00:00
req.Data = map[string]interface{}{
"token": newClient,
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Revoke using the renew prefix
2016-01-07 15:30:47 +00:00
req = logical.TestRequest(t, logical.UpdateOperation, "sys/revoke-prefix/auth/token/renew/")
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
2018-03-20 18:54:10 +00:00
// Verify our token is still valid (e.g. we did not get invalidated by the revoke)
2016-08-24 19:59:43 +00:00
req = logical.TestRequest(t, logical.UpdateOperation, "auth/token/lookup")
req.Data = map[string]interface{}{
"token": newClient,
}
req.ClientToken = newClient
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Verify the token exists
if newClient != resp.Data["id"].(string) {
t.Fatalf("bad: return IDs: expected %v, got %v",
resp.Data["id"], newClient)
}
}
2015-05-16 00:19:41 +00:00
// Based on bug GH-203, attempt to disable a credential backend with leased secrets
func TestCore_EnableDisableCred_WithLease(t *testing.T) {
noopBack := &NoopBackend{
Login: []string{"login"},
Response: &logical.Response{
Auth: &logical.Auth{
Policies: []string{"root"},
},
},
2018-11-07 01:21:24 +00:00
BackendType: logical.TypeCredential,
2015-05-16 00:19:41 +00:00
}
2015-05-16 00:19:41 +00:00
c, _, root := TestCoreUnsealed(t)
c.credentialBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
2015-05-16 00:19:41 +00:00
return noopBack, nil
}
secretWritingPolicy := `
name = "admins"
path "secret/*" {
capabilities = ["update", "create", "read"]
}
`
ps := c.policyStore
2018-09-18 03:03:00 +00:00
policy, _ := ParseACLPolicy(namespace.RootNamespace, secretWritingPolicy)
if err := ps.SetPolicy(namespace.RootContext(nil), policy); err != nil {
t.Fatal(err)
}
2015-05-16 00:19:41 +00:00
// Enable the credential backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/auth/foo")
2015-05-16 00:19:41 +00:00
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-05-16 00:19:41 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to login -- should fail because we don't allow root to be returned
2015-05-16 00:19:41 +00:00
lreq := &logical.Request{
Path: "auth/foo/login",
}
2018-09-18 03:03:00 +00:00
lresp, err := c.HandleRequest(namespace.RootContext(nil), lreq)
if err == nil || lresp == nil || !lresp.IsError() {
t.Fatalf("expected error trying to auth and receive root policy")
}
// Fix and try again
noopBack.Response.Auth.Policies = []string{"admins"}
lreq = &logical.Request{
Path: "auth/foo/login",
}
2018-09-18 03:03:00 +00:00
lresp, err = c.HandleRequest(namespace.RootContext(nil), lreq)
2015-05-16 00:19:41 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Create a leasable secret
req = &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
2015-05-16 00:19:41 +00:00
Path: "secret/test",
Data: map[string]interface{}{
"foo": "bar",
"lease": "1h",
},
ClientToken: lresp.Auth.ClientToken,
}
2018-09-18 03:03:00 +00:00
resp, err := c.HandleRequest(namespace.RootContext(nil), req)
2015-05-16 00:19:41 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
// Read the key
req.Operation = logical.ReadOperation
req.Data = nil
err = c.PopulateTokenEntry(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %s", err)
}
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
2015-05-16 00:19:41 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
if resp == nil || resp.Secret == nil || resp.Secret.LeaseID == "" {
t.Fatalf("bad: %#v", resp.Secret)
}
2015-05-16 00:48:03 +00:00
// Renew the lease
req = logical.TestRequest(t, logical.UpdateOperation, "sys/leases/renew")
2016-09-29 04:01:28 +00:00
req.Data = map[string]interface{}{
"lease_id": resp.Secret.LeaseID,
}
2015-05-16 00:48:03 +00:00
req.ClientToken = lresp.Auth.ClientToken
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), req)
2015-05-16 00:48:03 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2015-05-16 00:19:41 +00:00
// Disable the credential backend
req = logical.TestRequest(t, logical.DeleteOperation, "sys/auth/foo")
req.ClientToken = root
2018-09-18 03:03:00 +00:00
resp, err = c.HandleRequest(namespace.RootContext(nil), req)
2015-05-16 00:19:41 +00:00
if err != nil {
t.Fatalf("err: %v %#v", err, resp)
}
}
Create unified aws auth backend (#2441) * Rename builtin/credential/aws-ec2 to aws The aws-ec2 authentication backend is being expanded and will become the generic aws backend. This is a small rename commit to keep the commit history clean. * Expand aws-ec2 backend to more generic aws This adds the ability to authenticate arbitrary AWS IAM principals using AWS's sts:GetCallerIdentity method. The AWS-EC2 auth backend is being to just AWS with the expansion. * Add missing aws auth handler to CLI This was omitted from the previous commit * aws auth backend general variable name cleanup Also fixed a bug where allowed auth types weren't being checked upon login, and added tests for it. * Update docs for the aws auth backend * Refactor aws bind validation * Fix env var override in aws backend test Intent is to override the AWS environment variables with the TEST_* versions if they are set, but the reverse was happening. * Update docs on use of IAM authentication profile AWS now allows you to change the instance profile of a running instance, so the use case of "a long-lived instance that's not in an instance profile" no longer means you have to use the the EC2 auth method. You can now just change the instance profile on the fly. * Fix typo in aws auth cli help * Respond to PR feedback * More PR feedback * Respond to additional PR feedback * Address more feedback on aws auth PR * Make aws auth_type immutable per role * Address more aws auth PR feedback * Address more iam auth PR feedback * Rename aws-ec2.html.md to aws.html.md Per PR feedback, to go along with new backend name. * Add MountType to logical.Request * Make default aws auth_type dependent upon MountType When MountType is aws-ec2, default to ec2 auth_type for backwards compatibility with legacy roles. Otherwise, default to iam. * Pass MountPoint and MountType back up to the core Previously the request router reset the MountPoint and MountType back to the empty string before returning to the core. This ensures they get set back to the correct values.
2017-04-24 19:15:50 +00:00
func TestCore_HandleRequest_MountPointType(t *testing.T) {
noop := &NoopBackend{
Response: &logical.Response{},
}
c, _, root := TestCoreUnsealed(t)
c.logicalBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the logical backend
2016-01-07 15:30:47 +00:00
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
req.Data["type"] = "noop"
req.Data["description"] = "foo"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to request
req = &logical.Request{
Operation: logical.ReadOperation,
Path: "foo/test",
Connection: &logical.Connection{},
}
req.ClientToken = root
2018-09-18 03:03:00 +00:00
if _, err := c.HandleRequest(namespace.RootContext(nil), req); err != nil {
t.Fatalf("err: %v", err)
}
Create unified aws auth backend (#2441) * Rename builtin/credential/aws-ec2 to aws The aws-ec2 authentication backend is being expanded and will become the generic aws backend. This is a small rename commit to keep the commit history clean. * Expand aws-ec2 backend to more generic aws This adds the ability to authenticate arbitrary AWS IAM principals using AWS's sts:GetCallerIdentity method. The AWS-EC2 auth backend is being to just AWS with the expansion. * Add missing aws auth handler to CLI This was omitted from the previous commit * aws auth backend general variable name cleanup Also fixed a bug where allowed auth types weren't being checked upon login, and added tests for it. * Update docs for the aws auth backend * Refactor aws bind validation * Fix env var override in aws backend test Intent is to override the AWS environment variables with the TEST_* versions if they are set, but the reverse was happening. * Update docs on use of IAM authentication profile AWS now allows you to change the instance profile of a running instance, so the use case of "a long-lived instance that's not in an instance profile" no longer means you have to use the the EC2 auth method. You can now just change the instance profile on the fly. * Fix typo in aws auth cli help * Respond to PR feedback * More PR feedback * Respond to additional PR feedback * Address more feedback on aws auth PR * Make aws auth_type immutable per role * Address more aws auth PR feedback * Address more iam auth PR feedback * Rename aws-ec2.html.md to aws.html.md Per PR feedback, to go along with new backend name. * Add MountType to logical.Request * Make default aws auth_type dependent upon MountType When MountType is aws-ec2, default to ec2 auth_type for backwards compatibility with legacy roles. Otherwise, default to iam. * Pass MountPoint and MountType back up to the core Previously the request router reset the MountPoint and MountType back to the empty string before returning to the core. This ensures they get set back to the correct values.
2017-04-24 19:15:50 +00:00
// Verify Path, MountPoint, and MountType
if noop.Requests[0].Path != "test" {
t.Fatalf("bad: %#v", noop.Requests)
}
if noop.Requests[0].MountPoint != "foo/" {
t.Fatalf("bad: %#v", noop.Requests)
}
Create unified aws auth backend (#2441) * Rename builtin/credential/aws-ec2 to aws The aws-ec2 authentication backend is being expanded and will become the generic aws backend. This is a small rename commit to keep the commit history clean. * Expand aws-ec2 backend to more generic aws This adds the ability to authenticate arbitrary AWS IAM principals using AWS's sts:GetCallerIdentity method. The AWS-EC2 auth backend is being to just AWS with the expansion. * Add missing aws auth handler to CLI This was omitted from the previous commit * aws auth backend general variable name cleanup Also fixed a bug where allowed auth types weren't being checked upon login, and added tests for it. * Update docs for the aws auth backend * Refactor aws bind validation * Fix env var override in aws backend test Intent is to override the AWS environment variables with the TEST_* versions if they are set, but the reverse was happening. * Update docs on use of IAM authentication profile AWS now allows you to change the instance profile of a running instance, so the use case of "a long-lived instance that's not in an instance profile" no longer means you have to use the the EC2 auth method. You can now just change the instance profile on the fly. * Fix typo in aws auth cli help * Respond to PR feedback * More PR feedback * Respond to additional PR feedback * Address more feedback on aws auth PR * Make aws auth_type immutable per role * Address more aws auth PR feedback * Address more iam auth PR feedback * Rename aws-ec2.html.md to aws.html.md Per PR feedback, to go along with new backend name. * Add MountType to logical.Request * Make default aws auth_type dependent upon MountType When MountType is aws-ec2, default to ec2 auth_type for backwards compatibility with legacy roles. Otherwise, default to iam. * Pass MountPoint and MountType back up to the core Previously the request router reset the MountPoint and MountType back to the empty string before returning to the core. This ensures they get set back to the correct values.
2017-04-24 19:15:50 +00:00
if noop.Requests[0].MountType != "noop" {
t.Fatalf("bad: %#v", noop.Requests)
}
}
2015-05-28 19:02:30 +00:00
func TestCore_Standby_Rotate(t *testing.T) {
// Create the first core and initialize it
logger = logging.NewVaultLogger(log.Trace)
2016-08-19 20:45:17 +00:00
inm, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
redirectOriginal := "http://127.0.0.1:8200"
core, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal,
DisableMlock: true,
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core.Shutdown()
2017-01-17 20:43:10 +00:00
keys, root := TestCoreInit(t, core)
for _, key := range keys {
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
// Wait for core to become active
TestWaitActive(t, core)
// Create a second core, attached to same in-memory store
redirectOriginal2 := "http://127.0.0.1:8500"
core2, err := NewCore(&CoreConfig{
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectOriginal2,
DisableMlock: true,
})
if err != nil {
t.Fatalf("err: %v", err)
}
defer core2.Shutdown()
2017-01-17 20:43:10 +00:00
for _, key := range keys {
if _, err := TestCoreUnseal(core2, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
// Rotate the encryption key
req := &logical.Request{
2016-01-07 15:30:47 +00:00
Operation: logical.UpdateOperation,
Path: "sys/rotate",
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
_, err = core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Seal the first core, should step down
err = core.Seal(root)
if err != nil {
t.Fatalf("err: %v", err)
}
// Wait for core2 to become active
TestWaitActive(t, core2)
// Read the key status
req = &logical.Request{
Operation: logical.ReadOperation,
Path: "sys/key-status",
ClientToken: root,
}
2018-09-18 03:03:00 +00:00
resp, err := core2.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Verify the response
if resp.Data["term"] != 2 {
t.Fatalf("bad: %#v", resp)
}
}
func TestCore_HandleRequest_Headers(t *testing.T) {
noop := &NoopBackend{
Response: &logical.Response{
Data: map[string]interface{}{},
},
}
c, _, root := TestCoreUnsealed(t)
c.logicalBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the backend
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
req.Data["type"] = "noop"
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Mount tune
req = logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo/tune")
req.Data["passthrough_request_headers"] = []string{"Should-Passthrough", "should-passthrough-case-insensitive"}
req.ClientToken = root
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to read
lreq := &logical.Request{
Operation: logical.ReadOperation,
Path: "foo/test",
ClientToken: root,
Headers: map[string][]string{
"Should-Passthrough": {"foo"},
"Should-Passthrough-Case-Insensitive": {"baz"},
"Should-Not-Passthrough": {"bar"},
consts.AuthHeaderName: {"nope"},
},
}
2018-09-18 03:03:00 +00:00
_, err = c.HandleRequest(namespace.RootContext(nil), lreq)
if err != nil {
t.Fatalf("err: %v", err)
}
// Check the headers
headers := noop.Requests[0].Headers
// Test passthrough values
if val, ok := headers["Should-Passthrough"]; ok {
expected := []string{"foo"}
if !reflect.DeepEqual(val, expected) {
t.Fatalf("expected: %v, got: %v", expected, val)
}
} else {
t.Fatalf("expected 'Should-Passthrough' to be present in the headers map")
}
if val, ok := headers["Should-Passthrough-Case-Insensitive"]; ok {
expected := []string{"baz"}
if !reflect.DeepEqual(val, expected) {
t.Fatalf("expected: %v, got: %v", expected, val)
}
} else {
2019-02-05 21:02:15 +00:00
t.Fatal("expected 'Should-Passthrough-Case-Insensitive' to be present in the headers map")
}
if _, ok := headers["Should-Not-Passthrough"]; ok {
2019-02-05 21:02:15 +00:00
t.Fatal("did not expect 'Should-Not-Passthrough' to be in the headers map")
}
if _, ok := headers[consts.AuthHeaderName]; ok {
t.Fatalf("did not expect %q to be in the headers map", consts.AuthHeaderName)
}
}
func TestCore_HandleRequest_Headers_denyList(t *testing.T) {
noop := &NoopBackend{
Response: &logical.Response{
Data: map[string]interface{}{},
},
}
c, _, root := TestCoreUnsealed(t)
c.logicalBackends["noop"] = func(context.Context, *logical.BackendConfig) (logical.Backend, error) {
return noop, nil
}
// Enable the backend
req := logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo")
req.Data["type"] = "noop"
req.ClientToken = root
_, err := c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Mount tune
req = logical.TestRequest(t, logical.UpdateOperation, "sys/mounts/foo/tune")
req.Data["passthrough_request_headers"] = []string{"Authorization", consts.AuthHeaderName}
req.ClientToken = root
_, err = c.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Attempt to read
lreq := &logical.Request{
Operation: logical.ReadOperation,
Path: "foo/test",
ClientToken: root,
Headers: map[string][]string{
consts.AuthHeaderName: {"foo"},
},
}
_, err = c.HandleRequest(namespace.RootContext(nil), lreq)
if err != nil {
t.Fatalf("err: %v", err)
}
// Check the headers
headers := noop.Requests[0].Headers
// Test passthrough values, they should not be present in the backend
if _, ok := headers[consts.AuthHeaderName]; ok {
t.Fatalf("did not expect %q to be in the headers map", consts.AuthHeaderName)
}
}
func TestCore_HandleRequest_TokenCreate_RegisterAuthFailure(t *testing.T) {
core, _, root := TestCoreUnsealed(t)
// Create a root token and use that for subsequent requests
req := logical.TestRequest(t, logical.CreateOperation, "auth/token/create")
req.Data = map[string]interface{}{
"policies": []string{"root"},
}
req.ClientToken = root
resp, err := core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatal(err)
}
if resp == nil || resp.Auth == nil || resp.Auth.ClientToken == "" {
t.Fatalf("expected a response from token creation, got: %#v", resp)
}
tokenWithRootPolicy := resp.Auth.ClientToken
// Use new token to create yet a new token, this should succeed
req = logical.TestRequest(t, logical.CreateOperation, "auth/token/create")
req.ClientToken = tokenWithRootPolicy
_, err = core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatal(err)
}
// Try again but force failure on RegisterAuth to simulate a network failure
// when registering the lease (e.g. a storage failure). This should trigger
// an expiration manager cleanup on the newly created token
core.expiration.testRegisterAuthFailure.Store(true)
req = logical.TestRequest(t, logical.CreateOperation, "auth/token/create")
req.ClientToken = tokenWithRootPolicy
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
if err == nil {
t.Fatalf("expected error, got a response: %#v", resp)
}
core.expiration.testRegisterAuthFailure.Store(false)
// Do a lookup against the client token that we used for the failed request.
// It should still be present
req = logical.TestRequest(t, logical.UpdateOperation, "auth/token/lookup")
req.Data = map[string]interface{}{
"token": tokenWithRootPolicy,
}
req.ClientToken = root
_, err = core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatal(err)
}
// Do a token creation request with the token to ensure that it's still
// valid, should succeed.
req = logical.TestRequest(t, logical.CreateOperation, "auth/token/create")
req.ClientToken = tokenWithRootPolicy
resp, err = core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatal(err)
}
}
// mockServiceRegistration helps test whether standalone ServiceRegistration works
type mockServiceRegistration struct {
notifyActiveCount int
notifySealedCount int
notifyPerfCount int
notifyInitCount int
runDiscoveryCount int
}
func (m *mockServiceRegistration) Run(shutdownCh <-chan struct{}, wait *sync.WaitGroup, redirectAddr string) error {
m.runDiscoveryCount++
return nil
}
func (m *mockServiceRegistration) NotifyActiveStateChange(isActive bool) error {
m.notifyActiveCount++
return nil
}
func (m *mockServiceRegistration) NotifySealedStateChange(isSealed bool) error {
m.notifySealedCount++
return nil
}
func (m *mockServiceRegistration) NotifyPerformanceStandbyStateChange(isStandby bool) error {
m.notifyPerfCount++
return nil
}
func (m *mockServiceRegistration) NotifyInitializedStateChange(isInitialized bool) error {
m.notifyInitCount++
return nil
}
// TestCore_ServiceRegistration tests whether standalone ServiceRegistration works
func TestCore_ServiceRegistration(t *testing.T) {
// Make a mock service discovery
sr := &mockServiceRegistration{}
// Create the core
logger = logging.NewVaultLogger(log.Trace)
inm, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
inmha, err := inmem.NewInmemHA(nil, logger)
if err != nil {
t.Fatal(err)
}
const redirectAddr = "http://127.0.0.1:8200"
core, err := NewCore(&CoreConfig{
ServiceRegistration: sr,
Physical: inm,
HAPhysical: inmha.(physical.HABackend),
RedirectAddr: redirectAddr,
DisableMlock: true,
})
if err != nil {
t.Fatal(err)
}
defer core.Shutdown()
// Vault should not yet be registered
if diff := deep.Equal(sr, &mockServiceRegistration{}); diff != nil {
t.Fatal(diff)
}
// Vault should be registered
if diff := deep.Equal(sr, &mockServiceRegistration{
runDiscoveryCount: 1,
}); diff != nil {
t.Fatal(diff)
}
// Initialize and unseal the core
keys, _ := TestCoreInit(t, core)
for _, key := range keys {
if _, err := TestCoreUnseal(core, TestKeyCopy(key)); err != nil {
t.Fatalf("unseal err: %s", err)
}
}
if core.Sealed() {
t.Fatal("should not be sealed")
}
// Wait for core to become active
TestWaitActive(t, core)
// Vault should be registered, unsealed, and active
if diff := deep.Equal(sr, &mockServiceRegistration{
runDiscoveryCount: 1,
notifyActiveCount: 1,
notifySealedCount: 1,
notifyInitCount: 1,
}); diff != nil {
t.Fatal(diff)
}
}
func TestDetectedDeadlock(t *testing.T) {
testCore, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{DetectDeadlocks: "statelock"})
InduceDeadlock(t, testCore, 1)
}
func TestDefaultDeadlock(t *testing.T) {
testCore, _, _ := TestCoreUnsealed(t)
InduceDeadlock(t, testCore, 0)
}
func RestoreDeadlockOpts() func() {
opts := deadlock.Opts
return func() {
deadlock.Opts = opts
}
}
func InduceDeadlock(t *testing.T, vaultcore *Core, expected uint32) {
defer RestoreDeadlockOpts()()
var deadlocks uint32
deadlock.Opts.OnPotentialDeadlock = func() {
atomic.AddUint32(&deadlocks, 1)
}
var mtx deadlock.Mutex
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
vaultcore.expiration.coreStateLock.Lock()
mtx.Lock()
mtx.Unlock()
vaultcore.expiration.coreStateLock.Unlock()
}()
wg.Wait()
wg.Add(1)
go func() {
defer wg.Done()
mtx.Lock()
vaultcore.expiration.coreStateLock.RLock()
vaultcore.expiration.coreStateLock.RUnlock()
mtx.Unlock()
}()
wg.Wait()
if atomic.LoadUint32(&deadlocks) != expected {
t.Fatalf("expected 1 deadlock, detected %d", deadlocks)
}
}
func TestExpiration_DeadlockDetection(t *testing.T) {
testCore := TestCore(t)
testCoreUnsealed(t, testCore)
if testCore.expiration.DetectDeadlocks() {
t.Fatal("expiration has deadlock detection enabled, it shouldn't")
}
testCore = TestCoreWithDeadlockDetection(t, nil, false)
testCoreUnsealed(t, testCore)
if !testCore.expiration.DetectDeadlocks() {
t.Fatal("expiration doesn't have deadlock detection enabled, it should")
}
}
func TestQuotas_DeadlockDetection(t *testing.T) {
testCore := TestCore(t)
testCoreUnsealed(t, testCore)
if testCore.quotaManager.DetectDeadlocks() {
t.Fatal("quotas has deadlock detection enabled, it shouldn't")
}
testCore = TestCoreWithDeadlockDetection(t, nil, false)
testCoreUnsealed(t, testCore)
if !testCore.quotaManager.DetectDeadlocks() {
t.Fatal("quotas doesn't have deadlock detection enabled, it should")
}
}
func TestStatelock_DeadlockDetection(t *testing.T) {
testCore := TestCore(t)
testCoreUnsealed(t, testCore)
if testCore.DetectStateLockDeadlocks() {
t.Fatal("statelock has deadlock detection enabled, it shouldn't")
}
testCore = TestCoreWithDeadlockDetection(t, nil, false)
testCoreUnsealed(t, testCore)
if !testCore.DetectStateLockDeadlocks() {
t.Fatal("statelock doesn't have deadlock detection enabled, it should")
}
}