2023-03-15 16:00:52 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2015-03-15 21:42:05 +00:00
package vault
import (
2018-01-08 18:31:38 +00:00
"context"
2017-10-20 14:59:17 +00:00
"encoding/base64"
2017-04-12 17:39:18 +00:00
"encoding/hex"
"fmt"
"io/ioutil"
2020-05-27 18:28:00 +00:00
"net/http"
2017-04-12 17:39:18 +00:00
"os"
"path/filepath"
2015-03-15 21:42:05 +00:00
"reflect"
2016-04-19 20:26:26 +00:00
"strings"
2015-03-15 21:42:05 +00:00
"testing"
2015-08-31 18:27:49 +00:00
"time"
2015-03-15 21:42:05 +00:00
2015-09-01 22:29:30 +00:00
"github.com/fatih/structs"
2018-10-15 16:56:24 +00:00
"github.com/go-test/deep"
2022-08-31 18:23:05 +00:00
"github.com/hashicorp/go-hclog"
2022-08-25 20:31:42 +00:00
semver "github.com/hashicorp/go-version"
2022-02-18 16:04:21 +00:00
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
2017-04-12 17:39:18 +00:00
"github.com/hashicorp/vault/helper/builtinplugins"
2023-01-16 16:07:18 +00:00
"github.com/hashicorp/vault/helper/experiments"
2019-04-10 21:46:17 +00:00
"github.com/hashicorp/vault/helper/identity"
2018-09-18 03:03:00 +00:00
"github.com/hashicorp/vault/helper/namespace"
2020-06-17 20:24:38 +00:00
"github.com/hashicorp/vault/helper/random"
2023-02-01 13:33:16 +00:00
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
"github.com/hashicorp/vault/helper/versions"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/sdk/framework"
2022-01-20 12:52:53 +00:00
"github.com/hashicorp/vault/sdk/helper/compressutil"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
2022-08-25 20:31:42 +00:00
"github.com/hashicorp/vault/sdk/helper/pluginutil"
2023-01-20 16:09:33 +00:00
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/logical"
2022-12-07 18:29:51 +00:00
"github.com/hashicorp/vault/version"
2017-05-04 02:03:42 +00:00
"github.com/mitchellh/mapstructure"
2015-03-15 21:42:05 +00:00
)
func TestSystemBackend_RootPaths ( t * testing . T ) {
expected := [ ] string {
2015-03-20 19:48:19 +00:00
"auth/*" ,
2015-03-15 21:42:05 +00:00
"remount" ,
2015-03-31 23:45:00 +00:00
"audit" ,
"audit/*" ,
2017-09-15 04:21:35 +00:00
"raw" ,
2015-04-02 00:44:43 +00:00
"raw/*" ,
2017-02-17 04:36:06 +00:00
"replication/primary/secondary-token" ,
2018-09-18 03:03:00 +00:00
"replication/performance/primary/secondary-token" ,
"replication/dr/primary/secondary-token" ,
2017-02-17 04:36:06 +00:00
"replication/reindex" ,
2018-09-18 03:03:00 +00:00
"replication/dr/reindex" ,
"replication/performance/reindex" ,
2015-05-28 00:53:42 +00:00
"rotate" ,
2017-06-17 05:51:42 +00:00
"config/cors" ,
2017-02-02 19:49:20 +00:00
"config/auditing/*" ,
2018-04-03 18:07:43 +00:00
"config/ui/headers/*" ,
2017-04-24 19:47:40 +00:00
"plugins/catalog/*" ,
2017-05-04 02:03:42 +00:00
"revoke-prefix/*" ,
2017-07-25 15:59:43 +00:00
"revoke-force/*" ,
2017-05-04 02:03:42 +00:00
"leases/revoke-prefix/*" ,
"leases/revoke-force/*" ,
"leases/lookup/*" ,
2020-10-16 18:57:11 +00:00
"storage/raft/snapshot-auto/config/*" ,
2021-06-28 22:51:47 +00:00
"leases" ,
2022-11-04 16:39:09 +00:00
"internal/inspect/*" ,
2015-03-15 21:42:05 +00:00
}
b := testSystemBackend ( t )
2015-03-31 00:46:18 +00:00
actual := b . SpecialPaths ( ) . Root
2015-03-15 21:42:05 +00:00
if ! reflect . DeepEqual ( actual , expected ) {
2018-04-03 18:07:43 +00:00
t . Fatalf ( "bad: mismatch\nexpected:\n%#v\ngot:\n%#v" , expected , actual )
2015-03-15 21:42:05 +00:00
}
}
2017-06-17 04:04:55 +00:00
func TestSystemConfigCORS ( t * testing . T ) {
b := testSystemBackend ( t )
2023-02-16 20:06:26 +00:00
paths := b . ( * SystemBackend ) . configPaths ( )
2017-06-17 05:26:25 +00:00
_ , barrier , _ := mockBarrier ( t )
view := NewBarrierView ( barrier , "" )
b . ( * SystemBackend ) . Core . systemBarrierView = view
2017-06-17 04:04:55 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "config/cors" )
req . Data [ "allowed_origins" ] = "http://www.example.com"
2017-08-07 14:03:30 +00:00
req . Data [ "allowed_headers" ] = "X-Custom-Header"
2018-11-05 16:11:32 +00:00
_ , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-06-17 04:04:55 +00:00
if err != nil {
t . Fatal ( err )
}
expected := & logical . Response {
Data : map [ string ] interface { } {
"enabled" : true ,
2017-06-17 05:26:25 +00:00
"allowed_origins" : [ ] string { "http://www.example.com" } ,
2017-08-07 19:02:08 +00:00
"allowed_headers" : append ( StdAllowedHeaders , "X-Custom-Header" ) ,
2017-06-17 04:04:55 +00:00
} ,
}
req = logical . TestRequest ( t , logical . ReadOperation , "config/cors" )
2018-11-05 16:11:32 +00:00
actual , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-06-17 04:04:55 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if ! reflect . DeepEqual ( actual , expected ) {
2017-06-17 05:26:25 +00:00
t . Fatalf ( "bad: %#v" , actual )
2017-06-17 04:04:55 +00:00
}
2023-02-16 20:06:26 +00:00
schema . ValidateResponse (
t ,
schema . FindResponseSchema ( t , paths , 0 , req . Operation ) ,
actual ,
true ,
)
2017-06-17 04:04:55 +00:00
2019-02-11 18:10:26 +00:00
// Do it again. Bug #6182
req = logical . TestRequest ( t , logical . UpdateOperation , "config/cors" )
req . Data [ "allowed_origins" ] = "http://www.example.com"
req . Data [ "allowed_headers" ] = "X-Custom-Header"
2023-02-16 20:06:26 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2019-02-11 18:10:26 +00:00
if err != nil {
t . Fatal ( err )
}
2023-02-16 20:06:26 +00:00
schema . ValidateResponse (
t ,
schema . FindResponseSchema ( t , paths , 0 , req . Operation ) ,
resp ,
true ,
)
2019-02-11 18:10:26 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "config/cors" )
actual , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-16 20:06:26 +00:00
schema . ValidateResponse (
t ,
schema . FindResponseSchema ( t , paths , 0 , req . Operation ) ,
actual ,
true ,
)
2019-02-11 18:10:26 +00:00
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "bad: %#v" , actual )
}
2017-06-17 04:04:55 +00:00
req = logical . TestRequest ( t , logical . DeleteOperation , "config/cors" )
2023-02-16 20:06:26 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-06-17 04:04:55 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-16 20:06:26 +00:00
schema . ValidateResponse (
t ,
schema . FindResponseSchema ( t , paths , 0 , req . Operation ) ,
resp ,
true ,
)
2017-06-17 04:04:55 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "config/cors" )
2018-11-05 16:11:32 +00:00
actual , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-06-17 04:04:55 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-16 20:06:26 +00:00
schema . ValidateResponse (
t ,
schema . FindResponseSchema ( t , paths , 0 , req . Operation ) ,
actual ,
true ,
)
2017-06-17 04:04:55 +00:00
expected = & logical . Response {
Data : map [ string ] interface { } {
2017-06-17 05:26:25 +00:00
"enabled" : false ,
2017-06-17 04:04:55 +00:00
} ,
}
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "DELETE FAILED -- bad: %#v" , actual )
}
}
2015-03-15 21:42:05 +00:00
func TestSystemBackend_mounts ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "mounts" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-15 21:42:05 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2015-09-01 22:29:30 +00:00
// We can't know the pointer address ahead of time so simply
// copy what's given
2015-03-15 21:42:05 +00:00
exp := map [ string ] interface { } {
2015-08-31 18:27:49 +00:00
"secret/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "kv" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "key/value secret storage" ,
"accessor" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2015-08-31 18:27:49 +00:00
"config" : map [ string ] interface { } {
2016-06-21 00:08:12 +00:00
"default_lease_ttl" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
2017-03-08 14:20:09 +00:00
"force_no_cache" : false ,
2015-08-31 18:27:49 +00:00
} ,
2017-11-13 16:22:22 +00:00
"local" : false ,
"seal_wrap" : false ,
2018-03-21 19:04:27 +00:00
"options" : map [ string ] string {
2018-04-09 20:14:44 +00:00
"version" : "1" ,
2018-03-21 19:04:27 +00:00
} ,
2022-09-20 11:35:50 +00:00
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "kv" ) ,
"running_sha256" : "" ,
2015-03-15 21:42:05 +00:00
} ,
2015-08-31 18:27:49 +00:00
"sys/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "system" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "system endpoints used for control, policy and debugging" ,
"accessor" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2015-08-31 18:27:49 +00:00
"config" : map [ string ] interface { } {
2019-02-20 20:12:21 +00:00
"default_lease_ttl" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
2019-02-15 19:14:45 +00:00
"passthrough_request_headers" : [ ] string { "Accept" } ,
2015-08-31 18:27:49 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : true ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . DefaultBuiltinVersion ,
"running_sha256" : "" ,
2015-03-15 21:42:05 +00:00
} ,
2015-09-10 01:58:09 +00:00
"cubbyhole/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "per-token private secret storage" ,
"type" : "cubbyhole" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2015-09-10 01:58:09 +00:00
"config" : map [ string ] interface { } {
2016-06-21 00:08:12 +00:00
"default_lease_ttl" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
2017-03-08 14:20:09 +00:00
"force_no_cache" : false ,
2015-09-10 01:58:09 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : true ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "cubbyhole" ) ,
"running_sha256" : "" ,
2015-09-10 01:58:09 +00:00
} ,
2017-10-11 17:21:20 +00:00
"identity/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "identity store" ,
"type" : "identity" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-10-11 17:21:20 +00:00
"config" : map [ string ] interface { } {
2021-10-14 01:59:36 +00:00
"default_lease_ttl" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
"passthrough_request_headers" : [ ] string { "Authorization" } ,
2017-10-11 17:21:20 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "identity" ) ,
"running_sha256" : "" ,
2017-10-11 17:21:20 +00:00
} ,
2015-03-15 21:42:05 +00:00
}
2019-02-15 19:14:45 +00:00
if diff := deep . Equal ( resp . Data , exp ) ; len ( diff ) > 0 {
t . Fatalf ( "bad, diff: %#v" , diff )
2015-03-15 21:42:05 +00:00
}
2021-11-08 18:32:01 +00:00
for name , conf := range exp {
req := logical . TestRequest ( t , logical . ReadOperation , "mounts/" + name )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if diff := deep . Equal ( resp . Data , conf ) ; len ( diff ) > 0 {
t . Fatalf ( "bad, diff: %#v" , diff )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for mount named read
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2021-11-08 18:32:01 +00:00
}
2015-03-15 21:42:05 +00:00
}
func TestSystemBackend_mount ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "mounts/prod/secret/" )
2017-09-15 13:02:29 +00:00
req . Data [ "type" ] = "kv"
2018-02-22 15:26:29 +00:00
req . Data [ "config" ] = map [ string ] interface { } {
"default_lease_ttl" : "35m" ,
"max_lease_ttl" : "45m" ,
}
2017-11-13 16:22:22 +00:00
req . Data [ "local" ] = true
req . Data [ "seal_wrap" ] = true
2018-03-21 19:04:27 +00:00
req . Data [ "options" ] = map [ string ] string {
2018-04-09 20:14:44 +00:00
"version" : "1" ,
2018-03-21 19:04:27 +00:00
}
2015-03-15 21:42:05 +00:00
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-15 21:42:05 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for mount named update
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-11-13 16:22:22 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "mounts" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-11-13 16:22:22 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
// We can't know the pointer address ahead of time so simply
// copy what's given
exp := map [ string ] interface { } {
"secret/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "kv" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "key/value secret storage" ,
"accessor" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
"default_lease_ttl" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "secret/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
} ,
"local" : false ,
"seal_wrap" : false ,
2018-03-21 19:04:27 +00:00
"options" : map [ string ] string {
2018-04-09 20:14:44 +00:00
"version" : "1" ,
2018-03-21 19:04:27 +00:00
} ,
2022-09-20 11:35:50 +00:00
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "kv" ) ,
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
"sys/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "system" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "system endpoints used for control, policy and debugging" ,
"accessor" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
2019-02-20 20:12:21 +00:00
"default_lease_ttl" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "sys/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
2019-02-15 19:14:45 +00:00
"passthrough_request_headers" : [ ] string { "Accept" } ,
2017-11-13 16:22:22 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : true ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . DefaultBuiltinVersion ,
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
"cubbyhole/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "per-token private secret storage" ,
"type" : "cubbyhole" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
"default_lease_ttl" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
} ,
2022-09-20 11:35:50 +00:00
"local" : true ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "cubbyhole" ) ,
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
"identity/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "identity store" ,
"type" : "identity" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
2021-10-14 01:59:36 +00:00
"default_lease_ttl" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "identity/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
"passthrough_request_headers" : [ ] string { "Authorization" } ,
2017-11-13 16:22:22 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "identity" ) ,
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
"prod/secret/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "" ,
"type" : "kv" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "prod/secret/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "prod/secret/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
2018-02-22 15:26:29 +00:00
"default_lease_ttl" : int64 ( 2100 ) ,
"max_lease_ttl" : int64 ( 2700 ) ,
2017-11-13 16:22:22 +00:00
"force_no_cache" : false ,
} ,
"local" : true ,
"seal_wrap" : true ,
2018-03-21 19:04:27 +00:00
"options" : map [ string ] string {
2018-04-09 20:14:44 +00:00
"version" : "1" ,
2018-03-21 19:04:27 +00:00
} ,
2022-09-20 11:35:50 +00:00
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "kv" ) ,
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
}
2019-02-15 19:14:45 +00:00
if diff := deep . Equal ( resp . Data , exp ) ; len ( diff ) > 0 {
t . Fatalf ( "bad: diff: %#v" , diff )
2017-11-13 16:22:22 +00:00
}
2015-03-15 21:42:05 +00:00
}
2017-03-08 14:20:09 +00:00
func TestSystemBackend_mount_force_no_cache ( t * testing . T ) {
core , b , _ := testCoreSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "mounts/prod/secret/" )
2017-09-15 13:02:29 +00:00
req . Data [ "type" ] = "kv"
2017-03-08 14:20:09 +00:00
req . Data [ "config" ] = map [ string ] interface { } {
"force_no_cache" : true ,
}
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-03-08 14:20:09 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2018-11-05 16:11:32 +00:00
mountEntry := core . router . MatchingMountEntry ( namespace . RootContext ( nil ) , "prod/secret/" )
2017-03-08 14:20:09 +00:00
if mountEntry == nil {
t . Fatalf ( "missing mount entry" )
}
if ! mountEntry . Config . ForceNoCache {
t . Fatalf ( "bad config %#v" , mountEntry )
}
}
2015-03-15 21:42:05 +00:00
func TestSystemBackend_mount_invalid ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "mounts/prod/secret/" )
2015-03-15 21:42:05 +00:00
req . Data [ "type" ] = "nope"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-15 21:53:41 +00:00
if err != logical . ErrInvalidRequest {
2015-03-15 21:42:05 +00:00
t . Fatalf ( "err: %v" , err )
}
2018-11-07 01:21:24 +00:00
if resp . Data [ "error" ] != ` plugin not found in the catalog: nope ` {
2015-03-15 21:42:05 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
func TestSystemBackend_unmount ( t * testing . T ) {
b := testSystemBackend ( t )
2015-03-16 17:52:35 +00:00
req := logical . TestRequest ( t , logical . DeleteOperation , "mounts/secret/" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-15 21:42:05 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for mount named delete
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-15 21:42:05 +00:00
}
2016-03-18 15:58:06 +00:00
var capabilitiesPolicy = `
name = "test"
path "foo/bar*" {
capabilities = [ "create" , "sudo" , "update" ]
}
path "sys/capabilities*" {
capabilities = [ "update" ]
}
2018-03-01 16:14:56 +00:00
path "bar/baz" {
capabilities = [ "read" , "update" ]
}
path "bar/baz" {
capabilities = [ "delete" ]
}
2016-03-18 15:58:06 +00:00
`
2018-03-01 16:14:56 +00:00
func TestSystemBackend_PathCapabilities ( t * testing . T ) {
var resp * logical . Response
var err error
core , b , rootToken := testCoreSystemBackend ( t )
2018-09-18 03:03:00 +00:00
policy , _ := ParseACLPolicy ( namespace . RootNamespace , capabilitiesPolicy )
2018-11-05 16:11:32 +00:00
err = core . policyStore . SetPolicy ( namespace . RootContext ( nil ) , policy )
2018-03-01 16:14:56 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
path1 := "foo/bar"
path2 := "foo/bar/sample"
path3 := "sys/capabilities"
path4 := "bar/baz"
rootCheckFunc := func ( t * testing . T , resp * logical . Response ) {
// All the paths should have "root" as the capability
expectedRoot := [ ] string { "root" }
if ! reflect . DeepEqual ( resp . Data [ path1 ] , expectedRoot ) ||
! reflect . DeepEqual ( resp . Data [ path2 ] , expectedRoot ) ||
! reflect . DeepEqual ( resp . Data [ path3 ] , expectedRoot ) ||
! reflect . DeepEqual ( resp . Data [ path4 ] , expectedRoot ) {
t . Fatalf ( "bad: capabilities; expected: %#v, actual: %#v" , expectedRoot , resp . Data )
}
}
// Check the capabilities using the root token
2023-02-16 20:04:37 +00:00
req := & logical . Request {
2018-03-01 16:14:56 +00:00
Path : "capabilities" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"paths" : [ ] string { path1 , path2 , path3 , path4 } ,
"token" : rootToken ,
} ,
2023-02-16 20:04:37 +00:00
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-01 16:14:56 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: resp: %#v\nerr: %v" , resp , err )
}
2023-02-16 20:04:37 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-01 16:14:56 +00:00
rootCheckFunc ( t , resp )
// Check the capabilities using capabilities-self
2023-02-16 20:04:37 +00:00
req = & logical . Request {
2018-03-01 16:14:56 +00:00
ClientToken : rootToken ,
Path : "capabilities-self" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"paths" : [ ] string { path1 , path2 , path3 , path4 } ,
} ,
2023-02-16 20:04:37 +00:00
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-01 16:14:56 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: resp: %#v\nerr: %v" , resp , err )
}
2023-02-16 20:04:37 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-01 16:14:56 +00:00
rootCheckFunc ( t , resp )
// Lookup the accessor of the root token
2018-11-05 16:11:32 +00:00
te , err := core . tokenStore . Lookup ( namespace . RootContext ( nil ) , rootToken )
2018-03-01 16:14:56 +00:00
if err != nil {
t . Fatal ( err )
}
// Check the capabilities using capabilities-accessor endpoint
2023-02-16 20:04:37 +00:00
req = & logical . Request {
2018-03-01 16:14:56 +00:00
Path : "capabilities-accessor" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"paths" : [ ] string { path1 , path2 , path3 , path4 } ,
"accessor" : te . Accessor ,
} ,
2023-02-16 20:04:37 +00:00
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-01 16:14:56 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: resp: %#v\nerr: %v" , resp , err )
}
2023-02-16 20:04:37 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-01 16:14:56 +00:00
rootCheckFunc ( t , resp )
// Create a non-root token
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaBackend ( t , core . tokenStore , rootToken , "tokenid" , "" , [ ] string { "test" } )
2018-03-01 16:14:56 +00:00
nonRootCheckFunc := func ( t * testing . T , resp * logical . Response ) {
expected1 := [ ] string { "create" , "sudo" , "update" }
expected2 := expected1
expected3 := [ ] string { "update" }
expected4 := [ ] string { "delete" , "read" , "update" }
if ! reflect . DeepEqual ( resp . Data [ path1 ] , expected1 ) ||
! reflect . DeepEqual ( resp . Data [ path2 ] , expected2 ) ||
! reflect . DeepEqual ( resp . Data [ path3 ] , expected3 ) ||
! reflect . DeepEqual ( resp . Data [ path4 ] , expected4 ) {
t . Fatalf ( "bad: capabilities; actual: %#v" , resp . Data )
}
}
// Check the capabilities using a non-root token
2023-02-16 20:04:37 +00:00
req = & logical . Request {
2018-03-01 16:14:56 +00:00
Path : "capabilities" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"paths" : [ ] string { path1 , path2 , path3 , path4 } ,
"token" : "tokenid" ,
} ,
2023-02-16 20:04:37 +00:00
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-01 16:14:56 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: resp: %#v\nerr: %v" , resp , err )
}
2023-02-16 20:04:37 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-01 16:14:56 +00:00
nonRootCheckFunc ( t , resp )
// Check the capabilities of a non-root token using capabilities-self
// endpoint
2023-02-16 20:04:37 +00:00
req = & logical . Request {
2018-03-01 16:14:56 +00:00
ClientToken : "tokenid" ,
Path : "capabilities-self" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"paths" : [ ] string { path1 , path2 , path3 , path4 } ,
} ,
2023-02-16 20:04:37 +00:00
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-01 16:14:56 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: resp: %#v\nerr: %v" , resp , err )
}
2023-02-16 20:04:37 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-01 16:14:56 +00:00
nonRootCheckFunc ( t , resp )
// Lookup the accessor of the non-root token
2018-11-05 16:11:32 +00:00
te , err = core . tokenStore . Lookup ( namespace . RootContext ( nil ) , "tokenid" )
2018-03-01 16:14:56 +00:00
if err != nil {
t . Fatal ( err )
}
// Check the capabilities using a non-root token using
// capabilities-accessor endpoint
2023-02-16 20:04:37 +00:00
req = & logical . Request {
2018-03-01 16:14:56 +00:00
Path : "capabilities-accessor" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"paths" : [ ] string { path1 , path2 , path3 , path4 } ,
"accessor" : te . Accessor ,
} ,
2023-02-16 20:04:37 +00:00
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-01 16:14:56 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: resp: %#v\nerr: %v" , resp , err )
}
2023-02-16 20:04:37 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-01 16:14:56 +00:00
nonRootCheckFunc ( t , resp )
}
func TestSystemBackend_Capabilities_BC ( t * testing . T ) {
2016-03-18 15:58:06 +00:00
testCapabilities ( t , "capabilities" )
testCapabilities ( t , "capabilities-self" )
}
func testCapabilities ( t * testing . T , endpoint string ) {
core , b , rootToken := testCoreSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , endpoint )
2018-03-01 16:14:56 +00:00
if endpoint == "capabilities-self" {
req . ClientToken = rootToken
} else {
req . Data [ "token" ] = rootToken
}
2016-03-18 15:58:06 +00:00
req . Data [ "path" ] = "any_path"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatalf ( "bad: %v" , resp )
}
actual := resp . Data [ "capabilities" ]
expected := [ ] string { "root" }
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "bad: got\n%#v\nexpected\n%#v\n" , actual , expected )
}
2018-09-18 03:03:00 +00:00
policy , _ := ParseACLPolicy ( namespace . RootNamespace , capabilitiesPolicy )
2018-11-05 16:11:32 +00:00
err = core . policyStore . SetPolicy ( namespace . RootContext ( nil ) , policy )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaBackend ( t , core . tokenStore , rootToken , "tokenid" , "" , [ ] string { "test" } )
2016-03-18 15:58:06 +00:00
req = logical . TestRequest ( t , logical . UpdateOperation , endpoint )
2018-03-01 16:14:56 +00:00
if endpoint == "capabilities-self" {
req . ClientToken = "tokenid"
} else {
req . Data [ "token" ] = "tokenid"
}
2016-03-18 15:58:06 +00:00
req . Data [ "path" ] = "foo/bar"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatalf ( "bad: %v" , resp )
}
actual = resp . Data [ "capabilities" ]
2016-03-18 16:40:17 +00:00
expected = [ ] string { "create" , "sudo" , "update" }
2016-03-18 15:58:06 +00:00
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "bad: got\n%#v\nexpected\n%#v\n" , actual , expected )
}
}
2018-03-01 16:14:56 +00:00
func TestSystemBackend_CapabilitiesAccessor_BC ( t * testing . T ) {
2016-03-18 15:58:06 +00:00
core , b , rootToken := testCoreSystemBackend ( t )
2018-11-05 16:11:32 +00:00
te , err := core . tokenStore . Lookup ( namespace . RootContext ( nil ) , rootToken )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatal ( err )
}
2016-03-18 14:37:49 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "capabilities-accessor" )
2016-03-18 15:58:06 +00:00
// Accessor of root token
req . Data [ "accessor" ] = te . Accessor
req . Data [ "path" ] = "any_path"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-03-18 14:37:49 +00:00
if err != nil {
2016-03-18 15:58:06 +00:00
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatalf ( "bad: %v" , resp )
}
actual := resp . Data [ "capabilities" ]
expected := [ ] string { "root" }
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "bad: got\n%#v\nexpected\n%#v\n" , actual , expected )
}
2018-09-18 03:03:00 +00:00
policy , _ := ParseACLPolicy ( namespace . RootNamespace , capabilitiesPolicy )
2018-11-05 16:11:32 +00:00
err = core . policyStore . SetPolicy ( namespace . RootContext ( nil ) , policy )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaBackend ( t , core . tokenStore , rootToken , "tokenid" , "" , [ ] string { "test" } )
2016-03-18 15:58:06 +00:00
2018-11-05 16:11:32 +00:00
te , err = core . tokenStore . Lookup ( namespace . RootContext ( nil ) , "tokenid" )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatal ( err )
}
req = logical . TestRequest ( t , logical . UpdateOperation , "capabilities-accessor" )
req . Data [ "accessor" ] = te . Accessor
req . Data [ "path" ] = "foo/bar"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-03-18 15:58:06 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatalf ( "bad: %v" , resp )
}
actual = resp . Data [ "capabilities" ]
2016-03-18 16:40:17 +00:00
expected = [ ] string { "create" , "sudo" , "update" }
2016-03-18 15:58:06 +00:00
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "bad: got\n%#v\nexpected\n%#v\n" , actual , expected )
2016-03-18 14:37:49 +00:00
}
}
2022-02-18 16:04:21 +00:00
func TestSystemBackend_remount_auth ( t * testing . T ) {
err := AddTestCredentialBackend ( "userpass" , credUserpass . Factory )
if err != nil {
t . Fatal ( err )
}
c , b , _ := testCoreSystemBackend ( t )
userpassMe := & MountEntry {
Table : credentialTableType ,
Path : "userpass1/" ,
Type : "userpass" ,
Description : "userpass" ,
}
err = c . enableCredential ( namespace . RootContext ( nil ) , userpassMe )
if err != nil {
t . Fatal ( err )
}
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "auth/userpass1"
req . Data [ "to" ] = "auth/userpass2"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2023-02-15 20:02:21 +00:00
// validate the response structure for remount named read
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2023-02-01 13:33:16 +00:00
corehelpers . RetryUntil ( t , 5 * time . Second , func ( ) error {
2022-02-18 16:04:21 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , fmt . Sprintf ( "remount/status/%s" , resp . Data [ "migration_id" ] ) )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:02:21 +00:00
// validate the response structure for remount status read
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-02-18 16:04:21 +00:00
migrationInfo := resp . Data [ "migration_info" ] . ( * MountMigrationInfo )
if migrationInfo . MigrationStatus != MigrationSuccessStatus . String ( ) {
return fmt . Errorf ( "Expected migration status to be successful, got %q" , migrationInfo . MigrationStatus )
}
return nil
} )
}
func TestSystemBackend_remount_auth_invalid ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "auth/unknown"
req . Data [ "to" ] = "auth/foo"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "no matching mount at \"auth/unknown/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
req . Data [ "to" ] = "foo"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "cannot remount auth mount to non-auth mount \"foo/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
}
func TestSystemBackend_remount_auth_protected ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "auth/token"
req . Data [ "to" ] = "auth/foo"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "cannot remount \"auth/token/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
req . Data [ "from" ] = "auth/foo"
req . Data [ "to" ] = "auth/token"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "cannot remount to destination \"auth/token/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
}
func TestSystemBackend_remount_auth_destinationInUse ( t * testing . T ) {
err := AddTestCredentialBackend ( "userpass" , credUserpass . Factory )
if err != nil {
t . Fatal ( err )
}
c , b , _ := testCoreSystemBackend ( t )
userpassMe := & MountEntry {
Table : credentialTableType ,
Path : "userpass1/" ,
Type : "userpass" ,
Description : "userpass" ,
}
err = c . enableCredential ( namespace . RootContext ( nil ) , userpassMe )
if err != nil {
t . Fatal ( err )
}
userpassMe2 := & MountEntry {
Table : credentialTableType ,
Path : "userpass2/" ,
Type : "userpass" ,
Description : "userpass" ,
}
err = c . enableCredential ( namespace . RootContext ( nil ) , userpassMe2 )
if err != nil {
t . Fatal ( err )
}
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "auth/userpass1"
req . Data [ "to" ] = "auth/userpass2"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "path already in use at \"auth/userpass2/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
req . Data [ "to" ] = "auth/userpass2/mypass"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "path already in use at \"auth/userpass2/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
userpassMe3 := & MountEntry {
Table : credentialTableType ,
Path : "userpass3/mypass/" ,
Type : "userpass" ,
Description : "userpass" ,
}
err = c . enableCredential ( namespace . RootContext ( nil ) , userpassMe3 )
if err != nil {
t . Fatal ( err )
}
req . Data [ "to" ] = "auth/userpass3/"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "path already in use at \"auth/userpass3/mypass/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
}
2015-03-15 21:42:05 +00:00
func TestSystemBackend_remount ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
2015-03-15 21:42:05 +00:00
req . Data [ "from" ] = "secret"
req . Data [ "to" ] = "foo"
2015-09-01 22:29:30 +00:00
req . Data [ "config" ] = structs . Map ( MountConfig { } )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2023-02-01 13:33:16 +00:00
corehelpers . RetryUntil ( t , 5 * time . Second , func ( ) error {
2022-02-17 20:17:59 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , fmt . Sprintf ( "remount/status/%s" , resp . Data [ "migration_id" ] ) )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
migrationInfo := resp . Data [ "migration_info" ] . ( * MountMigrationInfo )
if migrationInfo . MigrationStatus != MigrationSuccessStatus . String ( ) {
return fmt . Errorf ( "Expected migration status to be successful, got %q" , migrationInfo . MigrationStatus )
}
return nil
} )
2015-03-15 21:42:05 +00:00
}
2022-02-18 22:01:43 +00:00
func TestSystemBackend_remount_destinationInUse ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
me := & MountEntry {
Table : mountTableType ,
Path : "foo/" ,
Type : "generic" ,
}
err := c . mount ( namespace . RootContext ( nil ) , me )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "secret"
req . Data [ "to" ] = "foo"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "path already in use at \"foo/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
req . Data [ "to" ] = "foo/foo2"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "path already in use at \"foo/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
me2 := & MountEntry {
Table : mountTableType ,
Path : "foo2/foo3/" ,
Type : "generic" ,
}
err = c . mount ( namespace . RootContext ( nil ) , me2 )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
req . Data [ "to" ] = "foo2/"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "path already in use at \"foo2/foo3/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
}
}
2015-03-15 21:42:05 +00:00
func TestSystemBackend_remount_invalid ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
2015-03-15 21:42:05 +00:00
req . Data [ "from" ] = "unknown"
req . Data [ "to" ] = "foo"
2015-09-01 22:29:30 +00:00
req . Data [ "config" ] = structs . Map ( MountConfig { } )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-15 21:53:41 +00:00
if err != logical . ErrInvalidRequest {
2015-03-15 21:42:05 +00:00
t . Fatalf ( "err: %v" , err )
}
2022-02-17 20:17:59 +00:00
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "no matching mount at \"unknown/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
2015-03-15 21:42:05 +00:00
}
}
func TestSystemBackend_remount_system ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
2015-03-15 21:42:05 +00:00
req . Data [ "from" ] = "sys"
req . Data [ "to" ] = "foo"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-15 21:53:41 +00:00
if err != logical . ErrInvalidRequest {
2015-03-15 21:42:05 +00:00
t . Fatalf ( "err: %v" , err )
}
2022-02-17 20:17:59 +00:00
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "cannot remount \"sys/\"" ) {
t . Fatalf ( "Found unexpected error %q" , resp . Data [ "error" ] . ( string ) )
2015-03-15 21:42:05 +00:00
}
}
2020-10-29 18:06:07 +00:00
func TestSystemBackend_remount_clean ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "foo"
req . Data [ "to" ] = "foo//bar"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2022-02-17 20:17:59 +00:00
if resp . Data [ "error" ] != ` invalid destination mount: path 'foo//bar/' does not match cleaned path 'foo/bar/' ` {
2020-10-29 18:06:07 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
func TestSystemBackend_remount_nonPrintable ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "foo"
req . Data [ "to" ] = "foo\nbar"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2022-02-17 20:17:59 +00:00
if resp . Data [ "error" ] != ` invalid destination mount: path cannot contain non-printable characters ` {
2020-10-29 18:06:07 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
2023-03-16 19:26:55 +00:00
// TestSystemBackend_remount_trailingSpacesInFromPath ensures we error when
// there are trailing spaces in the 'from' path during a remount.
func TestSystemBackend_remount_trailingSpacesInFromPath ( t * testing . T ) {
2022-03-15 18:11:23 +00:00
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
2023-03-16 19:26:55 +00:00
req . Data [ "from" ] = " foo/ "
2022-03-15 18:11:23 +00:00
req . Data [ "to" ] = "bar"
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2023-03-16 19:26:55 +00:00
if resp . Data [ "error" ] != ` 'from' path cannot contain trailing whitespace ` {
2022-03-15 18:11:23 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
2023-03-16 19:26:55 +00:00
// TestSystemBackend_remount_trailingSpacesInToPath ensures we error when
// there are trailing spaces in the 'to' path during a remount.
func TestSystemBackend_remount_trailingSpacesInToPath ( t * testing . T ) {
2022-03-15 18:11:23 +00:00
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "remount" )
req . Data [ "from" ] = "foo"
2023-03-16 19:26:55 +00:00
req . Data [ "to" ] = " bar/ "
2022-03-15 18:11:23 +00:00
req . Data [ "config" ] = structs . Map ( MountConfig { } )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2023-03-16 19:26:55 +00:00
if resp . Data [ "error" ] != ` 'to' path cannot contain trailing whitespace ` {
2022-03-15 18:11:23 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
2017-05-04 02:03:42 +00:00
func TestSystemBackend_leases ( t * testing . T ) {
core , b , root := testCoreSystemBackend ( t )
// Create a key with a lease
req := logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
req . Data [ "foo" ] = "bar"
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err := core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
// Read lease
req = logical . TestRequest ( t , logical . UpdateOperation , "leases/lookup" )
req . Data [ "lease_id" ] = resp . Secret . LeaseID
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for Update
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-05-04 02:03:42 +00:00
if resp . Data [ "renewable" ] == nil || resp . Data [ "renewable" ] . ( bool ) {
2017-09-15 13:02:29 +00:00
t . Fatal ( "kv leases are not renewable" )
2017-05-04 02:03:42 +00:00
}
// Invalid lease
req = logical . TestRequest ( t , logical . UpdateOperation , "leases/lookup" )
req . Data [ "lease_id" ] = "invalid"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "expected invalid request, got err: %v" , err )
}
}
func TestSystemBackend_leases_list ( t * testing . T ) {
core , b , root := testCoreSystemBackend ( t )
// Create a key with a lease
req := logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
req . Data [ "foo" ] = "bar"
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err := core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
// List top level
req = logical . TestRequest ( t , logical . ListOperation , "leases/lookup/" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response body for list
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-05-04 02:03:42 +00:00
var keys [ ] string
if err := mapstructure . WeakDecode ( resp . Data [ "keys" ] , & keys ) ; err != nil {
t . Fatalf ( "err: %v" , err )
}
if len ( keys ) != 1 {
t . Fatalf ( "Expected 1 subkey lease, got %d: %#v" , len ( keys ) , keys )
}
if keys [ 0 ] != "secret/" {
t . Fatal ( "Expected only secret subkey" )
}
// List lease
req = logical . TestRequest ( t , logical . ListOperation , "leases/lookup/secret/foo" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Data == nil {
t . Fatalf ( "bad: %#v" , resp )
}
keys = [ ] string { }
if err := mapstructure . WeakDecode ( resp . Data [ "keys" ] , & keys ) ; err != nil {
t . Fatalf ( "err: %v" , err )
}
if len ( keys ) != 1 {
t . Fatalf ( "Expected 1 secret lease, got %d: %#v" , len ( keys ) , keys )
}
// Generate multiple leases
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
req = logical . TestRequest ( t , logical . ListOperation , "leases/lookup/secret/foo" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Data == nil {
t . Fatalf ( "bad: %#v" , resp )
}
keys = [ ] string { }
if err := mapstructure . WeakDecode ( resp . Data [ "keys" ] , & keys ) ; err != nil {
t . Fatalf ( "err: %v" , err )
}
if len ( keys ) != 3 {
t . Fatalf ( "Expected 3 secret lease, got %d: %#v" , len ( keys ) , keys )
}
// Listing subkeys
req = logical . TestRequest ( t , logical . UpdateOperation , "secret/bar" )
req . Data [ "foo" ] = "bar"
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/bar" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
req = logical . TestRequest ( t , logical . ListOperation , "leases/lookup/secret" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Data == nil {
t . Fatalf ( "bad: %#v" , resp )
}
keys = [ ] string { }
if err := mapstructure . WeakDecode ( resp . Data [ "keys" ] , & keys ) ; err != nil {
t . Fatalf ( "err: %v" , err )
}
if len ( keys ) != 2 {
t . Fatalf ( "Expected 2 secret lease, got %d: %#v" , len ( keys ) , keys )
}
expected := [ ] string { "bar/" , "foo/" }
if ! reflect . DeepEqual ( expected , keys ) {
t . Fatalf ( "exp: %#v, act: %#v" , expected , keys )
}
}
2015-03-16 23:11:55 +00:00
func TestSystemBackend_renew ( t * testing . T ) {
2015-03-24 18:37:07 +00:00
core , b , root := testCoreSystemBackend ( t )
2015-03-16 23:11:55 +00:00
// Create a key with a lease
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
2015-03-16 23:11:55 +00:00
req . Data [ "foo" ] = "bar"
2015-03-24 18:37:07 +00:00
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err := core . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:11:55 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2015-04-08 20:35:32 +00:00
// Read a key with a LeaseID
2015-03-16 23:11:55 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
2015-03-24 18:37:07 +00:00
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:11:55 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2015-04-08 20:35:32 +00:00
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
2015-03-16 23:11:55 +00:00
t . Fatalf ( "bad: %#v" , resp )
}
// Attempt renew
2017-05-04 02:03:42 +00:00
req2 := logical . TestRequest ( t , logical . UpdateOperation , "leases/renew/" + resp . Secret . LeaseID )
2018-11-05 16:11:32 +00:00
resp2 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2015-04-09 00:03:46 +00:00
if err != logical . ErrInvalidRequest {
2015-03-16 23:11:55 +00:00
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// Validate lease renewal response structure
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req2 . Path ) , req2 . Operation ) ,
resp ,
true ,
)
2015-04-09 00:03:46 +00:00
// Should get error about non-renewability
if resp2 . Data [ "error" ] != "lease is not renewable" {
2015-03-16 23:11:55 +00:00
t . Fatalf ( "bad: %#v" , resp )
}
2016-08-08 22:32:18 +00:00
// Add a TTL to the lease
req = logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
req . Data [ "foo" ] = "bar"
req . Data [ "ttl" ] = "180s"
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-08-08 22:32:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-08-08 22:32:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
// Attempt renew
2017-05-04 02:03:42 +00:00
req2 = logical . TestRequest ( t , logical . UpdateOperation , "leases/renew/" + resp . Secret . LeaseID )
2018-11-05 16:11:32 +00:00
resp2 , err = b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2016-08-08 22:32:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp2 . IsError ( ) {
t . Fatalf ( "got an error" )
}
if resp2 . Data == nil {
t . Fatal ( "nil data" )
}
if resp . Secret . TTL != 180 * time . Second {
2016-08-09 11:13:29 +00:00
t . Fatalf ( "bad lease duration: %v" , resp . Secret . TTL )
2016-08-08 22:32:18 +00:00
}
// Test the other route path
2017-05-04 02:03:42 +00:00
req2 = logical . TestRequest ( t , logical . UpdateOperation , "leases/renew" )
req2 . Data [ "lease_id" ] = resp . Secret . LeaseID
2018-11-05 16:11:32 +00:00
resp2 , err = b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp2 . IsError ( ) {
t . Fatalf ( "got an error" )
}
if resp2 . Data == nil {
t . Fatal ( "nil data" )
}
if resp . Secret . TTL != 180 * time . Second {
t . Fatalf ( "bad lease duration: %v" , resp . Secret . TTL )
}
// Test orig path
2016-08-08 22:32:18 +00:00
req2 = logical . TestRequest ( t , logical . UpdateOperation , "renew" )
req2 . Data [ "lease_id" ] = resp . Secret . LeaseID
2018-11-05 16:11:32 +00:00
resp2 , err = b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2016-08-08 22:32:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp2 . IsError ( ) {
t . Fatalf ( "got an error" )
}
if resp2 . Data == nil {
t . Fatal ( "nil data" )
}
2018-10-15 16:56:24 +00:00
if resp . Secret . TTL != time . Second * 180 {
2016-08-09 11:13:29 +00:00
t . Fatalf ( "bad lease duration: %v" , resp . Secret . TTL )
2016-08-08 22:32:18 +00:00
}
2015-03-16 23:11:55 +00:00
}
2015-03-16 23:14:53 +00:00
func TestSystemBackend_renew_invalidID ( t * testing . T ) {
b := testSystemBackend ( t )
2017-05-04 02:03:42 +00:00
// Attempt renew
req := logical . TestRequest ( t , logical . UpdateOperation , "leases/renew/foobarbaz" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp . Data [ "error" ] != "lease not found" {
2017-05-04 02:03:42 +00:00
t . Fatalf ( "bad: %v" , resp )
}
// Attempt renew with other method
req = logical . TestRequest ( t , logical . UpdateOperation , "leases/renew" )
req . Data [ "lease_id" ] = "foobarbaz"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp . Data [ "error" ] != "lease not found" {
2017-05-04 02:03:42 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
func TestSystemBackend_renew_invalidID_origUrl ( t * testing . T ) {
b := testSystemBackend ( t )
2015-03-16 23:14:53 +00:00
// Attempt renew
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "renew/foobarbaz" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:14:53 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp . Data [ "error" ] != "lease not found" {
2015-03-16 23:14:53 +00:00
t . Fatalf ( "bad: %v" , resp )
}
2017-04-27 14:47:43 +00:00
// Attempt renew with other method
req = logical . TestRequest ( t , logical . UpdateOperation , "renew" )
req . Data [ "lease_id" ] = "foobarbaz"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-27 14:47:43 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp . Data [ "error" ] != "lease not found" {
2017-04-27 14:47:43 +00:00
t . Fatalf ( "bad: %v" , resp )
}
2015-03-16 23:14:53 +00:00
}
2015-03-16 23:26:34 +00:00
func TestSystemBackend_revoke ( t * testing . T ) {
2015-03-24 18:37:07 +00:00
core , b , root := testCoreSystemBackend ( t )
2015-03-16 23:26:34 +00:00
// Create a key with a lease
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
2015-03-16 23:26:34 +00:00
req . Data [ "foo" ] = "bar"
req . Data [ "lease" ] = "1h"
2015-03-24 18:37:07 +00:00
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err := core . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:26:34 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2015-04-08 20:35:32 +00:00
// Read a key with a LeaseID
2015-03-16 23:26:34 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
2015-03-24 18:37:07 +00:00
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:26:34 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2015-04-08 20:35:32 +00:00
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
2015-03-16 23:26:34 +00:00
t . Fatalf ( "bad: %#v" , resp )
}
2015-03-16 23:33:48 +00:00
// Attempt revoke
2016-01-07 15:30:47 +00:00
req2 := logical . TestRequest ( t , logical . UpdateOperation , "revoke/" + resp . Secret . LeaseID )
2018-11-05 16:11:32 +00:00
resp2 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2015-03-16 23:26:34 +00:00
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp2 )
}
if resp2 != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2015-03-16 23:33:48 +00:00
// Attempt renew
2016-01-07 15:30:47 +00:00
req3 := logical . TestRequest ( t , logical . UpdateOperation , "renew/" + resp . Secret . LeaseID )
2018-11-05 16:11:32 +00:00
resp3 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req3 )
2015-03-16 23:33:48 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp3 . Data [ "error" ] != "lease not found" {
t . Fatalf ( "bad: %v" , * resp3 )
2015-03-16 23:33:48 +00:00
}
2017-04-27 14:47:43 +00:00
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-27 14:47:43 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
// Test the other route path
req2 = logical . TestRequest ( t , logical . UpdateOperation , "revoke" )
req2 . Data [ "lease_id" ] = resp . Secret . LeaseID
2018-11-05 16:11:32 +00:00
resp2 , err = b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2017-04-27 14:47:43 +00:00
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp2 )
}
if resp2 != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2017-05-04 02:03:42 +00:00
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
// Test the other route path
req2 = logical . TestRequest ( t , logical . UpdateOperation , "leases/revoke" )
req2 . Data [ "lease_id" ] = resp . Secret . LeaseID
2018-11-05 16:11:32 +00:00
resp2 , err = b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp2 )
}
if resp2 != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2015-03-16 23:26:34 +00:00
}
func TestSystemBackend_revoke_invalidID ( t * testing . T ) {
b := testSystemBackend ( t )
2017-05-04 02:03:42 +00:00
// Attempt revoke
req := logical . TestRequest ( t , logical . UpdateOperation , "leases/revoke/foobarbaz" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
// Attempt revoke with other method
req = logical . TestRequest ( t , logical . UpdateOperation , "leases/revoke" )
req . Data [ "lease_id" ] = "foobarbaz"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for lease revoke
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-05-04 02:03:42 +00:00
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
}
func TestSystemBackend_revoke_invalidID_origUrl ( t * testing . T ) {
b := testSystemBackend ( t )
2017-04-27 14:47:43 +00:00
// Attempt revoke
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "revoke/foobarbaz" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:26:34 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2017-04-27 14:47:43 +00:00
// Attempt revoke with other method
req = logical . TestRequest ( t , logical . UpdateOperation , "revoke" )
req . Data [ "lease_id" ] = "foobarbaz"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-27 14:47:43 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2015-03-16 23:26:34 +00:00
}
2015-03-16 23:33:48 +00:00
func TestSystemBackend_revokePrefix ( t * testing . T ) {
2015-03-24 18:37:07 +00:00
core , b , root := testCoreSystemBackend ( t )
2015-03-16 23:33:48 +00:00
// Create a key with a lease
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
2015-03-16 23:33:48 +00:00
req . Data [ "foo" ] = "bar"
req . Data [ "lease" ] = "1h"
2015-03-24 18:37:07 +00:00
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err := core . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:33:48 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2015-04-08 20:35:32 +00:00
// Read a key with a LeaseID
2015-03-16 23:33:48 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
2015-03-24 18:37:07 +00:00
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-16 23:33:48 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2015-04-08 20:35:32 +00:00
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
2015-03-16 23:33:48 +00:00
t . Fatalf ( "bad: %#v" , resp )
}
2017-05-04 02:03:42 +00:00
// Attempt revoke
req2 := logical . TestRequest ( t , logical . UpdateOperation , "leases/revoke-prefix/secret/" )
2018-11-05 16:11:32 +00:00
resp2 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp2 )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for lease revoke-prefix
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req2 . Path ) , req2 . Operation ) ,
resp ,
true ,
)
2017-05-04 02:03:42 +00:00
// Attempt renew
req3 := logical . TestRequest ( t , logical . UpdateOperation , "leases/renew/" + resp . Secret . LeaseID )
2018-11-05 16:11:32 +00:00
resp3 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req3 )
2017-05-04 02:03:42 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp3 . Data [ "error" ] != "lease not found" {
t . Fatalf ( "bad: %v" , * resp3 )
2017-05-04 02:03:42 +00:00
}
}
func TestSystemBackend_revokePrefix_origUrl ( t * testing . T ) {
core , b , root := testCoreSystemBackend ( t )
// Create a key with a lease
req := logical . TestRequest ( t , logical . UpdateOperation , "secret/foo" )
req . Data [ "foo" ] = "bar"
req . Data [ "lease" ] = "1h"
req . ClientToken = root
2018-11-05 16:11:32 +00:00
resp , err := core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// Read a key with a LeaseID
req = logical . TestRequest ( t , logical . ReadOperation , "secret/foo" )
req . ClientToken = root
2022-03-01 20:24:45 +00:00
err = core . PopulateTokenEntry ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
2018-11-05 16:11:32 +00:00
resp , err = core . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Secret == nil || resp . Secret . LeaseID == "" {
t . Fatalf ( "bad: %#v" , resp )
}
2015-03-16 23:33:48 +00:00
// Attempt revoke
2016-01-07 15:30:47 +00:00
req2 := logical . TestRequest ( t , logical . UpdateOperation , "revoke-prefix/secret/" )
2018-11-05 16:11:32 +00:00
resp2 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
2015-03-16 23:33:48 +00:00
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp2 )
}
if resp2 != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// Attempt renew
2016-01-07 15:30:47 +00:00
req3 := logical . TestRequest ( t , logical . UpdateOperation , "renew/" + resp . Secret . LeaseID )
2018-11-05 16:11:32 +00:00
resp3 , err := b . HandleRequest ( namespace . RootContext ( nil ) , req3 )
2015-03-16 23:33:48 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-10-15 16:56:24 +00:00
if resp3 . Data [ "error" ] != "lease not found" {
t . Fatalf ( "bad: %#v" , * resp3 )
2015-03-16 23:33:48 +00:00
}
}
2018-06-03 22:14:51 +00:00
func TestSystemBackend_revokePrefixAuth_newUrl ( t * testing . T ) {
core , _ , _ := TestCoreUnsealed ( t )
ts := core . tokenStore
2016-03-31 22:04:05 +00:00
bc := & logical . BackendConfig {
Logger : core . logger ,
System : logical . StaticSystemView {
DefaultLeaseTTLVal : time . Hour * 24 ,
2016-09-28 22:32:49 +00:00
MaxLeaseTTLVal : time . Hour * 24 * 32 ,
2016-03-31 22:04:05 +00:00
} ,
}
2018-04-03 00:46:59 +00:00
b := NewSystemBackend ( core , hclog . New ( & hclog . LoggerOptions { } ) )
2018-11-05 16:11:32 +00:00
err := b . Backend . Setup ( namespace . RootContext ( nil ) , bc )
2016-09-29 04:01:28 +00:00
if err != nil {
t . Fatal ( err )
}
2016-03-31 22:04:05 +00:00
exp := ts . expiration
2018-06-08 21:24:27 +00:00
te := & logical . TokenEntry {
2018-09-18 03:03:00 +00:00
ID : "foo" ,
Path : "auth/github/login/bar" ,
TTL : time . Hour ,
NamespaceID : namespace . RootNamespaceID ,
2017-05-04 02:03:42 +00:00
}
2018-06-03 22:14:51 +00:00
testMakeTokenDirectly ( t , ts , te )
2017-05-04 02:03:42 +00:00
2018-11-05 16:11:32 +00:00
te , err = ts . Lookup ( namespace . RootContext ( nil ) , "foo" )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatal ( err )
}
if te == nil {
t . Fatal ( "token entry was nil" )
}
// Create a new token
auth := & logical . Auth {
ClientToken : te . ID ,
LeaseOptions : logical . LeaseOptions {
TTL : time . Hour ,
} ,
}
2022-07-05 17:02:00 +00:00
err = exp . RegisterAuth ( namespace . RootContext ( nil ) , te , auth , "" )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
req := logical . TestRequest ( t , logical . UpdateOperation , "leases/revoke-prefix/auth/github/" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v %v" , err , resp )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2018-11-05 16:11:32 +00:00
te , err = ts . Lookup ( namespace . RootContext ( nil ) , te . ID )
2017-05-04 02:03:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if te != nil {
t . Fatalf ( "bad: %v" , te )
}
}
func TestSystemBackend_revokePrefixAuth_origUrl ( t * testing . T ) {
2018-06-03 22:14:51 +00:00
core , _ , _ := TestCoreUnsealed ( t )
ts := core . tokenStore
2016-03-31 22:04:05 +00:00
bc := & logical . BackendConfig {
Logger : core . logger ,
System : logical . StaticSystemView {
DefaultLeaseTTLVal : time . Hour * 24 ,
2016-09-28 22:32:49 +00:00
MaxLeaseTTLVal : time . Hour * 24 * 32 ,
2016-03-31 22:04:05 +00:00
} ,
}
2018-04-03 00:46:59 +00:00
b := NewSystemBackend ( core , hclog . New ( & hclog . LoggerOptions { } ) )
2018-11-05 16:11:32 +00:00
err := b . Backend . Setup ( namespace . RootContext ( nil ) , bc )
2016-09-29 04:01:28 +00:00
if err != nil {
t . Fatal ( err )
}
2016-03-31 22:04:05 +00:00
exp := ts . expiration
2018-06-08 21:24:27 +00:00
te := & logical . TokenEntry {
2018-09-18 03:03:00 +00:00
ID : "foo" ,
Path : "auth/github/login/bar" ,
TTL : time . Hour ,
NamespaceID : namespace . RootNamespaceID ,
2016-03-31 22:04:05 +00:00
}
2018-06-03 22:14:51 +00:00
testMakeTokenDirectly ( t , ts , te )
2016-03-31 22:04:05 +00:00
2018-11-05 16:11:32 +00:00
te , err = ts . Lookup ( namespace . RootContext ( nil ) , "foo" )
2016-03-31 22:04:05 +00:00
if err != nil {
t . Fatal ( err )
}
if te == nil {
t . Fatal ( "token entry was nil" )
}
// Create a new token
auth := & logical . Auth {
ClientToken : te . ID ,
LeaseOptions : logical . LeaseOptions {
TTL : time . Hour ,
} ,
}
2022-07-05 17:02:00 +00:00
err = exp . RegisterAuth ( namespace . RootContext ( nil ) , te , auth , "" )
2016-03-31 22:04:05 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
req := logical . TestRequest ( t , logical . UpdateOperation , "revoke-prefix/auth/github/" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-03-31 22:04:05 +00:00
if err != nil {
t . Fatalf ( "err: %v %v" , err , resp )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2018-11-05 16:11:32 +00:00
te , err = ts . Lookup ( namespace . RootContext ( nil ) , te . ID )
2016-03-31 22:04:05 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if te != nil {
t . Fatalf ( "bad: %v" , te )
}
}
2015-03-20 19:48:19 +00:00
func TestSystemBackend_authTable ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "auth" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-20 19:48:19 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-20 19:48:19 +00:00
exp := map [ string ] interface { } {
2016-06-20 19:55:21 +00:00
"token/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "token" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "token based credentials" ,
"accessor" : resp . Data [ "token/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "token/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2016-06-20 19:55:21 +00:00
"config" : map [ string ] interface { } {
2016-06-21 00:08:12 +00:00
"default_lease_ttl" : int64 ( 0 ) ,
"max_lease_ttl" : int64 ( 0 ) ,
2018-10-15 16:56:24 +00:00
"force_no_cache" : false ,
"token_type" : "default-service" ,
2016-06-20 19:55:21 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
2022-09-23 10:19:38 +00:00
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeCredential , "token" ) ,
2022-09-20 11:35:50 +00:00
"running_sha256" : "" ,
2015-03-20 19:48:19 +00:00
} ,
}
2018-10-15 16:56:24 +00:00
if diff := deep . Equal ( resp . Data , exp ) ; diff != nil {
t . Fatal ( diff )
2015-03-20 19:48:19 +00:00
}
2022-01-25 19:56:40 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "auth/token" )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-01-25 19:56:40 +00:00
if diff := deep . Equal ( resp . Data , exp [ "token/" ] ) ; diff != nil {
t . Fatal ( diff )
}
2015-03-20 19:48:19 +00:00
}
func TestSystemBackend_enableAuth ( t * testing . T ) {
2015-03-24 18:37:07 +00:00
c , b , _ := testCoreSystemBackend ( t )
2018-01-19 06:44:44 +00:00
c . credentialBackends [ "noop" ] = func ( context . Context , * logical . BackendConfig ) ( logical . Backend , error ) {
2018-11-07 01:21:24 +00:00
return & NoopBackend { BackendType : logical . TypeCredential } , nil
2015-03-20 19:48:19 +00:00
}
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "auth/foo" )
2015-03-20 19:48:19 +00:00
req . Data [ "type" ] = "noop"
2018-02-22 15:26:29 +00:00
req . Data [ "config" ] = map [ string ] interface { } {
"default_lease_ttl" : "35m" ,
"max_lease_ttl" : "45m" ,
}
2017-11-13 16:22:22 +00:00
req . Data [ "local" ] = true
req . Data [ "seal_wrap" ] = true
2015-03-20 19:48:19 +00:00
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-20 19:48:19 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-11-13 16:22:22 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "auth" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-11-13 16:22:22 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatal ( "resp is nil" )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-11-13 16:22:22 +00:00
exp := map [ string ] interface { } {
"foo/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "noop" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "" ,
"accessor" : resp . Data [ "foo/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "foo/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
2018-02-22 15:26:29 +00:00
"default_lease_ttl" : int64 ( 2100 ) ,
"max_lease_ttl" : int64 ( 2700 ) ,
2018-10-15 16:56:24 +00:00
"force_no_cache" : false ,
"token_type" : "default-service" ,
2017-11-13 16:22:22 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : true ,
"seal_wrap" : true ,
"options" : map [ string ] string { } ,
"plugin_version" : "" ,
"running_plugin_version" : versions . DefaultBuiltinVersion ,
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
"token/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "token" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "token based credentials" ,
"accessor" : resp . Data [ "token/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "token/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2017-11-13 16:22:22 +00:00
"config" : map [ string ] interface { } {
"default_lease_ttl" : int64 ( 0 ) ,
"max_lease_ttl" : int64 ( 0 ) ,
2018-10-15 16:56:24 +00:00
"force_no_cache" : false ,
"token_type" : "default-service" ,
2017-11-13 16:22:22 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
2022-09-23 10:19:38 +00:00
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeCredential , "token" ) ,
2022-09-20 11:35:50 +00:00
"running_sha256" : "" ,
2017-11-13 16:22:22 +00:00
} ,
}
2018-10-15 16:56:24 +00:00
if diff := deep . Equal ( resp . Data , exp ) ; diff != nil {
t . Fatal ( diff )
2017-11-13 16:22:22 +00:00
}
2015-03-20 19:48:19 +00:00
}
func TestSystemBackend_enableAuth_invalid ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "auth/foo" )
2015-03-20 19:48:19 +00:00
req . Data [ "type" ] = "nope"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-20 19:48:19 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-11-07 01:21:24 +00:00
if resp . Data [ "error" ] != ` plugin not found in the catalog: nope ` {
2015-03-20 19:48:19 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
func TestSystemBackend_disableAuth ( t * testing . T ) {
2015-03-24 18:37:07 +00:00
c , b , _ := testCoreSystemBackend ( t )
2018-01-19 06:44:44 +00:00
c . credentialBackends [ "noop" ] = func ( context . Context , * logical . BackendConfig ) ( logical . Backend , error ) {
2015-03-31 01:07:05 +00:00
return & NoopBackend { } , nil
2015-03-20 19:48:19 +00:00
}
// Register the backend
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "auth/foo" )
2015-03-20 19:48:19 +00:00
req . Data [ "type" ] = "noop"
2018-11-05 16:11:32 +00:00
b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-20 19:48:19 +00:00
// Deregister it
req = logical . TestRequest ( t , logical . DeleteOperation , "auth/foo" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-20 19:48:19 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-20 19:48:19 +00:00
}
2020-02-15 18:32:47 +00:00
func TestSystemBackend_tuneAuth ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
c . credentialBackends [ "noop" ] = func ( context . Context , * logical . BackendConfig ) ( logical . Backend , error ) {
return & NoopBackend { BackendType : logical . TypeCredential } , nil
}
req := logical . TestRequest ( t , logical . ReadOperation , "auth/token/tune" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatal ( "resp is nil" )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2020-02-15 18:32:47 +00:00
exp := map [ string ] interface { } {
"description" : "token based credentials" ,
"default_lease_ttl" : int ( 2764800 ) ,
"max_lease_ttl" : int ( 2764800 ) ,
"force_no_cache" : false ,
"token_type" : "default-service" ,
}
if diff := deep . Equal ( resp . Data , exp ) ; diff != nil {
t . Fatal ( diff )
}
req = logical . TestRequest ( t , logical . UpdateOperation , "auth/token/tune" )
req . Data [ "description" ] = ""
2022-09-22 12:53:52 +00:00
req . Data [ "plugin_version" ] = "v1.0.0"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err == nil || resp == nil || ! resp . IsError ( ) || ! strings . Contains ( resp . Error ( ) . Error ( ) , ErrPluginNotFound . Error ( ) ) {
t . Fatalf ( "expected tune request to fail, but got resp: %#v, err: %s" , resp , err )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-09-22 12:53:52 +00:00
// Register the plugin in the catalog, and then try the same request again.
{
tempDir , err := filepath . EvalSymlinks ( t . TempDir ( ) )
if err != nil {
t . Fatal ( err )
}
c . pluginCatalog . directory = tempDir
file , err := os . Create ( filepath . Join ( tempDir , "foo" ) )
if err != nil {
t . Fatal ( err )
}
if err := file . Close ( ) ; err != nil {
t . Fatal ( err )
}
err = c . pluginCatalog . Set ( context . Background ( ) , "token" , consts . PluginTypeCredential , "v1.0.0" , "foo" , [ ] string { } , [ ] string { } , [ ] byte { } )
if err != nil {
t . Fatal ( err )
}
}
2020-02-15 18:32:47 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
2022-09-22 12:53:52 +00:00
t . Fatal ( resp , err )
2020-02-15 18:32:47 +00:00
}
req = logical . TestRequest ( t , logical . ReadOperation , "auth/token/tune" )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatal ( "resp is nil" )
}
2023-02-16 20:03:19 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2020-02-15 18:32:47 +00:00
if resp . Data [ "description" ] != "" {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data [ "description" ] , "" )
}
2022-09-22 12:53:52 +00:00
if resp . Data [ "plugin_version" ] != "v1.0.0" {
t . Fatalf ( "got: %#v, expected: %v" , resp . Data [ "version" ] , "v1.0.0" )
}
2020-02-15 18:32:47 +00:00
}
2015-03-23 21:43:31 +00:00
func TestSystemBackend_policyList ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "policy" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for policy read
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-23 21:43:31 +00:00
exp := map [ string ] interface { } {
2016-07-25 19:59:02 +00:00
"keys" : [ ] string { "default" , "root" } ,
"policies" : [ ] string { "default" , "root" } ,
2015-03-23 21:43:31 +00:00
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
func TestSystemBackend_policyCRUD ( t * testing . T ) {
b := testSystemBackend ( t )
// Create the policy
rules := ` path "foo/" { policy = "read" } `
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "policy/Foo" )
2015-03-23 21:43:31 +00:00
req . Data [ "rules" ] = rules
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp )
}
2017-10-23 19:35:28 +00:00
if resp != nil && ( resp . IsError ( ) || len ( resp . Data ) > 0 ) {
2015-03-23 21:43:31 +00:00
t . Fatalf ( "bad: %#v" , resp )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for policy named Update
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-23 21:43:31 +00:00
// Read the policy
req = logical . TestRequest ( t , logical . ReadOperation , "policy/foo" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for policy named read
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-23 21:43:31 +00:00
exp := map [ string ] interface { } {
"name" : "foo" ,
"rules" : rules ,
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
2015-10-07 17:52:21 +00:00
// Read, and make sure that case has been normalized
req = logical . TestRequest ( t , logical . ReadOperation , "policy/Foo" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-07-04 17:58:28 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2017-08-18 23:47:23 +00:00
exp = map [ string ] interface { } {
"name" : "foo" ,
"rules" : rules ,
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
2015-10-07 17:52:21 +00:00
}
2015-03-23 21:43:31 +00:00
// List the policies
req = logical . TestRequest ( t , logical . ReadOperation , "policy" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
exp = map [ string ] interface { } {
2016-07-25 19:59:02 +00:00
"keys" : [ ] string { "default" , "foo" , "root" } ,
"policies" : [ ] string { "default" , "foo" , "root" } ,
2015-03-23 21:43:31 +00:00
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
// Delete the policy
req = logical . TestRequest ( t , logical . DeleteOperation , "policy/foo" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
2023-02-15 20:00:06 +00:00
// validate the response structure for policy named delete
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-03-23 21:43:31 +00:00
// Read the policy (deleted)
req = logical . TestRequest ( t , logical . ReadOperation , "policy/foo" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %#v" , resp )
}
// List the policies (deleted)
req = logical . TestRequest ( t , logical . ReadOperation , "policy" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-23 21:43:31 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
exp = map [ string ] interface { } {
2016-07-25 19:59:02 +00:00
"keys" : [ ] string { "default" , "root" } ,
"policies" : [ ] string { "default" , "root" } ,
2015-03-23 21:43:31 +00:00
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
2015-03-31 23:45:00 +00:00
func TestSystemBackend_enableAudit ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
2023-02-01 13:33:16 +00:00
c . auditBackends [ "noop" ] = corehelpers . NoopAuditFactory ( nil )
2015-03-31 23:45:00 +00:00
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "audit/foo" )
2015-03-31 23:45:00 +00:00
req . Data [ "type" ] = "noop"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-31 23:45:00 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
}
2015-11-19 01:26:03 +00:00
func TestSystemBackend_auditHash ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
2023-02-01 13:33:16 +00:00
c . auditBackends [ "noop" ] = corehelpers . NoopAuditFactory ( nil )
2015-11-19 01:26:03 +00:00
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "audit/foo" )
2015-11-19 01:26:03 +00:00
req . Data [ "type" ] = "noop"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-11-19 01:26:03 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2023-02-15 20:00:06 +00:00
2023-01-20 16:09:33 +00:00
schema . ValidateResponse (
t ,
2023-02-15 20:00:06 +00:00
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
2023-01-20 16:09:33 +00:00
resp ,
true ,
)
2015-11-19 01:26:03 +00:00
2016-01-07 15:30:47 +00:00
req = logical . TestRequest ( t , logical . UpdateOperation , "audit-hash/foo" )
2015-11-19 01:26:03 +00:00
req . Data [ "input" ] = "bar"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-11-19 01:26:03 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil || resp . Data == nil {
t . Fatalf ( "response or its data was nil" )
}
2023-02-15 20:00:06 +00:00
2023-01-20 16:09:33 +00:00
schema . ValidateResponse (
t ,
2023-02-15 20:00:06 +00:00
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
2023-01-20 16:09:33 +00:00
resp ,
true ,
)
2015-11-19 01:26:03 +00:00
hash , ok := resp . Data [ "hash" ]
if ! ok {
t . Fatalf ( "did not get hash back in response, response was %#v" , resp . Data )
}
if hash . ( string ) != "hmac-sha256:f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317" {
t . Fatalf ( "bad hash back: %s" , hash . ( string ) )
}
}
2015-03-31 23:45:00 +00:00
func TestSystemBackend_enableAudit_invalid ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "audit/foo" )
2015-03-31 23:45:00 +00:00
req . Data [ "type" ] = "nope"
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-31 23:45:00 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
2018-04-06 00:43:29 +00:00
if resp . Data [ "error" ] != ` unknown backend type: "nope" ` {
2015-03-31 23:45:00 +00:00
t . Fatalf ( "bad: %v" , resp )
}
}
func TestSystemBackend_auditTable ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
2023-02-01 13:33:16 +00:00
c . auditBackends [ "noop" ] = corehelpers . NoopAuditFactory ( nil )
2015-03-31 23:45:00 +00:00
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "audit/foo" )
2015-03-31 23:45:00 +00:00
req . Data [ "type" ] = "noop"
req . Data [ "description" ] = "testing"
req . Data [ "options" ] = map [ string ] interface { } {
"foo" : "bar" ,
}
2017-02-16 21:29:30 +00:00
req . Data [ "local" ] = true
2018-11-05 16:11:32 +00:00
b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-31 23:45:00 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "audit" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-31 23:45:00 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
exp := map [ string ] interface { } {
2015-04-03 21:27:33 +00:00
"foo/" : map [ string ] interface { } {
2016-03-14 22:40:12 +00:00
"path" : "foo/" ,
2015-03-31 23:45:00 +00:00
"type" : "noop" ,
"description" : "testing" ,
"options" : map [ string ] string {
"foo" : "bar" ,
} ,
2017-02-16 21:29:30 +00:00
"local" : true ,
2015-03-31 23:45:00 +00:00
} ,
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
func TestSystemBackend_disableAudit ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
2023-02-01 13:33:16 +00:00
c . auditBackends [ "noop" ] = corehelpers . NoopAuditFactory ( nil )
2015-03-31 23:45:00 +00:00
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "audit/foo" )
2015-03-31 23:45:00 +00:00
req . Data [ "type" ] = "noop"
req . Data [ "description" ] = "testing"
req . Data [ "options" ] = map [ string ] interface { } {
"foo" : "bar" ,
}
2018-11-05 16:11:32 +00:00
b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-31 23:45:00 +00:00
// Deregister it
req = logical . TestRequest ( t , logical . DeleteOperation , "audit/foo" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-03-31 23:45:00 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
}
2018-02-09 23:43:48 +00:00
func TestSystemBackend_rawRead_Compressed ( t * testing . T ) {
2022-01-20 12:52:53 +00:00
t . Run ( "basic" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
2018-02-09 23:43:48 +00:00
2022-01-20 12:52:53 +00:00
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-22 17:46:46 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-01-20 12:52:53 +00:00
if ! strings . HasPrefix ( resp . Data [ "value" ] . ( string ) , ` { "type":"mounts" ` ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "base64" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"encoding" : "base64" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if _ , ok := resp . Data [ "value" ] . ( [ ] byte ) ; ! ok {
t . Fatalf ( "value is a not an array of bytes, it is %T" , resp . Data [ "value" ] )
}
if ! strings . HasPrefix ( string ( resp . Data [ "value" ] . ( [ ] byte ) ) , ` { "type":"mounts" ` ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "invalid_encoding" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"encoding" : "invalid_encoding" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "compressed_false" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"compressed" : false ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if _ , ok := resp . Data [ "value" ] . ( string ) ; ! ok {
t . Fatalf ( "value is a not a string, it is %T" , resp . Data [ "value" ] )
}
if ! strings . HasPrefix ( string ( resp . Data [ "value" ] . ( string ) ) , string ( compressutil . CompressionCanaryGzip ) ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "compressed_false_base64" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"compressed" : false ,
"encoding" : "base64" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if _ , ok := resp . Data [ "value" ] . ( [ ] byte ) ; ! ok {
t . Fatalf ( "value is a not an array of bytes, it is %T" , resp . Data [ "value" ] )
}
if ! strings . HasPrefix ( string ( resp . Data [ "value" ] . ( [ ] byte ) ) , string ( compressutil . CompressionCanaryGzip ) ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "uncompressed_entry_with_prefix_byte" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/test_raw" )
req . Data = map [ string ] interface { } {
"value" : "414c1e7f-0a9a-49e0-9fc4-61af329d0724" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2023-02-22 17:46:46 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-01-20 12:52:53 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "raw/test_raw" )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err == nil {
t . Fatalf ( "expected error if trying to read uncompressed entry with prefix byte" )
}
if ! resp . IsError ( ) {
t . Fatalf ( "bad: %v" , resp )
}
req = logical . TestRequest ( t , logical . ReadOperation , "raw/test_raw" )
req . Data = map [ string ] interface { } {
"compressed" : false ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp . IsError ( ) {
t . Fatalf ( "bad: %v" , resp )
}
if resp . Data [ "value" ] . ( string ) != "414c1e7f-0a9a-49e0-9fc4-61af329d0724" {
t . Fatalf ( "bad: %v" , resp )
}
} )
2018-02-09 23:43:48 +00:00
}
2015-05-28 17:24:41 +00:00
func TestSystemBackend_rawRead_Protected ( t * testing . T ) {
2017-09-15 04:21:35 +00:00
b := testSystemBackendRaw ( t )
2015-05-28 17:24:41 +00:00
req := logical . TestRequest ( t , logical . ReadOperation , "raw/" + keyringPath )
2018-11-05 16:11:32 +00:00
_ , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-05-28 17:24:41 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
}
func TestSystemBackend_rawWrite_Protected ( t * testing . T ) {
2017-09-15 04:21:35 +00:00
b := testSystemBackendRaw ( t )
2015-05-28 17:24:41 +00:00
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "raw/" + keyringPath )
2018-11-05 16:11:32 +00:00
_ , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-05-28 17:24:41 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
}
2016-04-19 20:26:26 +00:00
func TestSystemBackend_rawReadWrite ( t * testing . T ) {
2017-10-23 19:35:28 +00:00
_ , b , _ := testCoreSystemBackendRaw ( t )
2015-04-02 00:44:43 +00:00
2022-01-20 12:52:53 +00:00
req := logical . TestRequest ( t , logical . CreateOperation , "raw/sys/policy/test" )
2015-04-02 00:44:43 +00:00
req . Data [ "value" ] = ` path "secret/" { policy = "read" } `
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-04-02 00:44:43 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2016-04-19 20:26:26 +00:00
// Read via raw API
req = logical . TestRequest ( t , logical . ReadOperation , "raw/sys/policy/test" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2016-04-19 20:26:26 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if ! strings . HasPrefix ( resp . Data [ "value" ] . ( string ) , "path" ) {
t . Fatalf ( "bad: %v" , resp )
}
2017-10-23 19:35:28 +00:00
// Note: since the upgrade code is gone that upgraded from 0.1, we can't
// simply parse this out directly via GetPolicy, so the test now ends here.
2015-04-02 00:44:43 +00:00
}
2022-01-20 12:52:53 +00:00
func TestSystemBackend_rawWrite_ExistanceCheck ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/core/mounts" )
_ , exist , err := b . HandleExistenceCheck ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: #{err}" )
}
if ! exist {
t . Fatalf ( "raw existence check failed for actual key" )
}
req = logical . TestRequest ( t , logical . CreateOperation , "raw/non_existent" )
_ , exist , err = b . HandleExistenceCheck ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: #{err}" )
}
if exist {
t . Fatalf ( "raw existence check failed for non-existent key" )
}
}
func TestSystemBackend_rawReadWrite_base64 ( t * testing . T ) {
t . Run ( "basic" , func ( t * testing . T ) {
_ , b , _ := testCoreSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/sys/policy/test" )
req . Data = map [ string ] interface { } {
"value" : base64 . StdEncoding . EncodeToString ( [ ] byte ( ` path "secret/" { policy = "read"[ } ` ) ) ,
"encoding" : "base64" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
// Read via raw API
req = logical . TestRequest ( t , logical . ReadOperation , "raw/sys/policy/test" )
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if ! strings . HasPrefix ( resp . Data [ "value" ] . ( string ) , "path" ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "invalid_value" , func ( t * testing . T ) {
_ , b , _ := testCoreSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/sys/policy/test" )
req . Data = map [ string ] interface { } {
"value" : "invalid base64" ,
"encoding" : "base64" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err == nil {
t . Fatalf ( "no error" )
}
if err != logical . ErrInvalidRequest {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "response is not error: %v" , resp )
}
} )
t . Run ( "invalid_encoding" , func ( t * testing . T ) {
_ , b , _ := testCoreSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/sys/policy/test" )
req . Data = map [ string ] interface { } {
"value" : "text" ,
"encoding" : "invalid_encoding" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err == nil {
t . Fatalf ( "no error" )
}
if err != logical . ErrInvalidRequest {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "response is not error: %v" , resp )
}
} )
}
func TestSystemBackend_rawReadWrite_Compressed ( t * testing . T ) {
t . Run ( "use_existing_compression" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
mounts := resp . Data [ "value" ] . ( string )
req = logical . TestRequest ( t , logical . UpdateOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"value" : mounts ,
"compression_type" : compressutil . CompressionTypeGzip ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-22 17:46:46 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-01-20 12:52:53 +00:00
// Read back and check gzip was applied by looking for prefix byte
req = logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"compressed" : false ,
"encoding" : "base64" ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if _ , ok := resp . Data [ "value" ] . ( [ ] byte ) ; ! ok {
t . Fatalf ( "value is a not an array of bytes, it is %T" , resp . Data [ "value" ] )
}
if ! strings . HasPrefix ( string ( resp . Data [ "value" ] . ( [ ] byte ) ) , string ( compressutil . CompressionCanaryGzip ) ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "compression_type_matches_existing_compression" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
mounts := resp . Data [ "value" ] . ( string )
req = logical . TestRequest ( t , logical . UpdateOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"value" : mounts ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
// Read back and check gzip was applied by looking for prefix byte
req = logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"compressed" : false ,
"encoding" : "base64" ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if _ , ok := resp . Data [ "value" ] . ( [ ] byte ) ; ! ok {
t . Fatalf ( "value is a not an array of bytes, it is %T" , resp . Data [ "value" ] )
}
if ! strings . HasPrefix ( string ( resp . Data [ "value" ] . ( [ ] byte ) ) , string ( compressutil . CompressionCanaryGzip ) ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "write_uncompressed_over_existing_compressed" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
mounts := resp . Data [ "value" ] . ( string )
req = logical . TestRequest ( t , logical . UpdateOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"value" : mounts ,
"compression_type" : "" ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
// Read back and check gzip was not applied by looking for prefix byte
req = logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"compressed" : false ,
"encoding" : "base64" ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if _ , ok := resp . Data [ "value" ] . ( [ ] byte ) ; ! ok {
t . Fatalf ( "value is a not an array of bytes, it is %T" , resp . Data [ "value" ] )
}
if ! strings . HasPrefix ( string ( resp . Data [ "value" ] . ( [ ] byte ) ) , ` { "type":"mounts" ` ) {
t . Fatalf ( "bad: %v" , resp )
}
} )
t . Run ( "invalid_compression_type" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "raw/core/mounts" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
mounts := resp . Data [ "value" ] . ( string )
req = logical . TestRequest ( t , logical . UpdateOperation , "raw/core/mounts" )
req . Data = map [ string ] interface { } {
"value" : mounts ,
"compression_type" : "invalid_type" ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "response is not error: %v" , resp )
}
} )
t . Run ( "update_non_existent_entry" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "raw/non_existent" )
req . Data = map [ string ] interface { } {
"value" : "{}" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "response is not error: %v" , resp )
}
} )
t . Run ( "invalid_compression_over_existing_uncompressed_data" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/test" )
req . Data = map [ string ] interface { } {
"value" : "{}" ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
if resp . IsError ( ) {
t . Fatalf ( "response is an error: %v" , resp )
}
req = logical . TestRequest ( t , logical . UpdateOperation , "raw/test" )
req . Data = map [ string ] interface { } {
"value" : "{}" ,
"compression_type" : compressutil . CompressionTypeGzip ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "response is not error: %v" , resp )
}
} )
t . Run ( "wrong_compression_type_over_existing_compressed_data" , func ( t * testing . T ) {
b := testSystemBackendRaw ( t )
req := logical . TestRequest ( t , logical . CreateOperation , "raw/test" )
req . Data = map [ string ] interface { } {
"value" : "{}" ,
"compression_type" : compressutil . CompressionTypeGzip ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
if resp . IsError ( ) {
t . Fatalf ( "response is an error: %v" , resp )
}
req = logical . TestRequest ( t , logical . UpdateOperation , "raw/test" )
req . Data = map [ string ] interface { } {
"value" : "{}" ,
"compression_type" : compressutil . CompressionTypeSnappy ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != logical . ErrInvalidRequest {
t . Fatalf ( "unexpected error: %v" , err )
}
if ! resp . IsError ( ) {
t . Fatalf ( "response is not error: %v" , resp )
}
} )
}
2015-05-28 17:24:41 +00:00
func TestSystemBackend_rawDelete_Protected ( t * testing . T ) {
2017-09-15 04:21:35 +00:00
b := testSystemBackendRaw ( t )
2015-05-28 17:24:41 +00:00
req := logical . TestRequest ( t , logical . DeleteOperation , "raw/" + keyringPath )
2018-11-05 16:11:32 +00:00
_ , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-05-28 17:24:41 +00:00
if err != logical . ErrInvalidRequest {
t . Fatalf ( "err: %v" , err )
}
}
2015-04-02 00:44:43 +00:00
func TestSystemBackend_rawDelete ( t * testing . T ) {
2017-09-15 04:21:35 +00:00
c , b , _ := testCoreSystemBackendRaw ( t )
2015-04-02 00:44:43 +00:00
// set the policy!
2017-10-23 19:35:28 +00:00
p := & Policy {
2018-09-18 03:03:00 +00:00
Name : "test" ,
Type : PolicyTypeACL ,
namespace : namespace . RootNamespace ,
2017-10-23 19:35:28 +00:00
}
2018-11-05 16:11:32 +00:00
err := c . policyStore . SetPolicy ( namespace . RootContext ( nil ) , p )
2015-04-02 00:44:43 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
// Delete the policy
req := logical . TestRequest ( t , logical . DeleteOperation , "raw/sys/policy/test" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-04-02 00:44:43 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
2023-02-22 17:46:46 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2015-04-02 00:44:43 +00:00
// Policy should be gone
2017-10-23 19:35:28 +00:00
c . policyStore . tokenPoliciesLRU . Purge ( )
2018-11-05 16:11:32 +00:00
out , err := c . policyStore . GetPolicy ( namespace . RootContext ( nil ) , "test" , PolicyTypeToken )
2015-04-02 00:44:43 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if out != nil {
t . Fatalf ( "policy should be gone" )
}
}
2015-05-28 00:53:42 +00:00
func TestSystemBackend_keyStatus ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "key-status" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-05-28 00:53:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
exp := map [ string ] interface { } {
"term" : 1 ,
}
delete ( resp . Data , "install_time" )
2021-02-25 20:27:25 +00:00
delete ( resp . Data , "encryptions" )
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
func TestSystemBackend_rotateConfig ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . ReadOperation , "rotate/config" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-03-28 19:40:48 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2021-02-25 20:27:25 +00:00
exp := map [ string ] interface { } {
"max_operations" : absoluteOperationMaximum ,
"interval" : 0 ,
"enabled" : true ,
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
req2 := logical . TestRequest ( t , logical . UpdateOperation , "rotate/config" )
2021-05-05 19:39:04 +00:00
req2 . Data [ "max_operations" ] = int64 ( 3221225472 )
2021-02-25 20:27:25 +00:00
req2 . Data [ "interval" ] = "5432h0m0s"
req2 . Data [ "enabled" ] = false
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req2 )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-03-28 19:40:48 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req2 . Path ) , req2 . Operation ) ,
resp ,
true ,
)
2021-02-25 20:27:25 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-03-28 19:40:48 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) , resp ,
true ,
)
2021-02-25 20:27:25 +00:00
exp = map [ string ] interface { } {
2021-05-05 19:39:04 +00:00
"max_operations" : int64 ( 3221225472 ) ,
2021-02-25 20:27:25 +00:00
"interval" : "5432h0m0s" ,
"enabled" : false ,
}
2015-05-28 00:53:42 +00:00
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
func TestSystemBackend_rotate ( t * testing . T ) {
b := testSystemBackend ( t )
2016-01-07 15:30:47 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "rotate" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-05-28 00:53:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
req = logical . TestRequest ( t , logical . ReadOperation , "key-status" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2015-05-28 00:53:42 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
exp := map [ string ] interface { } {
"term" : 2 ,
}
delete ( resp . Data , "install_time" )
2021-02-25 20:27:25 +00:00
delete ( resp . Data , "encryptions" )
2015-05-28 00:53:42 +00:00
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
2015-03-16 00:35:59 +00:00
func testSystemBackend ( t * testing . T ) logical . Backend {
2022-08-31 18:23:05 +00:00
t . Helper ( )
2015-03-29 23:18:08 +00:00
c , _ , _ := TestCoreUnsealed ( t )
2018-03-01 16:14:56 +00:00
return c . systemBackend
2017-09-15 04:21:35 +00:00
}
2016-09-29 04:01:28 +00:00
2017-09-15 04:21:35 +00:00
func testSystemBackendRaw ( t * testing . T ) logical . Backend {
2022-08-31 18:23:05 +00:00
t . Helper ( )
2017-09-15 04:21:35 +00:00
c , _ , _ := TestCoreUnsealedRaw ( t )
2018-03-01 16:14:56 +00:00
return c . systemBackend
2015-03-15 21:42:05 +00:00
}
2015-03-16 23:11:55 +00:00
2015-03-24 18:37:07 +00:00
func testCoreSystemBackend ( t * testing . T ) ( * Core , logical . Backend , string ) {
2022-08-31 18:23:05 +00:00
t . Helper ( )
2015-03-29 23:18:08 +00:00
c , _ , root := TestCoreUnsealed ( t )
2018-03-01 16:14:56 +00:00
return c , c . systemBackend , root
2017-09-15 04:21:35 +00:00
}
func testCoreSystemBackendRaw ( t * testing . T ) ( * Core , logical . Backend , string ) {
2022-08-31 18:23:05 +00:00
t . Helper ( )
2017-09-15 04:21:35 +00:00
c , _ , root := TestCoreUnsealedRaw ( t )
2018-03-01 16:14:56 +00:00
return c , c . systemBackend , root
2017-09-15 04:21:35 +00:00
}
2017-04-12 17:39:18 +00:00
func TestSystemBackend_PluginCatalog_CRUD ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
// Bootstrap the pluginCatalog
sym , err := filepath . EvalSymlinks ( os . TempDir ( ) )
if err != nil {
t . Fatalf ( "error: %v" , err )
}
c . pluginCatalog . directory = sym
2018-11-07 01:21:24 +00:00
req := logical . TestRequest ( t , logical . ListOperation , "plugins/catalog/database" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-12 17:39:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-11-07 01:21:24 +00:00
if len ( resp . Data [ "keys" ] . ( [ ] string ) ) != len ( c . builtinRegistry . Keys ( consts . PluginTypeDatabase ) ) {
t . Fatalf ( "Wrong number of plugins, got %d, expected %d" , len ( resp . Data [ "keys" ] . ( [ ] string ) ) , len ( builtinplugins . Registry . Keys ( consts . PluginTypeDatabase ) ) )
2017-04-12 17:39:18 +00:00
}
2018-11-07 01:21:24 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "plugins/catalog/database/mysql-database-plugin" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-12 17:39:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-09-09 20:03:07 +00:00
// Get deprecation status directly from the registry so we can compare it to the API response
deprecationStatus , _ := c . builtinRegistry . DeprecationStatus ( "mysql-database-plugin" , consts . PluginTypeDatabase )
2018-01-18 00:19:28 +00:00
actualRespData := resp . Data
expectedRespData := map [ string ] interface { } {
2022-09-09 20:03:07 +00:00
"name" : "mysql-database-plugin" ,
"command" : "" ,
"args" : [ ] string ( nil ) ,
"sha256" : "" ,
"builtin" : true ,
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
"version" : versions . GetBuiltinVersion ( consts . PluginTypeDatabase , "mysql-database-plugin" ) ,
2022-09-09 20:03:07 +00:00
"deprecation_status" : deprecationStatus . String ( ) ,
2017-04-12 17:39:18 +00:00
}
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
if ! reflect . DeepEqual ( actualRespData , expectedRespData ) {
t . Fatalf ( "expected did not match actual, got %#v\n expected %#v\n" , actualRespData , expectedRespData )
2017-04-12 17:39:18 +00:00
}
// Set a plugin
file , err := ioutil . TempFile ( os . TempDir ( ) , "temp" )
if err != nil {
t . Fatal ( err )
}
defer file . Close ( )
2018-01-18 00:19:28 +00:00
// Check we can only specify args in one of command or args.
2017-04-12 17:39:18 +00:00
command := fmt . Sprintf ( "%s --test" , filepath . Base ( file . Name ( ) ) )
2018-11-07 01:21:24 +00:00
req = logical . TestRequest ( t , logical . UpdateOperation , "plugins/catalog/database/test-plugin" )
2018-01-18 00:19:28 +00:00
req . Data [ "args" ] = [ ] string { "--foo" }
2017-04-12 17:39:18 +00:00
req . Data [ "sha_256" ] = hex . EncodeToString ( [ ] byte { '1' } )
req . Data [ "command" ] = command
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-12 17:39:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-03-20 18:54:10 +00:00
if resp . Error ( ) . Error ( ) != "must not specify args in command and args field" {
2018-01-18 00:19:28 +00:00
t . Fatalf ( "err: %v" , resp . Error ( ) )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-01-18 00:19:28 +00:00
delete ( req . Data , "args" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-01-18 00:19:28 +00:00
if err != nil || resp . Error ( ) != nil {
t . Fatalf ( "err: %v %v" , err , resp . Error ( ) )
}
2017-04-12 17:39:18 +00:00
2018-11-07 01:21:24 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "plugins/catalog/database/test-plugin" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-12 17:39:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-01-18 00:19:28 +00:00
actual := resp . Data
expected := map [ string ] interface { } {
"name" : "test-plugin" ,
"command" : filepath . Base ( file . Name ( ) ) ,
"args" : [ ] string { "--test" } ,
"sha256" : "31" ,
"builtin" : false ,
2022-08-25 20:31:42 +00:00
"version" : "" ,
2017-04-12 17:39:18 +00:00
}
Backend plugin system (#2874)
* Add backend plugin changes
* Fix totp backend plugin tests
* Fix logical/plugin InvalidateKey test
* Fix plugin catalog CRUD test, fix NoopBackend
* Clean up commented code block
* Fix system backend mount test
* Set plugin_name to omitempty, fix handleMountTable config parsing
* Clean up comments, keep shim connections alive until cleanup
* Include pluginClient, disallow LookupPlugin call from within a plugin
* Add wrapper around backendPluginClient for proper cleanup
* Add logger shim tests
* Add logger, storage, and system shim tests
* Use pointer receivers for system view shim
* Use plugin name if no path is provided on mount
* Enable plugins for auth backends
* Add backend type attribute, move builtin/plugin/package
* Fix merge conflict
* Fix missing plugin name in mount config
* Add integration tests on enabling auth backend plugins
* Remove dependency cycle on mock-plugin
* Add passthrough backend plugin, use logical.BackendType to determine lease generation
* Remove vault package dependency on passthrough package
* Add basic impl test for passthrough plugin
* Incorporate feedback; set b.backend after shims creation on backendPluginServer
* Fix totp plugin test
* Add plugin backends docs
* Fix tests
* Fix builtin/plugin tests
* Remove flatten from PluginRunner fields
* Move mock plugin to logical/plugin, remove totp and passthrough plugins
* Move pluginMap into newPluginClient
* Do not create storage RPC connection on HandleRequest and HandleExistenceCheck
* Change shim logger's Fatal to no-op
* Change BackendType to uint32, match UX backend types
* Change framework.Backend Setup signature
* Add Setup func to logical.Backend interface
* Move OptionallyEnableMlock call into plugin.Serve, update docs and comments
* Remove commented var in plugin package
* RegisterLicense on logical.Backend interface (#3017)
* Add RegisterLicense to logical.Backend interface
* Update RegisterLicense to use callback func on framework.Backend
* Refactor framework.Backend.RegisterLicense
* plugin: Prevent plugin.SystemViewClient.ResponseWrapData from getting JWTs
* plugin: Revert BackendType to remove TypePassthrough and related references
* Fix typo in plugin backends docs
2017-07-20 17:28:40 +00:00
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "expected did not match actual, got %#v\n expected %#v\n" , actual , expected )
2017-04-12 17:39:18 +00:00
}
// Delete plugin
2018-11-07 01:21:24 +00:00
req = logical . TestRequest ( t , logical . DeleteOperation , "plugins/catalog/database/test-plugin" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-12 17:39:18 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-11-07 01:21:24 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "plugins/catalog/database/test-plugin" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-04-25 04:24:19 +00:00
if resp != nil || err != nil {
t . Fatalf ( "expected nil response, plugin not deleted correctly got resp: %v, err: %v" , resp , err )
2017-04-12 17:39:18 +00:00
}
2022-08-25 20:31:42 +00:00
// Add a versioned plugin, and check we get the version back in the right form when we read.
req = logical . TestRequest ( t , logical . UpdateOperation , "plugins/catalog/database/test-plugin" )
req . Data [ "version" ] = "v0.1.0"
req . Data [ "sha_256" ] = hex . EncodeToString ( [ ] byte { '1' } )
req . Data [ "command" ] = command
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || resp . Error ( ) != nil {
t . Fatalf ( "err: %v %v" , err , resp . Error ( ) )
}
req = logical . TestRequest ( t , logical . ReadOperation , "plugins/catalog/database/test-plugin" )
req . Data [ "version" ] = "v0.1.0"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
actual = resp . Data
expected = map [ string ] interface { } {
"name" : "test-plugin" ,
"command" : filepath . Base ( file . Name ( ) ) ,
"args" : [ ] string { "--test" } ,
"sha256" : "31" ,
"builtin" : false ,
2022-08-31 18:23:05 +00:00
"version" : "v0.1.0" ,
2022-08-25 20:31:42 +00:00
}
if ! reflect . DeepEqual ( actual , expected ) {
t . Fatalf ( "expected did not match actual, got %#v\n expected %#v\n" , actual , expected )
}
// Delete versioned plugin
req = logical . TestRequest ( t , logical . DeleteOperation , "plugins/catalog/database/test-plugin" )
req . Data [ "version" ] = "0.1.0"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
req = logical . TestRequest ( t , logical . ReadOperation , "plugins/catalog/database/test-plugin" )
req . Data [ "version" ] = "0.1.0"
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if resp != nil || err != nil {
t . Fatalf ( "expected nil response, plugin not deleted correctly got resp: %v, err: %v" , resp , err )
}
2017-04-12 17:39:18 +00:00
}
2017-10-20 14:59:17 +00:00
2022-12-01 10:44:44 +00:00
func TestSystemBackend_PluginCatalog_ListPlugins_SucceedsWithAuditLogEnabled ( t * testing . T ) {
core , b , root := testCoreSystemBackend ( t )
tempDir := t . TempDir ( )
f , err := os . CreateTemp ( tempDir , "" )
if err != nil {
t . Fatal ( err )
}
// Enable audit logging.
req := logical . TestRequest ( t , logical . UpdateOperation , "audit/file" )
req . Data = map [ string ] any {
"type" : "file" ,
"options" : map [ string ] any {
"file_path" : f . Name ( ) ,
} ,
}
ctx := namespace . RootContext ( nil )
resp , err := b . HandleRequest ( ctx , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "resp: %#v, err: %v" , resp , err )
}
// List plugins
req = logical . TestRequest ( t , logical . ReadOperation , "sys/plugins/catalog" )
req . ClientToken = root
resp , err = core . HandleRequest ( ctx , req )
if err != nil || resp == nil || resp . IsError ( ) {
t . Fatalf ( "resp: %#v, err: %v" , resp , err )
}
}
2022-09-22 22:15:46 +00:00
func TestSystemBackend_PluginCatalog_CannotRegisterBuiltinPlugins ( t * testing . T ) {
c , b , _ := testCoreSystemBackend ( t )
// Bootstrap the pluginCatalog
sym , err := filepath . EvalSymlinks ( os . TempDir ( ) )
if err != nil {
t . Fatalf ( "error: %v" , err )
}
c . pluginCatalog . directory = sym
// Set a plugin
req := logical . TestRequest ( t , logical . UpdateOperation , "plugins/catalog/database/test-plugin" )
req . Data [ "sha256" ] = hex . EncodeToString ( [ ] byte { '1' } )
req . Data [ "command" ] = "foo"
req . Data [ "version" ] = "v1.2.3+special.builtin"
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if ! strings . Contains ( resp . Error ( ) . Error ( ) , "reserved metadata" ) {
t . Fatalf ( "err: %v" , resp . Error ( ) )
}
}
2017-10-20 14:59:17 +00:00
func TestSystemBackend_ToolsHash ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "tools/hash" )
req . Data = map [ string ] interface { } {
"input" : "dGhlIHF1aWNrIGJyb3duIGZveA==" ,
}
2023-03-24 23:11:39 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-10-20 14:59:17 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-03-24 23:11:39 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-10-20 14:59:17 +00:00
doRequest := func ( req * logical . Request , errExpected bool , expected string ) {
t . Helper ( )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-10-20 14:59:17 +00:00
if err != nil && ! errExpected {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
2023-03-24 23:11:39 +00:00
2017-10-20 14:59:17 +00:00
if errExpected {
if ! resp . IsError ( ) {
t . Fatalf ( "bad: got error response: %#v" , * resp )
}
return
2023-03-24 23:11:39 +00:00
} else {
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-10-20 14:59:17 +00:00
}
2023-03-24 23:11:39 +00:00
2017-10-20 14:59:17 +00:00
if resp . IsError ( ) {
t . Fatalf ( "bad: got error response: %#v" , * resp )
}
sum , ok := resp . Data [ "sum" ]
if ! ok {
t . Fatal ( "no sum key found in returned data" )
}
if sum . ( string ) != expected {
2021-12-08 18:29:33 +00:00
t . Fatalf ( "mismatched hashes: got: %s, expect: %s" , sum . ( string ) , expected )
2017-10-20 14:59:17 +00:00
}
}
// Test defaults -- sha2-256
doRequest ( req , false , "9ecb36561341d18eb65484e833efea61edc74b84cf5e6ae1b81c63533e25fc8f" )
// Test algorithm selection in the path
req . Path = "tools/hash/sha2-224"
doRequest ( req , false , "ea074a96cabc5a61f8298a2c470f019074642631a49e1c5e2f560865" )
// Reset and test algorithm selection in the data
req . Path = "tools/hash"
req . Data [ "algorithm" ] = "sha2-224"
doRequest ( req , false , "ea074a96cabc5a61f8298a2c470f019074642631a49e1c5e2f560865" )
req . Data [ "algorithm" ] = "sha2-384"
doRequest ( req , false , "15af9ec8be783f25c583626e9491dbf129dd6dd620466fdf05b3a1d0bb8381d30f4d3ec29f923ff1e09a0f6b337365a6" )
req . Data [ "algorithm" ] = "sha2-512"
doRequest ( req , false , "d9d380f29b97ad6a1d92e987d83fa5a02653301e1006dd2bcd51afa59a9147e9caedaf89521abc0f0b682adcd47fb512b8343c834a32f326fe9bef00542ce887" )
// Test returning as base64
req . Data [ "format" ] = "base64"
doRequest ( req , false , "2dOA8puXrWodkumH2D+loCZTMB4QBt0rzVGvpZqRR+nK7a+JUhq8DwtoKtzUf7USuDQ8g0oy8yb+m+8AVCzohw==" )
2021-12-08 18:29:33 +00:00
// Test SHA-3
req . Data [ "format" ] = "hex"
req . Data [ "algorithm" ] = "sha3-224"
doRequest ( req , false , "ced91e69d89c837e87cff960bd64fd9b9f92325fb9add8988d33d007" )
req . Data [ "algorithm" ] = "sha3-256"
doRequest ( req , false , "e4bd866ec3fa52df3b7842aa97b448bc859a7606cefcdad1715847f4b82a6c93" )
req . Data [ "algorithm" ] = "sha3-384"
doRequest ( req , false , "715cd38cbf8d0bab426b6a084d649760be555dd64b34de6db148a3fbf2cd2aa5d8b03eb6eda73a3e9a8769c00b4c2113" )
req . Data [ "algorithm" ] = "sha3-512"
doRequest ( req , false , "f7cac5ad830422a5408b36a60a60620687be180765a3e2895bc3bdbd857c9e08246c83064d4e3612f0cb927f3ead208413ab98624bf7b0617af0f03f62080976" )
2017-10-20 14:59:17 +00:00
// Test bad input/format/algorithm
req . Data [ "format" ] = "base92"
doRequest ( req , true , "" )
req . Data [ "format" ] = "hex"
req . Data [ "algorithm" ] = "foobar"
doRequest ( req , true , "" )
req . Data [ "algorithm" ] = "sha2-256"
req . Data [ "input" ] = "foobar"
doRequest ( req , true , "" )
}
func TestSystemBackend_ToolsRandom ( t * testing . T ) {
b := testSystemBackend ( t )
req := logical . TestRequest ( t , logical . UpdateOperation , "tools/random" )
2023-03-24 23:11:39 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-10-20 14:59:17 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-03-24 23:11:39 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-10-20 14:59:17 +00:00
doRequest := func ( req * logical . Request , errExpected bool , format string , numBytes int ) {
t . Helper ( )
getResponse := func ( ) [ ] byte {
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2017-10-20 14:59:17 +00:00
if err != nil && ! errExpected {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "expected non-nil response" )
}
if errExpected {
if ! resp . IsError ( ) {
t . Fatalf ( "bad: got error response: %#v" , * resp )
}
return nil
2023-03-24 23:11:39 +00:00
} else {
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2017-10-20 14:59:17 +00:00
}
2023-03-24 23:11:39 +00:00
2017-10-20 14:59:17 +00:00
if resp . IsError ( ) {
t . Fatalf ( "bad: got error response: %#v" , * resp )
}
if _ , ok := resp . Data [ "random_bytes" ] ; ! ok {
t . Fatal ( "no random_bytes found in response" )
}
outputStr := resp . Data [ "random_bytes" ] . ( string )
var outputBytes [ ] byte
switch format {
case "base64" :
outputBytes , err = base64 . StdEncoding . DecodeString ( outputStr )
case "hex" :
outputBytes , err = hex . DecodeString ( outputStr )
default :
t . Fatal ( "unknown format" )
}
if err != nil {
t . Fatal ( err )
}
return outputBytes
}
rand1 := getResponse ( )
// Expected error
if rand1 == nil {
return
}
rand2 := getResponse ( )
if len ( rand1 ) != numBytes || len ( rand2 ) != numBytes {
2018-03-20 18:54:10 +00:00
t . Fatal ( "length of output random bytes not what is expected" )
2017-10-20 14:59:17 +00:00
}
if reflect . DeepEqual ( rand1 , rand2 ) {
t . Fatal ( "found identical ouputs" )
}
}
// Test defaults
doRequest ( req , false , "base64" , 32 )
// Test size selection in the path
req . Path = "tools/random/24"
req . Data [ "format" ] = "hex"
doRequest ( req , false , "hex" , 24 )
// Test bad input/format
req . Path = "tools/random"
req . Data [ "format" ] = "base92"
doRequest ( req , true , "" , 0 )
req . Data [ "format" ] = "hex"
req . Data [ "bytes" ] = - 1
doRequest ( req , true , "" , 0 )
2019-07-25 01:22:23 +00:00
req . Data [ "format" ] = "hex"
req . Data [ "bytes" ] = maxBytes + 1
doRequest ( req , true , "" , 0 )
2017-10-20 14:59:17 +00:00
}
2018-03-20 03:16:33 +00:00
func TestSystemBackend_InternalUIMounts ( t * testing . T ) {
2018-04-23 22:00:02 +00:00
_ , b , rootToken := testCoreSystemBackend ( t )
2023-02-24 20:03:21 +00:00
systemBackend := b . ( * SystemBackend )
2018-03-20 03:16:33 +00:00
// Ensure no entries are in the endpoint as a starting point
req := logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts" )
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-20 03:16:33 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-24 20:03:21 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , systemBackend . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-20 03:16:33 +00:00
exp := map [ string ] interface { } {
"secret" : map [ string ] interface { } { } ,
"auth" : map [ string ] interface { } { } ,
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
2018-04-23 22:00:02 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts" )
req . ClientToken = rootToken
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-24 20:03:21 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , systemBackend . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-04-23 22:00:02 +00:00
exp = map [ string ] interface { } {
"secret" : map [ string ] interface { } {
"secret/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "kv" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "key/value secret storage" ,
"accessor" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "secret/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "secret/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2018-04-23 22:00:02 +00:00
"config" : map [ string ] interface { } {
"default_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "secret/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "secret/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
} ,
"local" : false ,
"seal_wrap" : false ,
"options" : map [ string ] string {
"version" : "1" ,
} ,
2022-09-20 11:35:50 +00:00
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "kv" ) ,
"running_sha256" : "" ,
2018-04-23 22:00:02 +00:00
} ,
"sys/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"type" : "system" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "system endpoints used for control, policy and debugging" ,
"accessor" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "sys/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "sys/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2018-04-23 22:00:02 +00:00
"config" : map [ string ] interface { } {
2019-02-15 18:45:55 +00:00
"default_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "sys/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "sys/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
"passthrough_request_headers" : [ ] string { "Accept" } ,
2018-04-23 22:00:02 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : true ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . DefaultBuiltinVersion ,
"running_sha256" : "" ,
2018-04-23 22:00:02 +00:00
} ,
"cubbyhole/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "per-token private secret storage" ,
"type" : "cubbyhole" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2018-04-23 22:00:02 +00:00
"config" : map [ string ] interface { } {
"default_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "cubbyhole/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
} ,
2022-09-20 11:35:50 +00:00
"local" : true ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "cubbyhole" ) ,
"running_sha256" : "" ,
2018-04-23 22:00:02 +00:00
} ,
"identity/" : map [ string ] interface { } {
2019-11-07 16:54:34 +00:00
"description" : "identity store" ,
"type" : "identity" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"accessor" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "identity/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "identity/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
2018-04-23 22:00:02 +00:00
"config" : map [ string ] interface { } {
2021-10-14 01:59:36 +00:00
"default_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "identity/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "default_lease_ttl" ] . ( int64 ) ,
"max_lease_ttl" : resp . Data [ "secret" ] . ( map [ string ] interface { } ) [ "identity/" ] . ( map [ string ] interface { } ) [ "config" ] . ( map [ string ] interface { } ) [ "max_lease_ttl" ] . ( int64 ) ,
"force_no_cache" : false ,
"passthrough_request_headers" : [ ] string { "Authorization" } ,
2018-04-23 22:00:02 +00:00
} ,
2022-09-20 11:35:50 +00:00
"local" : false ,
"seal_wrap" : false ,
"options" : map [ string ] string ( nil ) ,
"plugin_version" : "" ,
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeSecrets , "identity" ) ,
"running_sha256" : "" ,
2018-04-23 22:00:02 +00:00
} ,
} ,
"auth" : map [ string ] interface { } {
"token/" : map [ string ] interface { } {
"options" : map [ string ] string ( nil ) ,
"config" : map [ string ] interface { } {
"default_lease_ttl" : int64 ( 0 ) ,
"max_lease_ttl" : int64 ( 0 ) ,
"force_no_cache" : false ,
2018-10-15 16:56:24 +00:00
"token_type" : "default-service" ,
2018-04-23 22:00:02 +00:00
} ,
2019-11-07 16:54:34 +00:00
"type" : "token" ,
2019-10-17 17:33:00 +00:00
"external_entropy_access" : false ,
2019-11-07 16:54:34 +00:00
"description" : "token based credentials" ,
"accessor" : resp . Data [ "auth" ] . ( map [ string ] interface { } ) [ "token/" ] . ( map [ string ] interface { } ) [ "accessor" ] ,
"uuid" : resp . Data [ "auth" ] . ( map [ string ] interface { } ) [ "token/" ] . ( map [ string ] interface { } ) [ "uuid" ] ,
"local" : false ,
"seal_wrap" : false ,
2022-09-20 11:35:50 +00:00
"plugin_version" : "" ,
2022-09-23 10:19:38 +00:00
"running_plugin_version" : versions . GetBuiltinVersion ( consts . PluginTypeCredential , "token" ) ,
2022-09-20 11:35:50 +00:00
"running_sha256" : "" ,
2018-04-23 22:00:02 +00:00
} ,
} ,
}
2018-10-15 16:56:24 +00:00
if diff := deep . Equal ( resp . Data , exp ) ; diff != nil {
t . Fatal ( diff )
2018-04-23 22:00:02 +00:00
}
2018-03-20 03:16:33 +00:00
// Mount-tune an auth mount
req = logical . TestRequest ( t , logical . UpdateOperation , "auth/token/tune" )
req . Data [ "listing_visibility" ] = "unauth"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-09-18 03:03:00 +00:00
if resp . IsError ( ) || err != nil {
t . Fatalf ( "resp.Error: %v, err:%v" , resp . Error ( ) , err )
}
2018-03-20 03:16:33 +00:00
// Mount-tune a secret mount
req = logical . TestRequest ( t , logical . UpdateOperation , "mounts/secret/tune" )
req . Data [ "listing_visibility" ] = "unauth"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-09-18 03:03:00 +00:00
if resp . IsError ( ) || err != nil {
t . Fatalf ( "resp.Error: %v, err:%v" , resp . Error ( ) , err )
}
2018-03-20 03:16:33 +00:00
2023-02-15 20:00:06 +00:00
// validate the response structure for mount update
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-20 03:16:33 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts" )
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-03-20 03:16:33 +00:00
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2023-02-24 20:03:21 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , systemBackend . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-03-20 03:16:33 +00:00
exp = map [ string ] interface { } {
"secret" : map [ string ] interface { } {
"secret/" : map [ string ] interface { } {
"type" : "kv" ,
"description" : "key/value secret storage" ,
2018-04-23 22:00:02 +00:00
"options" : map [ string ] string { "version" : "1" } ,
2018-03-20 03:16:33 +00:00
} ,
} ,
"auth" : map [ string ] interface { } {
"token/" : map [ string ] interface { } {
"type" : "token" ,
"description" : "token based credentials" ,
2018-04-23 22:00:02 +00:00
"options" : map [ string ] string ( nil ) ,
2018-03-20 03:16:33 +00:00
} ,
} ,
}
if ! reflect . DeepEqual ( resp . Data , exp ) {
t . Fatalf ( "got: %#v expect: %#v" , resp . Data , exp )
}
}
2018-04-23 22:00:02 +00:00
func TestSystemBackend_InternalUIMount ( t * testing . T ) {
core , b , rootToken := testCoreSystemBackend ( t )
2023-02-24 20:03:21 +00:00
systemBackend := b . ( * SystemBackend )
2018-04-23 22:00:02 +00:00
req := logical . TestRequest ( t , logical . UpdateOperation , "policy/secret" )
req . ClientToken = rootToken
req . Data = map [ string ] interface { } {
"rules" : ` path "secret/foo/*" {
capabilities = [ "create" , "read" , "update" , "delete" , "list" ]
} ` ,
}
2018-11-05 16:11:32 +00:00
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "Bad %#v %#v" , err , resp )
}
req = logical . TestRequest ( t , logical . UpdateOperation , "mounts/kv" )
req . ClientToken = rootToken
req . Data = map [ string ] interface { } {
"type" : "kv" ,
}
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "Bad %#v %#v" , err , resp )
}
2018-04-23 22:16:10 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/kv/bar" )
2018-04-23 22:00:02 +00:00
req . ClientToken = rootToken
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "Bad %#v %#v" , err , resp )
}
2023-02-24 20:03:21 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , systemBackend . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-04-23 22:00:02 +00:00
if resp . Data [ "type" ] != "kv" {
t . Fatalf ( "Bad Response: %#v" , resp )
}
2018-10-15 16:56:24 +00:00
testMakeServiceTokenViaBackend ( t , core . tokenStore , rootToken , "tokenid" , "" , [ ] string { "secret" } )
2018-04-23 22:00:02 +00:00
2018-04-23 22:16:10 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/kv" )
2018-04-23 22:00:02 +00:00
req . ClientToken = "tokenid"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != logical . ErrPermissionDenied {
t . Fatal ( "expected permission denied error" )
}
2018-04-23 22:16:10 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/secret" )
2018-04-23 22:00:02 +00:00
req . ClientToken = "tokenid"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "Bad %#v %#v" , err , resp )
}
2023-02-24 20:03:21 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , systemBackend . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-04-23 22:00:02 +00:00
if resp . Data [ "type" ] != "kv" {
t . Fatalf ( "Bad Response: %#v" , resp )
}
2018-04-23 22:16:10 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/sys" )
2018-04-23 22:00:02 +00:00
req . ClientToken = "tokenid"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "Bad %#v %#v" , err , resp )
}
2023-02-24 20:03:21 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , systemBackend . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2018-04-23 22:00:02 +00:00
if resp . Data [ "type" ] != "system" {
t . Fatalf ( "Bad Response: %#v" , resp )
}
2018-04-23 22:16:10 +00:00
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/non-existent" )
2018-04-23 22:00:02 +00:00
req . ClientToken = "tokenid"
2018-11-05 16:11:32 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2018-04-23 22:00:02 +00:00
if err != logical . ErrPermissionDenied {
t . Fatal ( "expected permission denied error" )
}
}
2018-11-05 20:24:39 +00:00
func TestSystemBackend_OpenAPI ( t * testing . T ) {
_ , b , rootToken := testCoreSystemBackend ( t )
// Ensure no paths are reported if there is no token
2023-01-31 21:27:39 +00:00
{
req := logical . TestRequest ( t , logical . ReadOperation , "internal/specs/openapi" )
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
body := resp . Data [ "http_raw_body" ] . ( [ ] byte )
var oapi map [ string ] interface { }
err = jsonutil . DecodeJSON ( body , & oapi )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
exp := map [ string ] interface { } {
"openapi" : framework . OASVersion ,
"info" : map [ string ] interface { } {
"title" : "HashiCorp Vault API" ,
"description" : "HTTP API that gives you full access to Vault. All API routes are prefixed with `/v1/`." ,
"version" : version . GetVersion ( ) . Version ,
"license" : map [ string ] interface { } {
"name" : "Mozilla Public License 2.0" ,
"url" : "https://www.mozilla.org/en-US/MPL/2.0" ,
} ,
2018-11-05 20:24:39 +00:00
} ,
2023-01-31 21:27:39 +00:00
"paths" : map [ string ] interface { } { } ,
"components" : map [ string ] interface { } {
"schemas" : map [ string ] interface { } { } ,
} ,
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
if diff := deep . Equal ( oapi , exp ) ; diff != nil {
t . Fatal ( diff )
}
2018-11-05 20:24:39 +00:00
}
2023-01-31 21:27:39 +00:00
// Check that default paths are present with a root token (with and without generic_mount_paths)
for _ , genericMountPaths := range [ ] bool { false , true } {
req := logical . TestRequest ( t , logical . ReadOperation , "internal/specs/openapi" )
if genericMountPaths {
req . Data [ "generic_mount_paths" ] = true
}
req . ClientToken = rootToken
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
body := resp . Data [ "http_raw_body" ] . ( [ ] byte )
var oapi map [ string ] interface { }
err = jsonutil . DecodeJSON ( body , & oapi )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
doc , err := framework . NewOASDocumentFromMap ( oapi )
if err != nil {
t . Fatal ( err )
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
expectedSecretPrefix := "/secret/"
if genericMountPaths {
expectedSecretPrefix = "/{secret_mount_path}/"
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
pathSamples := [ ] struct {
path string
tag string
unpublished bool
} {
{ path : "/auth/token/lookup" , tag : "auth" } ,
{ path : "/cubbyhole/{path}" , tag : "secrets" } ,
{ path : "/identity/group/id" , tag : "identity" } ,
{ path : expectedSecretPrefix + "^.*$" , unpublished : true } ,
{ path : "/sys/policy" , tag : "system" } ,
2018-11-05 20:24:39 +00:00
}
2023-01-31 21:27:39 +00:00
for _ , path := range pathSamples {
if doc . Paths [ path . path ] == nil {
t . Fatalf ( "didn't find expected path %q." , path . path )
}
getOperation := doc . Paths [ path . path ] . Get
if getOperation == nil && ! path . unpublished {
t . Fatalf ( "path: %s; expected a get operation, but it was absent" , path . path )
}
if getOperation != nil && path . unpublished {
t . Fatalf ( "path: %s; expected absent get operation, but it was present" , path . path )
}
if ! path . unpublished {
tag := getOperation . Tags [ 0 ]
if tag != path . tag {
t . Fatalf ( "path: %s; expected tag: %s, actual: %s" , path . path , tag , path . tag )
}
}
2018-11-05 20:24:39 +00:00
}
2023-01-31 21:27:39 +00:00
// Simple check of response size (which is much larger than most
// Vault responses), mainly to catch mass omission of expected path data.
const minLen = 70000
if len ( body ) < minLen {
t . Fatalf ( "response size too small; expected: min %d, actual: %d" , minLen , len ( body ) )
}
2018-11-05 20:24:39 +00:00
}
// Test path-help response
2023-01-31 21:27:39 +00:00
{
req := logical . TestRequest ( t , logical . HelpOperation , "rotate" )
req . ClientToken = rootToken
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
doc := resp . Data [ "openapi" ] . ( * framework . OASDocument )
if len ( doc . Paths ) != 1 {
t . Fatalf ( "expected 1 path, actual: %d" , len ( doc . Paths ) )
}
2018-11-05 20:24:39 +00:00
2023-01-31 21:27:39 +00:00
if doc . Paths [ "/rotate" ] == nil {
t . Fatalf ( "expected to find path '/rotate'" )
}
2018-11-05 20:24:39 +00:00
}
}
2019-04-10 21:46:17 +00:00
func TestSystemBackend_PathWildcardPreflight ( t * testing . T ) {
core , b , _ := testCoreSystemBackend ( t )
ctx := namespace . RootContext ( nil )
// Add another mount
me := & MountEntry {
Table : mountTableType ,
2020-06-29 22:36:22 +00:00
Path : sanitizePath ( "kv-v1" ) ,
2019-04-10 21:46:17 +00:00
Type : "kv" ,
Options : map [ string ] string { "version" : "1" } ,
}
if err := core . mount ( ctx , me ) ; err != nil {
t . Fatal ( err )
}
// Create the policy, designed to fail
rules := ` path "foo" { capabilities = ["read"] } `
req := logical . TestRequest ( t , logical . UpdateOperation , "policy/foo" )
req . Data [ "rules" ] = rules
resp , err := b . HandleRequest ( ctx , req )
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp )
}
if resp != nil && ( resp . IsError ( ) || len ( resp . Data ) > 0 ) {
t . Fatalf ( "bad: %#v" , resp )
}
if err := core . identityStore . upsertEntity ( ctx , & identity . Entity {
2019-05-07 19:29:51 +00:00
ID : "abcd" ,
Name : "abcd" ,
BucketKey : "abcd" ,
2019-04-10 21:46:17 +00:00
} , nil , false ) ; err != nil {
t . Fatal ( err )
}
te := & logical . TokenEntry {
TTL : 300 * time . Second ,
EntityID : "abcd" ,
Policies : [ ] string { "default" , "foo" } ,
NamespaceID : namespace . RootNamespaceID ,
}
if err := core . tokenStore . create ( ctx , te ) ; err != nil {
t . Fatal ( err )
}
t . Logf ( "token id: %s" , te . ID )
if err := core . expiration . RegisterAuth ( ctx , te , & logical . Auth {
LeaseOptions : logical . LeaseOptions {
TTL : te . TTL ,
} ,
ClientToken : te . ID ,
Accessor : te . Accessor ,
Orphan : true ,
2022-07-05 17:02:00 +00:00
} , "" ) ; err != nil {
2019-04-10 21:46:17 +00:00
t . Fatal ( err )
}
// Check the mount access func
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/kv-v1/baz" )
req . ClientToken = te . ID
resp , err = b . HandleRequest ( ctx , req )
if err == nil || ! strings . Contains ( err . Error ( ) , "permission denied" ) {
t . Fatalf ( "expected 403, got err: %v" , err )
}
// Modify policy to pass
rules = ` path "kv-v1/+" { capabilities = ["read"] } `
req = logical . TestRequest ( t , logical . UpdateOperation , "policy/foo" )
req . Data [ "rules" ] = rules
resp , err = b . HandleRequest ( ctx , req )
if err != nil {
t . Fatalf ( "err: %v %#v" , err , resp )
}
if resp != nil && ( resp . IsError ( ) || len ( resp . Data ) > 0 ) {
t . Fatalf ( "bad: %#v" , resp )
}
// Check the mount access func again
req = logical . TestRequest ( t , logical . ReadOperation , "internal/ui/mounts/kv-v1/baz" )
req . ClientToken = te . ID
resp , err = b . HandleRequest ( ctx , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
}
2020-05-27 18:28:00 +00:00
func TestHandlePoliciesPasswordSet ( t * testing . T ) {
type testCase struct {
inputData * framework . FieldData
storage * logical . InmemStorage
expectedResp * logical . Response
expectErr bool
expectedStore map [ string ] * logical . StorageEntry
}
tests := map [ string ] testCase {
"missing policy name" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"policy" : ` length = 20
rule "charset" {
charset = "abcdefghij"
} ` ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"missing policy" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"garbage policy" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
"policy" : "hasdukfhiuashdfoiasjdf" ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"storage failure" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
"policy" : "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ,
} ) ,
storage : new ( logical . InmemStorage ) . FailPut ( true ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"impossible policy" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
"policy" : "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"a\"\n" +
" min-chars = 30\n" +
"}" ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"not base64 encoded" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
"policy" : "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : & logical . Response {
Data : map [ string ] interface { } {
logical . HTTPContentType : "application/json" ,
logical . HTTPStatusCode : http . StatusNoContent ,
} ,
} ,
expectErr : false ,
expectedStore : makeStorageMap ( storageEntry ( t , "testpolicy" , "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ) ,
} ,
"base64 encoded" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
"policy" : base64Encode (
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : & logical . Response {
Data : map [ string ] interface { } {
logical . HTTPContentType : "application/json" ,
logical . HTTPStatusCode : http . StatusNoContent ,
} ,
} ,
expectErr : false ,
expectedStore : makeStorageMap ( storageEntry ( t , "testpolicy" ,
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ) ,
} ,
}
for name , test := range tests {
t . Run ( name , func ( t * testing . T ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 100 * time . Millisecond )
defer cancel ( )
req := & logical . Request {
Storage : test . storage ,
}
b := & SystemBackend { }
actualResp , err := b . handlePoliciesPasswordSet ( ctx , req , test . inputData )
if test . expectErr && err == nil {
t . Fatalf ( "err expected, got nil" )
}
if ! test . expectErr && err != nil {
t . Fatalf ( "no error expected, got: %s" , err )
}
if ! reflect . DeepEqual ( actualResp , test . expectedResp ) {
t . Fatalf ( "Actual response: %#v\nExpected response: %#v" , actualResp , test . expectedResp )
}
actualStore := LogicalToMap ( t , ctx , test . storage )
if ! reflect . DeepEqual ( actualStore , test . expectedStore ) {
t . Fatalf ( "Actual: %#v\nActual: %#v" , dereferenceMap ( actualStore ) , dereferenceMap ( test . expectedStore ) )
}
} )
}
}
func TestHandlePoliciesPasswordGet ( t * testing . T ) {
type testCase struct {
inputData * framework . FieldData
storage * logical . InmemStorage
expectedResp * logical . Response
expectErr bool
expectedStore map [ string ] * logical . StorageEntry
}
tests := map [ string ] testCase {
"missing policy name" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } { } ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"storage error" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : new ( logical . InmemStorage ) . FailGet ( true ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"missing value" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"good value" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : makeStorage ( t , storageEntry ( t , "testpolicy" ,
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ) ,
expectedResp : & logical . Response {
Data : map [ string ] interface { } {
"policy" : "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ,
} ,
} ,
expectErr : false ,
expectedStore : makeStorageMap ( storageEntry ( t , "testpolicy" ,
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ) ,
} ,
}
for name , test := range tests {
t . Run ( name , func ( t * testing . T ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 10 * time . Millisecond )
defer cancel ( )
req := & logical . Request {
Storage : test . storage ,
}
b := & SystemBackend { }
actualResp , err := b . handlePoliciesPasswordGet ( ctx , req , test . inputData )
if test . expectErr && err == nil {
t . Fatalf ( "err expected, got nil" )
}
if ! test . expectErr && err != nil {
t . Fatalf ( "no error expected, got: %s" , err )
}
if ! reflect . DeepEqual ( actualResp , test . expectedResp ) {
t . Fatalf ( "Actual response: %#v\nExpected response: %#v" , actualResp , test . expectedResp )
}
actualStore := LogicalToMap ( t , ctx , test . storage )
if ! reflect . DeepEqual ( actualStore , test . expectedStore ) {
t . Fatalf ( "Actual: %#v\nActual: %#v" , dereferenceMap ( actualStore ) , dereferenceMap ( test . expectedStore ) )
}
} )
}
}
func TestHandlePoliciesPasswordDelete ( t * testing . T ) {
type testCase struct {
inputData * framework . FieldData
storage logical . Storage
expectedResp * logical . Response
expectErr bool
expectedStore map [ string ] * logical . StorageEntry
}
tests := map [ string ] testCase {
"missing policy name" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } { } ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"storage failure" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : new ( logical . InmemStorage ) . FailDelete ( true ) ,
expectedResp : nil ,
expectErr : true ,
expectedStore : map [ string ] * logical . StorageEntry { } ,
} ,
"successful delete" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : makeStorage ( t ,
& logical . StorageEntry {
Key : getPasswordPolicyKey ( "testpolicy" ) ,
Value : toJson ( t ,
passwordPolicyConfig {
HCLPolicy : "length = 18\n" +
"rule \"charset\" {\n" +
" charset=\"ABCDEFGHIJ\"\n" +
"}" ,
} ) ,
} ,
& logical . StorageEntry {
Key : getPasswordPolicyKey ( "unrelated_policy" ) ,
Value : toJson ( t ,
passwordPolicyConfig {
HCLPolicy : "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ,
} ) ,
} ,
) ,
expectedResp : nil ,
expectErr : false ,
expectedStore : makeStorageMap ( storageEntry ( t , "unrelated_policy" ,
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ) ,
} ,
}
for name , test := range tests {
t . Run ( name , func ( t * testing . T ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 10 * time . Millisecond )
defer cancel ( )
req := & logical . Request {
Storage : test . storage ,
}
b := & SystemBackend { }
actualResp , err := b . handlePoliciesPasswordDelete ( ctx , req , test . inputData )
if test . expectErr && err == nil {
t . Fatalf ( "err expected, got nil" )
}
if ! test . expectErr && err != nil {
t . Fatalf ( "no error expected, got: %s" , err )
}
if ! reflect . DeepEqual ( actualResp , test . expectedResp ) {
t . Fatalf ( "Actual response: %#v\nExpected response: %#v" , actualResp , test . expectedResp )
}
actualStore := LogicalToMap ( t , ctx , test . storage )
if ! reflect . DeepEqual ( actualStore , test . expectedStore ) {
t . Fatalf ( "Actual: %#v\nExpected: %#v" , dereferenceMap ( actualStore ) , dereferenceMap ( test . expectedStore ) )
}
} )
}
}
2022-01-24 21:42:14 +00:00
func TestHandlePoliciesPasswordList ( t * testing . T ) {
type testCase struct {
storage logical . Storage
expectErr bool
expectedResp * logical . Response
}
tests := map [ string ] testCase {
"no policies" : {
storage : new ( logical . InmemStorage ) ,
expectedResp : & logical . Response {
Data : map [ string ] interface { } { } ,
} ,
} ,
"one policy" : {
storage : makeStorage ( t ,
& logical . StorageEntry {
Key : getPasswordPolicyKey ( "testpolicy" ) ,
Value : toJson ( t ,
passwordPolicyConfig {
HCLPolicy : "length = 18\n" +
"rule \"charset\" {\n" +
" charset=\"ABCDEFGHIJ\"\n" +
"}" ,
} ) ,
} ,
) ,
expectedResp : & logical . Response {
Data : map [ string ] interface { } {
"keys" : [ ] string { "testpolicy" } ,
} ,
} ,
} ,
"two policies" : {
storage : makeStorage ( t ,
& logical . StorageEntry {
Key : getPasswordPolicyKey ( "testpolicy" ) ,
Value : toJson ( t ,
passwordPolicyConfig {
HCLPolicy : "length = 18\n" +
"rule \"charset\" {\n" +
" charset=\"ABCDEFGHIJ\"\n" +
"}" ,
} ) ,
} ,
& logical . StorageEntry {
Key : getPasswordPolicyKey ( "unrelated_policy" ) ,
Value : toJson ( t ,
passwordPolicyConfig {
HCLPolicy : "length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ,
} ) ,
} ,
) ,
expectedResp : & logical . Response {
Data : map [ string ] interface { } {
"keys" : [ ] string {
"testpolicy" ,
"unrelated_policy" ,
} ,
} ,
} ,
} ,
"storage failure" : {
storage : new ( logical . InmemStorage ) . FailList ( true ) ,
expectErr : true ,
} ,
}
for name , test := range tests {
t . Run ( name , func ( t * testing . T ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 10 * time . Millisecond )
defer cancel ( )
req := & logical . Request {
Storage : test . storage ,
}
b := & SystemBackend { }
actualResp , err := b . handlePoliciesPasswordList ( ctx , req , nil )
if test . expectErr && err == nil {
t . Fatalf ( "err expected, got nil" )
}
if ! test . expectErr && err != nil {
t . Fatalf ( "no error expected, got: %s" , err )
}
if ! reflect . DeepEqual ( actualResp , test . expectedResp ) {
t . Fatalf ( "Actual response: %#v\nExpected response: %#v" , actualResp , test . expectedResp )
}
} )
}
}
2020-05-27 18:28:00 +00:00
func TestHandlePoliciesPasswordGenerate ( t * testing . T ) {
t . Run ( "errors" , func ( t * testing . T ) {
type testCase struct {
timeout time . Duration
inputData * framework . FieldData
storage * logical . InmemStorage
expectedResp * logical . Response
expectErr bool
}
tests := map [ string ] testCase {
"missing policy name" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } { } ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
} ,
"storage failure" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : new ( logical . InmemStorage ) . FailGet ( true ) ,
expectedResp : nil ,
expectErr : true ,
} ,
"policy does not exist" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : new ( logical . InmemStorage ) ,
expectedResp : nil ,
expectErr : true ,
} ,
"policy improperly saved" : {
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : makeStorage ( t , storageEntry ( t , "testpolicy" , "badpolicy" ) ) ,
expectedResp : nil ,
expectErr : true ,
} ,
"failed to generate" : {
timeout : 0 * time . Second , // Timeout immediately
inputData : passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} ) ,
storage : makeStorage ( t , storageEntry ( t , "testpolicy" ,
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" ) ) ,
expectedResp : nil ,
expectErr : true ,
} ,
}
for name , test := range tests {
t . Run ( name , func ( t * testing . T ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , test . timeout )
defer cancel ( )
req := & logical . Request {
Storage : test . storage ,
}
b := & SystemBackend { }
actualResp , err := b . handlePoliciesPasswordGenerate ( ctx , req , test . inputData )
if test . expectErr && err == nil {
t . Fatalf ( "err expected, got nil" )
}
if ! test . expectErr && err != nil {
t . Fatalf ( "no error expected, got: %s" , err )
}
if ! reflect . DeepEqual ( actualResp , test . expectedResp ) {
t . Fatalf ( "Actual response: %#v\nExpected response: %#v" , actualResp , test . expectedResp )
}
} )
}
} )
t . Run ( "success" , func ( t * testing . T ) {
2020-06-11 22:08:20 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
2020-05-27 18:28:00 +00:00
defer cancel ( )
policyEntry := storageEntry ( t , "testpolicy" ,
"length = 20\n" +
"rule \"charset\" {\n" +
" charset=\"abcdefghij\"\n" +
"}" )
storage := makeStorage ( t , policyEntry )
inputData := passwordPoliciesFieldData ( map [ string ] interface { } {
"name" : "testpolicy" ,
} )
expectedResp := & logical . Response {
Data : map [ string ] interface { } {
// Doesn't include the password as that's pulled out and compared separately
} ,
}
// Password assertions
expectedPassLen := 20
rules := [ ] random . Rule {
random . CharsetRule {
Charset : [ ] rune ( "abcdefghij" ) ,
MinChars : expectedPassLen ,
} ,
}
// Run the test a bunch of times to help ensure we don't have flaky behavior
for i := 0 ; i < 1000 ; i ++ {
req := & logical . Request {
Storage : storage ,
}
b := & SystemBackend { }
actualResp , err := b . handlePoliciesPasswordGenerate ( ctx , req , inputData )
if err != nil {
t . Fatalf ( "no error expected, got: %s" , err )
}
2021-09-27 17:55:29 +00:00
assertTrue ( t , actualResp != nil , "response is nil" )
assertTrue ( t , actualResp . Data != nil , "expected data, got nil" )
2020-05-27 18:28:00 +00:00
assertHasKey ( t , actualResp . Data , "password" , "password key not found in data" )
assertIsString ( t , actualResp . Data [ "password" ] , "password key should have a string value" )
password := actualResp . Data [ "password" ] . ( string )
// Delete the password so the rest of the response can be compared
delete ( actualResp . Data , "password" )
2021-09-27 17:55:29 +00:00
assertTrue ( t , reflect . DeepEqual ( actualResp , expectedResp ) , "Actual response: %#v\nExpected response: %#v" , actualResp , expectedResp )
2020-05-27 18:28:00 +00:00
// Check to make sure the password is correctly formatted
passwordLength := len ( [ ] rune ( password ) )
if passwordLength != expectedPassLen {
t . Fatalf ( "password is %d characters but should be %d" , passwordLength , expectedPassLen )
}
for _ , rule := range rules {
if ! rule . Pass ( [ ] rune ( password ) ) {
t . Fatalf ( "password %s does not have the correct characters" , password )
}
}
}
} )
}
2021-09-27 17:55:29 +00:00
func assertTrue ( t * testing . T , pass bool , f string , vals ... interface { } ) {
2020-05-27 18:28:00 +00:00
t . Helper ( )
if ! pass {
t . Fatalf ( f , vals ... )
}
}
func assertHasKey ( t * testing . T , m map [ string ] interface { } , key string , f string , vals ... interface { } ) {
t . Helper ( )
_ , exists := m [ key ]
if ! exists {
t . Fatalf ( f , vals ... )
}
}
func assertIsString ( t * testing . T , val interface { } , f string , vals ... interface { } ) {
t . Helper ( )
_ , ok := val . ( string )
if ! ok {
t . Fatalf ( f , vals ... )
}
}
func passwordPoliciesFieldData ( raw map [ string ] interface { } ) * framework . FieldData {
return & framework . FieldData {
Raw : raw ,
Schema : map [ string ] * framework . FieldSchema {
2021-04-08 16:43:39 +00:00
"name" : {
2020-05-27 18:28:00 +00:00
Type : framework . TypeString ,
Description : "The name of the password policy." ,
} ,
2021-04-08 16:43:39 +00:00
"policy" : {
2020-05-27 18:28:00 +00:00
Type : framework . TypeString ,
Description : "The password policy" ,
} ,
} ,
}
}
func base64Encode ( data string ) string {
return base64 . StdEncoding . EncodeToString ( [ ] byte ( data ) )
}
func toJson ( t * testing . T , val interface { } ) [ ] byte {
t . Helper ( )
b , err := jsonutil . EncodeJSON ( val )
if err != nil {
t . Fatalf ( "Unable to marshal to JSON: %s" , err )
}
return b
}
func storageEntry ( t * testing . T , key string , policy string ) * logical . StorageEntry {
return & logical . StorageEntry {
Key : getPasswordPolicyKey ( key ) ,
Value : toJson ( t , passwordPolicyConfig {
HCLPolicy : policy ,
} ) ,
}
}
func makeStorageMap ( entries ... * logical . StorageEntry ) map [ string ] * logical . StorageEntry {
m := map [ string ] * logical . StorageEntry { }
for _ , entry := range entries {
m [ entry . Key ] = entry
}
return m
}
func dereferenceMap ( store map [ string ] * logical . StorageEntry ) map [ string ] interface { } {
m := map [ string ] interface { } { }
for k , v := range store {
m [ k ] = map [ string ] string {
"Key" : v . Key ,
"Value" : string ( v . Value ) ,
}
}
return m
}
type walkFunc func ( * logical . StorageEntry ) error
// WalkLogicalStorage applies the provided walkFunc against each entry in the logical storage.
// This operates as a breadth first search.
// TODO: Figure out a place for this to live permanently. This is generic and should be in a helper package somewhere.
// At the time of writing, none of these locations work due to import cycles:
// - vault/helper/testhelpers
// - vault/helper/testhelpers/logical
// - vault/helper/testhelpers/teststorage
func WalkLogicalStorage ( ctx context . Context , store logical . Storage , walker walkFunc ) ( err error ) {
if store == nil {
return fmt . Errorf ( "no storage provided" )
}
if walker == nil {
return fmt . Errorf ( "no walk function provided" )
}
keys , err := store . List ( ctx , "" )
if err != nil {
return fmt . Errorf ( "unable to list root keys: %w" , err )
}
// Non-recursive breadth-first search through all keys
for i := 0 ; i < len ( keys ) ; i ++ {
key := keys [ i ]
entry , err := store . Get ( ctx , key )
if err != nil {
return fmt . Errorf ( "unable to retrieve key at [%s]: %w" , key , err )
}
if entry != nil {
err = walker ( entry )
if err != nil {
return err
}
}
if strings . HasSuffix ( key , "/" ) {
// Directory
subkeys , err := store . List ( ctx , key )
if err != nil {
return fmt . Errorf ( "unable to list keys at [%s]: %w" , key , err )
}
// Append the sub-keys to the keys slice so it searches into the sub-directory
for _ , subkey := range subkeys {
// Avoids infinite loop if the subkey is empty which then repeats indefinitely
if subkey == "" {
continue
}
subkey = fmt . Sprintf ( "%s%s" , key , subkey )
keys = append ( keys , subkey )
}
}
}
return nil
}
// LogicalToMap retrieves all entries in the store and returns them as a map of key -> StorageEntry
func LogicalToMap ( t * testing . T , ctx context . Context , store logical . Storage ) ( data map [ string ] * logical . StorageEntry ) {
data = map [ string ] * logical . StorageEntry { }
f := func ( entry * logical . StorageEntry ) error {
data [ entry . Key ] = entry
return nil
}
err := WalkLogicalStorage ( ctx , store , f )
if err != nil {
t . Fatalf ( "Unable to walk the storage: %s" , err )
}
return data
}
// Ensure the WalkLogicalStorage function works
func TestWalkLogicalStorage ( t * testing . T ) {
type testCase struct {
entries [ ] * logical . StorageEntry
}
tests := map [ string ] testCase {
"no entries" : {
entries : [ ] * logical . StorageEntry { } ,
} ,
"one entry" : {
entries : [ ] * logical . StorageEntry {
{
Key : "root" ,
} ,
} ,
} ,
"many entries" : {
entries : [ ] * logical . StorageEntry {
// Alphabetical, breadth-first
{ Key : "bar" } ,
{ Key : "foo" } ,
{ Key : "bar/sub-bar1" } ,
{ Key : "bar/sub-bar2" } ,
{ Key : "foo/sub-foo1" } ,
{ Key : "foo/sub-foo2" } ,
{ Key : "foo/sub-foo3" } ,
{ Key : "bar/sub-bar1/sub-sub-bar1" } ,
{ Key : "bar/sub-bar1/sub-sub-bar2" } ,
{ Key : "bar/sub-bar2/sub-sub-bar1" } ,
{ Key : "foo/sub-foo1/sub-sub-foo1" } ,
{ Key : "foo/sub-foo2/sub-sub-foo1" } ,
{ Key : "foo/sub-foo3/sub-sub-foo1" } ,
{ Key : "foo/sub-foo3/sub-sub-foo2" } ,
} ,
} ,
"sub key without root key" : {
entries : [ ] * logical . StorageEntry {
{ Key : "foo/bar/baz" } ,
} ,
} ,
"key with trailing slash" : {
entries : [ ] * logical . StorageEntry {
{ Key : "foo/" } ,
} ,
} ,
"double slash" : {
entries : [ ] * logical . StorageEntry {
{ Key : "foo//" } ,
{ Key : "foo//bar" } ,
} ,
} ,
}
for name , test := range tests {
t . Run ( name , func ( t * testing . T ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 10 * time . Second )
defer cancel ( )
store := makeStorage ( t , test . entries ... )
actualEntries := [ ] * logical . StorageEntry { }
f := func ( entry * logical . StorageEntry ) error {
actualEntries = append ( actualEntries , entry )
return nil
}
err := WalkLogicalStorage ( ctx , store , f )
if err != nil {
t . Fatalf ( "Failed to walk storage: %s" , err )
}
if ! reflect . DeepEqual ( actualEntries , test . entries ) {
t . Fatalf ( "Actual: %#v\nExpected: %#v" , actualEntries , test . entries )
}
} )
}
}
func makeStorage ( t * testing . T , entries ... * logical . StorageEntry ) * logical . InmemStorage {
t . Helper ( )
ctx := context . Background ( )
store := new ( logical . InmemStorage )
for _ , entry := range entries {
err := store . Put ( ctx , entry )
if err != nil {
t . Fatalf ( "Unable to load test storage: %s" , err )
}
}
return store
}
2021-06-02 16:11:30 +00:00
func leaseLimitFieldData ( limit string ) * framework . FieldData {
raw := make ( map [ string ] interface { } )
raw [ "limit" ] = limit
return & framework . FieldData {
Raw : raw ,
Schema : map [ string ] * framework . FieldSchema {
"limit" : {
Type : framework . TypeString ,
Default : "" ,
Description : "limit return results" ,
} ,
} ,
}
}
func TestProcessLimit ( t * testing . T ) {
testCases := [ ] struct {
d * framework . FieldData
expectReturnAll bool
expectLimit int
expectErr bool
} {
{
d : leaseLimitFieldData ( "500" ) ,
expectReturnAll : false ,
expectLimit : 500 ,
expectErr : false ,
} ,
{
d : leaseLimitFieldData ( "" ) ,
expectReturnAll : false ,
expectLimit : MaxIrrevocableLeasesToReturn ,
expectErr : false ,
} ,
{
d : leaseLimitFieldData ( "none" ) ,
expectReturnAll : true ,
expectLimit : 10000 ,
expectErr : false ,
} ,
{
d : leaseLimitFieldData ( "NoNe" ) ,
expectReturnAll : true ,
expectLimit : 10000 ,
expectErr : false ,
} ,
{
d : leaseLimitFieldData ( "hello_world" ) ,
expectReturnAll : false ,
expectLimit : 0 ,
expectErr : true ,
} ,
{
d : leaseLimitFieldData ( "0" ) ,
expectReturnAll : false ,
expectLimit : 0 ,
expectErr : true ,
} ,
{
d : leaseLimitFieldData ( "-1" ) ,
expectReturnAll : false ,
expectLimit : 0 ,
expectErr : true ,
} ,
}
for i , tc := range testCases {
returnAll , limit , err := processLimit ( tc . d )
if returnAll != tc . expectReturnAll {
t . Errorf ( "bad return all for test case %d. expected %t, got %t" , i , tc . expectReturnAll , returnAll )
}
if limit != tc . expectLimit {
t . Errorf ( "bad limit for test case %d. expected %d, got %d" , i , tc . expectLimit , limit )
}
haveErr := err != nil
if haveErr != tc . expectErr {
t . Errorf ( "bad error status for test case %d. expected error: %t, got error: %t" , i , tc . expectErr , haveErr )
if err != nil {
t . Errorf ( "error was: %v" , err )
}
}
}
}
2022-06-27 15:39:53 +00:00
func TestSystemBackend_Loggers ( t * testing . T ) {
testCases := [ ] struct {
2022-11-28 16:18:36 +00:00
level string
expectedLevel string
expectError bool
2022-06-27 15:39:53 +00:00
} {
{
2022-11-28 16:18:36 +00:00
"trace" ,
2022-06-27 15:39:53 +00:00
"trace" ,
false ,
} ,
{
2022-11-28 16:18:36 +00:00
"debug" ,
2022-06-27 15:39:53 +00:00
"debug" ,
false ,
} ,
{
"notice" ,
2022-11-28 16:18:36 +00:00
"info" ,
2022-06-27 15:39:53 +00:00
false ,
} ,
{
2022-11-28 16:18:36 +00:00
"info" ,
2022-06-27 15:39:53 +00:00
"info" ,
false ,
} ,
{
2022-11-28 16:18:36 +00:00
"warn" ,
2022-06-27 15:39:53 +00:00
"warn" ,
false ,
} ,
{
"warning" ,
2022-11-28 16:18:36 +00:00
"warn" ,
2022-06-27 15:39:53 +00:00
false ,
} ,
{
"err" ,
2022-11-28 16:18:36 +00:00
"error" ,
2022-06-27 15:39:53 +00:00
false ,
} ,
{
2022-11-28 16:18:36 +00:00
"error" ,
2022-06-27 15:39:53 +00:00
"error" ,
false ,
} ,
{
"" ,
2022-11-28 16:18:36 +00:00
"info" ,
2022-06-27 15:39:53 +00:00
true ,
} ,
{
"invalid" ,
2022-11-28 16:18:36 +00:00
"" ,
2022-06-27 15:39:53 +00:00
true ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( fmt . Sprintf ( "all-loggers-%s" , tc . level ) , func ( t * testing . T ) {
t . Parallel ( )
core , b , _ := testCoreSystemBackend ( t )
2022-11-28 16:18:36 +00:00
// Test core overrides logging level outside of config,
// an initial delete will ensure that we an initial read
// to get expected values is based off of config and not
// the test override that is hidden from this test
2022-06-27 15:39:53 +00:00
req := & logical . Request {
2022-11-28 16:18:36 +00:00
Path : "loggers" ,
Operation : logical . DeleteOperation ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-11-28 16:18:36 +00:00
req = & logical . Request {
Path : "loggers" ,
Operation : logical . ReadOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-11-28 16:18:36 +00:00
initialLoggers := resp . Data
req = & logical . Request {
2022-06-27 15:39:53 +00:00
Path : "loggers" ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"level" : tc . level ,
} ,
}
2022-11-28 16:18:36 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2022-06-27 15:39:53 +00:00
respIsError := resp != nil && resp . IsError ( )
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-06-27 15:39:53 +00:00
if err != nil || ( ! tc . expectError && respIsError ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
if tc . expectError && ! respIsError {
t . Fatalf ( "expected response error, resp: %#v" , resp )
}
if ! tc . expectError {
2022-11-28 16:18:36 +00:00
req = & logical . Request {
Path : "loggers" ,
Operation : logical . ReadOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-06-27 15:39:53 +00:00
for _ , logger := range core . allLoggers {
2022-11-28 16:18:36 +00:00
loggerName := logger . Name ( )
levelRaw , ok := resp . Data [ loggerName ]
if ! ok {
t . Errorf ( "logger %q not found in response" , loggerName )
}
if levelStr := levelRaw . ( string ) ; levelStr != tc . expectedLevel {
t . Errorf ( "unexpected level of logger %q, expected: %s, actual: %s" , loggerName , tc . expectedLevel , levelStr )
2022-06-27 15:39:53 +00:00
}
}
}
req = & logical . Request {
2022-11-28 16:18:36 +00:00
Path : "loggers" ,
2022-06-27 15:39:53 +00:00
Operation : logical . DeleteOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-11-28 16:18:36 +00:00
req = & logical . Request {
Path : "loggers" ,
Operation : logical . ReadOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
2023-02-15 20:00:06 +00:00
schema . ValidateResponse (
t ,
schema . GetResponseSchema ( t , b . ( * SystemBackend ) . Route ( req . Path ) , req . Operation ) ,
resp ,
true ,
)
2022-06-27 15:39:53 +00:00
for _ , logger := range core . allLoggers {
2022-11-28 16:18:36 +00:00
loggerName := logger . Name ( )
levelRaw , currentOk := resp . Data [ loggerName ]
initialLevelRaw , initialOk := initialLoggers [ loggerName ]
if ! currentOk || ! initialOk {
t . Errorf ( "logger %q not found" , loggerName )
}
levelStr := levelRaw . ( string )
initialLevelStr := initialLevelRaw . ( string )
if levelStr != initialLevelStr {
t . Errorf ( "expected level of logger %q to match original config, expected: %s, actual: %s" , loggerName , initialLevelStr , levelStr )
2022-06-27 15:39:53 +00:00
}
}
} )
}
}
func TestSystemBackend_LoggersByName ( t * testing . T ) {
testCases := [ ] struct {
logger string
level string
2022-11-28 16:18:36 +00:00
expectedLevel string
2022-06-27 15:39:53 +00:00
expectWriteError bool
expectDeleteError bool
} {
{
"core" ,
"trace" ,
2022-11-28 16:18:36 +00:00
"trace" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"token" ,
"debug" ,
2022-11-28 16:18:36 +00:00
"debug" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"audit" ,
"notice" ,
2022-11-28 16:18:36 +00:00
"info" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"expiration" ,
"info" ,
2022-11-28 16:18:36 +00:00
"info" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"policy" ,
"warn" ,
2022-11-28 16:18:36 +00:00
"warn" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"activity" ,
"warning" ,
2022-11-28 16:18:36 +00:00
"warn" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"identity" ,
"err" ,
2022-11-28 16:18:36 +00:00
"error" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"rollback" ,
"error" ,
2022-11-28 16:18:36 +00:00
"error" ,
2022-06-27 15:39:53 +00:00
false ,
false ,
} ,
{
"system" ,
"" ,
2022-11-28 16:18:36 +00:00
"does-not-matter" ,
2022-06-27 15:39:53 +00:00
true ,
false ,
} ,
{
"quotas" ,
"invalid" ,
2022-11-28 16:18:36 +00:00
"does-not-matter" ,
2022-06-27 15:39:53 +00:00
true ,
false ,
} ,
{
"" ,
"info" ,
2022-11-28 16:18:36 +00:00
"does-not-matter" ,
2022-06-27 15:39:53 +00:00
true ,
true ,
} ,
{
"does_not_exist" ,
"error" ,
2022-11-28 16:18:36 +00:00
"does-not-matter" ,
2022-06-27 15:39:53 +00:00
true ,
true ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( fmt . Sprintf ( "loggers-by-name-%s" , tc . logger ) , func ( t * testing . T ) {
t . Parallel ( )
core , b , _ := testCoreSystemBackend ( t )
2022-11-28 16:18:36 +00:00
// Test core overrides logging level outside of config,
// an initial delete will ensure that we an initial read
// to get expected values is based off of config and not
// the test override that is hidden from this test
2022-06-27 15:39:53 +00:00
req := & logical . Request {
2022-11-28 16:18:36 +00:00
Path : "loggers" ,
Operation : logical . DeleteOperation ,
}
resp , err := b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
req = & logical . Request {
Path : "loggers" ,
Operation : logical . ReadOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
initialLoggers := resp . Data
req = & logical . Request {
2022-06-27 15:39:53 +00:00
Path : fmt . Sprintf ( "loggers/%s" , tc . logger ) ,
Operation : logical . UpdateOperation ,
Data : map [ string ] interface { } {
"level" : tc . level ,
} ,
}
2022-11-28 16:18:36 +00:00
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
2022-06-27 15:39:53 +00:00
respIsError := resp != nil && resp . IsError ( )
if err != nil || ( ! tc . expectWriteError && respIsError ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
if tc . expectWriteError && ! respIsError {
t . Fatalf ( "expected response error, resp: %#v" , resp )
}
if ! tc . expectWriteError {
2022-11-28 16:18:36 +00:00
req = & logical . Request {
Path : "loggers" ,
Operation : logical . ReadOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
2022-06-27 15:39:53 +00:00
for _ , logger := range core . allLoggers {
2022-11-28 16:18:36 +00:00
loggerName := logger . Name ( )
levelRaw , currentOk := resp . Data [ loggerName ]
initialLevelRaw , initialOk := initialLoggers [ loggerName ]
if ! currentOk || ! initialOk {
t . Errorf ( "logger %q not found" , loggerName )
}
levelStr := levelRaw . ( string )
initialLevelStr := initialLevelRaw . ( string )
if loggerName == tc . logger && levelStr != tc . expectedLevel {
t . Fatalf ( "expected logger %q to be %q, actual: %s" , loggerName , tc . expectedLevel , levelStr )
2022-06-27 15:39:53 +00:00
}
2022-11-28 16:18:36 +00:00
if loggerName != tc . logger && levelStr != initialLevelStr {
t . Errorf ( "expected level of logger %q to be unchanged, exepcted: %s, actual: %s" , loggerName , initialLevelStr , levelStr )
2022-06-27 15:39:53 +00:00
}
}
}
req = & logical . Request {
Path : fmt . Sprintf ( "loggers/%s" , tc . logger ) ,
Operation : logical . DeleteOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
respIsError = resp != nil && resp . IsError ( )
if err != nil || ( ! tc . expectDeleteError && respIsError ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
if tc . expectDeleteError && ! respIsError {
t . Fatalf ( "expected response error, resp: %#v" , resp )
}
if ! tc . expectDeleteError {
2022-11-28 16:18:36 +00:00
req = & logical . Request {
Path : fmt . Sprintf ( "loggers/%s" , tc . logger ) ,
Operation : logical . ReadOperation ,
}
resp , err = b . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "unexpected error, err: %v, resp: %#v" , err , resp )
}
currentLevel , ok := resp . Data [ tc . logger ] . ( string )
if ! ok {
t . Fatalf ( "expected resp to include %q, resp: %#v" , tc . logger , resp )
}
initialLevel , ok := initialLoggers [ tc . logger ] . ( string )
if ! ok {
t . Fatalf ( "expected initial loggers to include %q, resp: %#v" , tc . logger , initialLoggers )
}
if currentLevel != initialLevel {
t . Errorf ( "expected level of logger %q to match original config, expected: %s, actual: %s" , tc . logger , initialLevel , currentLevel )
2022-06-27 15:39:53 +00:00
}
}
} )
}
}
2022-08-25 20:31:42 +00:00
func TestSortVersionedPlugins ( t * testing . T ) {
versionedPlugin := func ( typ consts . PluginType , name string , version string , builtin bool ) pluginutil . VersionedPlugin {
return pluginutil . VersionedPlugin {
Type : typ . String ( ) ,
Name : name ,
Version : version ,
SHA256 : "" ,
Builtin : builtin ,
SemanticVersion : func ( ) * semver . Version {
if version != "" {
return semver . Must ( semver . NewVersion ( version ) )
}
return semver . Must ( semver . NewVersion ( "0.0.0" ) )
} ( ) ,
}
}
differingTypes := [ ] pluginutil . VersionedPlugin {
versionedPlugin ( consts . PluginTypeSecrets , "c" , "1.0.0" , false ) ,
versionedPlugin ( consts . PluginTypeDatabase , "c" , "1.0.0" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "c" , "1.0.0" , false ) ,
}
differingNames := [ ] pluginutil . VersionedPlugin {
versionedPlugin ( consts . PluginTypeCredential , "c" , "1.0.0" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "b" , "1.0.0" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "a" , "1.0.0" , false ) ,
}
differingVersions := [ ] pluginutil . VersionedPlugin {
versionedPlugin ( consts . PluginTypeCredential , "c" , "10.0.0" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "c" , "2.0.1" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "c" , "2.1.0" , false ) ,
}
versionedUnversionedAndBuiltin := [ ] pluginutil . VersionedPlugin {
versionedPlugin ( consts . PluginTypeCredential , "c" , "1.0.0" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "c" , "" , false ) ,
versionedPlugin ( consts . PluginTypeCredential , "c" , "1.0.0" , true ) ,
}
for name , tc := range map [ string ] [ ] pluginutil . VersionedPlugin {
"ascending types" : differingTypes ,
"ascending names" : differingNames ,
"ascending versions" : differingVersions ,
// Include differing versions twice so we can test out equality too.
"differing types, names and versions" : append ( differingTypes ,
append ( differingNames ,
append ( differingVersions , differingVersions ... ) ... ) ... ) ,
"mix of unversioned, versioned, and builtin" : versionedUnversionedAndBuiltin ,
} {
t . Run ( name , func ( t * testing . T ) {
sortVersionedPlugins ( tc )
for i := 1 ; i < len ( tc ) ; i ++ {
previous := tc [ i - 1 ]
current := tc [ i ]
if current . Type > previous . Type {
continue
}
if current . Name > previous . Name {
continue
}
if current . SemanticVersion . GreaterThan ( previous . SemanticVersion ) {
continue
}
if current . Type == previous . Type && current . Name == previous . Name && current . SemanticVersion . Equal ( previous . SemanticVersion ) {
continue
}
t . Fatalf ( "versioned plugins at index %d and %d were not properly sorted: %+v, %+v" , i - 1 , i , previous , current )
}
} )
}
}
2022-11-23 18:36:25 +00:00
func TestValidateVersion ( t * testing . T ) {
b := testSystemBackend ( t ) . ( * SystemBackend )
k8sAuthBuiltin := versions . GetBuiltinVersion ( consts . PluginTypeCredential , "kubernetes" )
for name , tc := range map [ string ] struct {
pluginName string
pluginVersion string
pluginType consts . PluginType
expectLogicalError string
expectedVersion string
} {
"default, nothing in nothing out" : { "kubernetes" , "" , consts . PluginTypeCredential , "" , "" } ,
"builtin specified, empty out" : { "kubernetes" , k8sAuthBuiltin , consts . PluginTypeCredential , "" , "" } ,
"not canonical is ok" : { "kubernetes" , "1.0.0" , consts . PluginTypeCredential , "" , "v1.0.0" } ,
"not a semantic version, error" : { "kubernetes" , "not-a-version" , consts . PluginTypeCredential , "not a valid semantic version" , "" } ,
"can't select non-builtin token" : { "token" , "v1.0.0" , consts . PluginTypeCredential , "cannot select non-builtin version" , "" } ,
"can't select non-builtin identity" : { "identity" , "v1.0.0" , consts . PluginTypeSecrets , "cannot select non-builtin version" , "" } ,
} {
t . Run ( name , func ( t * testing . T ) {
version , resp , err := b . validateVersion ( context . Background ( ) , tc . pluginVersion , tc . pluginName , tc . pluginType )
if err != nil {
t . Fatal ( err )
}
if tc . expectLogicalError != "" {
if resp == nil || ! resp . IsError ( ) || resp . Error ( ) == nil {
t . Errorf ( "expected logical error but got none, resp: %#v" , resp )
}
if ! strings . Contains ( resp . Error ( ) . Error ( ) , tc . expectLogicalError ) {
t . Errorf ( "expected logical error to contain %q, but got: %s" , tc . expectLogicalError , resp . Error ( ) )
}
} else if version != tc . expectedVersion {
t . Errorf ( "expected version %q but got %q" , tc . expectedVersion , version )
}
} )
}
}
func TestValidateVersion_HelpfulErrorWhenBuiltinOverridden ( t * testing . T ) {
core , _ , _ := TestCoreUnsealed ( t )
tempDir , err := filepath . EvalSymlinks ( t . TempDir ( ) )
if err != nil {
t . Fatal ( err )
}
core . pluginCatalog . directory = tempDir
b := core . systemBackend
// Shadow a builtin and test getting a helpful error back.
file , err := ioutil . TempFile ( tempDir , "temp" )
if err != nil {
t . Fatal ( err )
}
defer file . Close ( )
command := filepath . Base ( file . Name ( ) )
err = core . pluginCatalog . Set ( context . Background ( ) , "kubernetes" , consts . PluginTypeCredential , "" , command , nil , nil , nil )
if err != nil {
t . Fatal ( err )
}
// When we validate the version now, we should get a special error message
// about why the builtin isn't there.
k8sAuthBuiltin := versions . GetBuiltinVersion ( consts . PluginTypeCredential , "kubernetes" )
_ , resp , err := b . validateVersion ( context . Background ( ) , k8sAuthBuiltin , "kubernetes" , consts . PluginTypeCredential )
if err != nil {
t . Fatal ( err )
}
if resp == nil || ! resp . IsError ( ) || resp . Error ( ) == nil {
t . Errorf ( "expected logical error but got none, resp: %#v" , resp )
}
if ! strings . Contains ( resp . Error ( ) . Error ( ) , "overridden by an unversioned plugin of the same name" ) {
t . Errorf ( "expected logical error to contain overridden message, but got: %s" , resp . Error ( ) )
}
}
func TestCanUnseal_WithNonExistentBuiltinPluginVersion_InMountStorage ( t * testing . T ) {
core , keys , _ := TestCoreUnsealed ( t )
ctx := namespace . RootContext ( nil )
testCases := [ ] struct {
pluginName string
pluginType consts . PluginType
mountTable string
} {
{ "consul" , consts . PluginTypeSecrets , "mounts" } ,
{ "approle" , consts . PluginTypeCredential , "auth" } ,
}
readMountConfig := func ( pluginName , mountTable string ) map [ string ] interface { } {
t . Helper ( )
req := logical . TestRequest ( t , logical . ReadOperation , mountTable + "/" + pluginName )
resp , err := core . systemBackend . HandleRequest ( ctx , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
return resp . Data
}
for _ , tc := range testCases {
req := logical . TestRequest ( t , logical . UpdateOperation , tc . mountTable + "/" + tc . pluginName )
req . Data [ "type" ] = tc . pluginName
req . Data [ "config" ] = map [ string ] interface { } {
"default_lease_ttl" : "35m" ,
"max_lease_ttl" : "45m" ,
"plugin_version" : versions . GetBuiltinVersion ( tc . pluginType , tc . pluginName ) ,
}
resp , err := core . systemBackend . HandleRequest ( ctx , req )
if err != nil {
t . Fatalf ( "err: %v, resp: %#v" , err , resp )
}
if resp != nil {
t . Fatalf ( "bad: %v" , resp )
}
config := readMountConfig ( tc . pluginName , tc . mountTable )
pluginVersion , ok := config [ "plugin_version" ]
if ! ok || pluginVersion != "" {
t . Fatalf ( "expected empty plugin version in config: %#v" , config )
}
// Directly store plugin version in mount entry, so we can then simulate
// an upgrade from 1.12.1 to 1.12.2 by sealing and unsealing.
const nonExistentBuiltinVersion = "v1.0.0+builtin"
var mountEntry * MountEntry
if tc . mountTable == "mounts" {
mountEntry , err = core . mounts . find ( ctx , tc . pluginName + "/" )
} else {
mountEntry , err = core . auth . find ( ctx , tc . pluginName + "/" )
}
if err != nil {
t . Fatal ( err )
}
if mountEntry == nil {
t . Fatal ( )
}
mountEntry . Version = nonExistentBuiltinVersion
err = core . persistMounts ( ctx , core . mounts , & mountEntry . Local )
if err != nil {
t . Fatal ( err )
}
config = readMountConfig ( tc . pluginName , tc . mountTable )
pluginVersion , ok = config [ "plugin_version" ]
if ! ok || pluginVersion != nonExistentBuiltinVersion {
t . Fatalf ( "expected plugin version %s but was %s, config: %#v" , nonExistentBuiltinVersion , pluginVersion , config )
}
}
err := TestCoreSeal ( core )
if err != nil {
t . Fatal ( err )
}
for _ , key := range keys {
if _ , err := TestCoreUnseal ( core , TestKeyCopy ( key ) ) ; err != nil {
t . Fatalf ( "unseal err: %s" , err )
}
}
for _ , tc := range testCases {
// Storage should have been upgraded during the unseal, so plugin version
// should be empty again.
config := readMountConfig ( tc . pluginName , tc . mountTable )
pluginVersion , ok := config [ "plugin_version" ]
if ! ok || pluginVersion != "" {
t . Errorf ( "expected empty plugin version in config: %#v" , config )
}
}
}
2023-01-16 16:07:18 +00:00
func TestSystemBackend_ReadExperiments ( t * testing . T ) {
c , _ , _ := TestCoreUnsealed ( t )
for name , tc := range map [ string ] [ ] string {
"no experiments enabled" : { } ,
2023-01-23 19:26:49 +00:00
"one experiment enabled" : { experiments . VaultExperimentEventsAlpha1 } ,
2023-01-16 16:07:18 +00:00
} {
t . Run ( name , func ( t * testing . T ) {
// Set the enabled experiments.
c . experiments = tc
req := logical . TestRequest ( t , logical . ReadOperation , "experiments" )
resp , err := c . systemBackend . HandleRequest ( namespace . RootContext ( nil ) , req )
if err != nil {
t . Fatalf ( "err: %v" , err )
}
if resp == nil {
t . Fatal ( "Expected a response" )
}
if ! reflect . DeepEqual ( experiments . ValidExperiments ( ) , resp . Data [ "available" ] ) {
t . Fatalf ( "Expected %v but got %v" , experiments . ValidExperiments ( ) , resp . Data [ "available" ] )
}
if ! reflect . DeepEqual ( tc , resp . Data [ "enabled" ] ) {
t . Fatal ( "No experiments should be enabled by default" )
}
} )
}
}