vault/http/options_test.go
Violet Hynes b896dc1610
VAULT-24437 Address OpenAPI endpoint ignoring redact_version listener parameter (#26607)
* VAULT-24437 Address OpenAPI endpoint ignoring redact_version listener parameter

* VAULT-24437 changelog

* VAULT-24437 changelog mistake
2024-04-24 12:16:55 -04:00

274 lines
6.9 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package http
import (
"net/http"
"strings"
"testing"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/vault"
"github.com/hashicorp/vault/version"
"github.com/stretchr/testify/require"
)
// TestOptions_Default ensures that the default values are as expected.
func TestOptions_Default(t *testing.T) {
opts := getDefaultOptions()
require.NotNil(t, opts)
require.Equal(t, "", opts.withRedactionValue)
}
// TestOptions_WithRedactionValue ensures that we set the correct value to use for
// redaction when required.
func TestOptions_WithRedactionValue(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Value string
ExpectedValue string
IsErrorExpected bool
}{
"empty": {
Value: "",
ExpectedValue: "",
IsErrorExpected: false,
},
"whitespace": {
Value: " ",
ExpectedValue: " ",
IsErrorExpected: false,
},
"value": {
Value: "*****",
ExpectedValue: "*****",
IsErrorExpected: false,
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
opts := &listenerConfigOptions{}
applyOption := WithRedactionValue(tc.Value)
err := applyOption(opts)
switch {
case tc.IsErrorExpected:
require.Error(t, err)
default:
require.NoError(t, err)
require.Equal(t, tc.ExpectedValue, opts.withRedactionValue)
}
})
}
}
// TestOptions_WithRedactAddresses ensures that the option works as intended.
func TestOptions_WithRedactAddresses(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Value bool
ExpectedValue bool
}{
"true": {
Value: true,
ExpectedValue: true,
},
"false": {
Value: false,
ExpectedValue: false,
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
opts := &listenerConfigOptions{}
applyOption := WithRedactAddresses(tc.Value)
err := applyOption(opts)
require.NoError(t, err)
require.Equal(t, tc.ExpectedValue, opts.withRedactAddresses)
})
}
}
// TestOptions_WithRedactClusterName ensures that the option works as intended.
func TestOptions_WithRedactClusterName(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Value bool
ExpectedValue bool
}{
"true": {
Value: true,
ExpectedValue: true,
},
"false": {
Value: false,
ExpectedValue: false,
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
opts := &listenerConfigOptions{}
applyOption := WithRedactClusterName(tc.Value)
err := applyOption(opts)
require.NoError(t, err)
require.Equal(t, tc.ExpectedValue, opts.withRedactClusterName)
})
}
}
// TestOptions_WithRedactVersion ensures that the option works as intended.
func TestOptions_WithRedactVersion(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Value bool
ExpectedValue bool
}{
"true": {
Value: true,
ExpectedValue: true,
},
"false": {
Value: false,
ExpectedValue: false,
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
opts := &listenerConfigOptions{}
applyOption := WithRedactVersion(tc.Value)
err := applyOption(opts)
require.NoError(t, err)
require.Equal(t, tc.ExpectedValue, opts.withRedactVersion)
})
}
}
// TestRedactVersionListener tests that the version will be redacted
// from e.g. sys/health and the OpenAPI response if `redact_version`
// is set on the listener.
func TestRedactVersionListener(t *testing.T) {
conf := &vault.CoreConfig{
EnableUI: false,
EnableRaw: true,
BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(),
}
core, _, token := vault.TestCoreUnsealedWithConfig(t, conf)
// Setup listener without redaction
ln, addr := TestListener(t)
props := &vault.HandlerProperties{
Core: core,
ListenerConfig: &configutil.Listener{
RedactVersion: false,
},
}
TestServerWithListenerAndProperties(t, ln, addr, core, props)
defer ln.Close()
TestServerAuth(t, addr, token)
testRedactVersionEndpoints(t, addr, token, version.Version)
// Setup listener with redaction
ln, addr = TestListener(t)
props.ListenerConfig.RedactVersion = true
TestServerWithListenerAndProperties(t, ln, addr, core, props)
defer ln.Close()
TestServerAuth(t, addr, token)
testRedactVersionEndpoints(t, addr, token, "")
}
// testRedactVersionEndpoints tests the endpoints containing versions
// contain the expected version
func testRedactVersionEndpoints(t *testing.T, addr, token, expectedVersion string) {
client := cleanhttp.DefaultClient()
req, err := http.NewRequest("GET", addr+"/v1/auth/token?help=1", nil)
require.NoError(t, err)
req.Header.Set(consts.AuthHeaderName, token)
resp, err := client.Do(req)
require.NoError(t, err)
testResponseStatus(t, resp, 200)
var actual map[string]interface{}
testResponseBody(t, resp, &actual)
require.NotNil(t, actual["openapi"])
openAPI, ok := actual["openapi"].(map[string]interface{})
require.True(t, ok)
require.NotNil(t, openAPI["info"])
info, ok := openAPI["info"].(map[string]interface{})
require.True(t, ok)
require.NotNil(t, info["version"])
version, ok := info["version"].(string)
require.True(t, ok)
require.Equal(t, expectedVersion, version)
req, err = http.NewRequest("GET", addr+"/v1/sys/internal/specs/openapi", nil)
require.NoError(t, err)
req.Header.Set(consts.AuthHeaderName, "")
resp, err = client.Do(req)
require.NoError(t, err)
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)
require.NotNil(t, actual["info"])
info, ok = openAPI["info"].(map[string]interface{})
require.True(t, ok)
require.NotNil(t, info["version"])
version, ok = info["version"].(string)
require.True(t, ok)
require.Equal(t, expectedVersion, version)
req, err = http.NewRequest("GET", addr+"/v1/sys/health", nil)
require.NoError(t, err)
req.Header.Set(consts.AuthHeaderName, "")
resp, err = client.Do(req)
require.NoError(t, err)
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)
require.NotNil(t, actual["version"])
version, ok = actual["version"].(string)
require.True(t, ok)
// sys/health is special and uses a different format to the OpenAPI
// version.GetVersion().VersionNumber() instead of version.Version
// We use substring to make sure the check works anyway.
// In practice, version.GetVersion().VersionNumber() will give something like 1.17.0-beta1
// and version.Version gives something like 1.17.0
require.Truef(t, strings.HasPrefix(version, expectedVersion), "version was not as expected, version=%s, expectedVersion=%s",
version, expectedVersion)
}