mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	 b896dc1610
			
		
	
	b896dc1610
	
	
	
		
			
			* VAULT-24437 Address OpenAPI endpoint ignoring redact_version listener parameter * VAULT-24437 changelog * VAULT-24437 changelog mistake
		
			
				
	
	
		
			274 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			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)
 | |
| }
 |