open-vault/vault/custom_response_headers_tes...

210 lines
6.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package vault
import (
"context"
"fmt"
"net/http/httptest"
"strings"
"testing"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/helper/logging"
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/sdk/physical/inmem"
)
var defaultCustomHeaders = map[string]string{
"Strict-Transport-Security": "max-age=1; domains",
"Content-Security-Policy": "default-src 'others'",
"X-Vault-Ignored": "ignored",
"X-Custom-Header": "Custom header value default",
"X-Frame-Options": "Deny",
"X-Content-Type-Options": "nosniff",
"Content-Type": "text/plain; charset=utf-8",
"X-XSS-Protection": "1; mode=block",
}
var customHeaders307 = map[string]string{
"X-Custom-Header": "Custom header value 307",
}
var customHeader3xx = map[string]string{
"X-Vault-Ignored-3xx": "Ignored 3xx",
"X-Custom-Header": "Custom header value 3xx",
}
var customHeaders200 = map[string]string{
"Someheader-200": "200",
"X-Custom-Header": "Custom header value 200",
}
var customHeader2xx = map[string]string{
"X-Custom-Header": "Custom header value 2xx",
}
var customHeader400 = map[string]string{
"Someheader-400": "400",
}
func TestConfigCustomHeaders(t *testing.T) {
logger := logging.NewVaultLogger(log.Trace)
phys, err := inmem.NewTransactionalInmem(nil, logger)
if err != nil {
t.Fatal(err)
}
logl := &logical.InmemStorage{}
uiConfig := NewUIConfig(true, phys, logl)
rawListenerConfig := []*configutil.Listener{
{
Type: "tcp",
Address: "127.0.0.1:443",
CustomResponseHeaders: map[string]map[string]string{
"default": defaultCustomHeaders,
"307": customHeaders307,
"3xx": customHeader3xx,
"200": customHeaders200,
"2xx": customHeader2xx,
"400": customHeader400,
},
},
}
uiHeaders, err := uiConfig.Headers(context.Background())
if err != nil {
t.Fatal(err)
}
listenerCustomHeaders := NewListenerCustomHeader(rawListenerConfig, logger, uiHeaders)
if listenerCustomHeaders == nil || len(listenerCustomHeaders) != 1 {
t.Fatalf("failed to get custom header configuration")
}
lch := listenerCustomHeaders[0]
if lch.ExistCustomResponseHeader("X-Vault-Ignored-307") {
t.Fatalf("header name with X-Vault prefix is not valid")
}
if lch.ExistCustomResponseHeader("X-Vault-Ignored-3xx") {
t.Fatalf("header name with X-Vault prefix is not valid")
}
if !lch.ExistCustomResponseHeader("X-Custom-Header") {
t.Fatalf("header name with X-Vault prefix is not valid")
}
}
func TestCustomResponseHeadersConfigInteractUiConfig(t *testing.T) {
b := testSystemBackend(t)
paths := b.(*SystemBackend).configPaths()
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "")
b.(*SystemBackend).Core.systemBarrierView = view
logger := logging.NewVaultLogger(log.Trace)
rawListenerConfig := []*configutil.Listener{
{
Type: "tcp",
Address: "127.0.0.1:443",
CustomResponseHeaders: map[string]map[string]string{
"default": defaultCustomHeaders,
"307": customHeaders307,
"3xx": customHeader3xx,
"200": customHeaders200,
"2xx": customHeader2xx,
"400": customHeader400,
},
},
}
uiHeaders, err := b.(*SystemBackend).Core.uiConfig.Headers(context.Background())
if err != nil {
t.Fatalf("failed to get headers from ui config")
}
customListenerHeader := NewListenerCustomHeader(rawListenerConfig, logger, uiHeaders)
if customListenerHeader == nil {
t.Fatalf("custom header config should be configured")
}
b.(*SystemBackend).Core.customListenerHeader.Store(customListenerHeader)
clh := b.(*SystemBackend).Core.customListenerHeader
if clh == nil {
t.Fatalf("custom header config should be configured in core")
}
w := httptest.NewRecorder()
hw := logical.NewHTTPResponseWriter(w)
// setting a header that already exist in custom headers
req := logical.TestRequest(t, logical.UpdateOperation, "config/ui/headers/X-Custom-Header")
req.Data["values"] = []string{"UI Custom Header"}
req.ResponseWriter = hw
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
if err == nil {
t.Fatal("request did not fail on setting a header that is present in custom response headers")
}
schema.ValidateResponse(
t,
schema.FindResponseSchema(t, paths, 3, req.Operation),
resp,
true,
)
if !strings.Contains(resp.Data["error"].(string), fmt.Sprintf("This header already exists in the server configuration and cannot be set in the UI.")) {
t.Fatalf("failed to get the expected error")
}
// setting a header that already exist in custom headers
req = logical.TestRequest(t, logical.UpdateOperation, "config/ui/headers/Someheader-400")
req.Data["values"] = []string{"400"}
req.ResponseWriter = hw
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err == nil {
t.Fatal("request did not fail on setting a header that is present in custom response headers")
}
schema.ValidateResponse(
t,
schema.FindResponseSchema(t, paths, 3, req.Operation),
resp,
true,
)
h, err := b.(*SystemBackend).Core.uiConfig.Headers(context.Background())
if err != nil {
t.Fatal(err)
}
if h.Get("Someheader-400") == "400" {
t.Fatalf("should not be able to set a header that is in custom response headers")
}
// setting an ui specific header
req = logical.TestRequest(t, logical.UpdateOperation, "config/ui/headers/X-CustomUiHeader")
req.Data["values"] = []string{"Ui header value"}
req.ResponseWriter = hw
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatal("request failed on setting a header that is not present in custom response headers.", "error:", err)
}
schema.ValidateResponse(
t,
schema.FindResponseSchema(t, paths, 3, req.Operation),
resp,
true,
)
h, err = b.(*SystemBackend).Core.uiConfig.Headers(context.Background())
if err != nil {
t.Fatal(err)
}
if h.Get("X-CustomUiHeader") != "Ui header value" {
t.Fatalf("failed to set a header that is not in custom response headers")
}
}