open-vault/vault/external_tests/api/sudo_paths_test.go
VAL a06c8a139f
Add enterprise sudo paths to api.SudoPaths map (#15219)
* Add enterprise sudo paths to api.SudoPaths map

* add comment to denote ent-only sudo paths

* go fmt

Co-authored-by: Chris Capurso <1036769+ccapurso@users.noreply.github.com>
2022-04-29 10:09:25 -04:00

126 lines
3.5 KiB
Go

package api
import (
"fmt"
"testing"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/audit"
auditFile "github.com/hashicorp/vault/builtin/audit/file"
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
"github.com/hashicorp/vault/builtin/logical/database"
"github.com/hashicorp/vault/builtin/logical/pki"
"github.com/hashicorp/vault/builtin/logical/transit"
"github.com/hashicorp/vault/helper/builtinplugins"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)
const sudoKey = "x-vault-sudo"
// Tests that the static list of sudo paths in the api package matches what's in the current OpenAPI spec.
func TestSudoPaths(t *testing.T) {
t.Parallel()
coreConfig := &vault.CoreConfig{
DisableMlock: true,
DisableCache: true,
EnableRaw: true,
Logger: log.NewNullLogger(),
CredentialBackends: map[string]logical.Factory{
"userpass": credUserpass.Factory,
},
AuditBackends: map[string]audit.Factory{
"file": auditFile.Factory,
},
LogicalBackends: map[string]logical.Factory{
"database": database.Factory,
"generic-leased": vault.LeasedPassthroughBackendFactory,
"pki": pki.Factory,
"transit": transit.Factory,
},
BuiltinRegistry: builtinplugins.Registry,
}
client, _, closer := testVaultServerCoreConfig(t, coreConfig)
defer closer()
for credBackendName := range coreConfig.CredentialBackends {
err := client.Sys().EnableAuthWithOptions(credBackendName, &api.EnableAuthOptions{
Type: credBackendName,
})
if err != nil {
t.Fatalf("error enabling auth backend for test: %v", err)
}
}
for logicalBackendName := range coreConfig.LogicalBackends {
err := client.Sys().Mount(logicalBackendName, &api.MountInput{
Type: logicalBackendName,
})
if err != nil {
t.Fatalf("error enabling logical backend for test: %v", err)
}
}
sudoPathsFromSpec, err := getSudoPathsFromSpec(client)
if err != nil {
t.Fatalf("error getting list of paths that require sudo from OpenAPI endpoint: %v", err)
}
sudoPathsInCode := api.SudoPaths()
// check for missing paths
for path := range sudoPathsFromSpec {
if _, ok := sudoPathsInCode[path]; !ok {
t.Fatalf(
"A path in the OpenAPI spec is missing from the static list of "+
"sudo paths in the api module (%s). Please reconcile the two "+
"accordingly.", path)
}
}
}
func getSudoPathsFromSpec(client *api.Client) (map[string]struct{}, error) {
r := client.NewRequest("GET", "/v1/sys/internal/specs/openapi")
resp, err := client.RawRequest(r)
if err != nil {
return nil, fmt.Errorf("unable to retrieve sudo endpoints: %v", err)
}
if resp != nil {
defer resp.Body.Close()
}
oasInfo := make(map[string]interface{})
if err := jsonutil.DecodeJSONFromReader(resp.Body, &oasInfo); err != nil {
return nil, fmt.Errorf("unable to decode JSON from OpenAPI response: %v", err)
}
paths, ok := oasInfo["paths"]
if !ok {
return nil, fmt.Errorf("OpenAPI response did not include paths")
}
pathsMap, ok := paths.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("OpenAPI response did not return valid paths")
}
sudoPaths := make(map[string]struct{})
for pathName, pathInfo := range pathsMap {
pathInfoMap, ok := pathInfo.(map[string]interface{})
if !ok {
continue
}
if sudo, ok := pathInfoMap[sudoKey]; ok {
if sudo == true {
sudoPaths[pathName] = struct{}{}
}
}
}
return sudoPaths, nil
}