2023-03-15 19:00:52 +03:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2024-01-02 21:36:20 +03:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-15 19:00:52 +03:00
|
|
|
|
2021-10-13 18:06:33 +03:00
|
|
|
package vault
|
|
|
|
|
|
|
|
import (
|
2021-11-23 22:30:25 +03:00
|
|
|
"fmt"
|
2021-10-13 18:06:33 +03:00
|
|
|
"net/http"
|
|
|
|
"net/textproto"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
|
|
"github.com/hashicorp/vault/internalshared/configutil"
|
2021-11-23 22:30:25 +03:00
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2021-10-13 18:06:33 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type ListenerCustomHeaders struct {
|
|
|
|
Address string
|
2021-11-23 22:30:25 +03:00
|
|
|
StatusCodeHeaderMap map[string][]*logical.CustomHeader
|
2021-10-13 18:06:33 +03:00
|
|
|
// ConfiguredHeadersStatusCodeMap field is introduced so that we would not need to loop through
|
|
|
|
// StatusCodeHeaderMap to see if a header exists, the key for this map is the headers names
|
|
|
|
configuredHeadersStatusCodeMap map[string][]string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewListenerCustomHeader(ln []*configutil.Listener, logger log.Logger, uiHeaders http.Header) []*ListenerCustomHeaders {
|
|
|
|
var listenerCustomHeadersList []*ListenerCustomHeaders
|
|
|
|
|
|
|
|
for _, l := range ln {
|
|
|
|
listenerCustomHeaderStruct := &ListenerCustomHeaders{
|
|
|
|
Address: l.Address,
|
|
|
|
}
|
2021-11-23 22:30:25 +03:00
|
|
|
listenerCustomHeaderStruct.StatusCodeHeaderMap = make(map[string][]*logical.CustomHeader)
|
2021-10-13 18:06:33 +03:00
|
|
|
listenerCustomHeaderStruct.configuredHeadersStatusCodeMap = make(map[string][]string)
|
|
|
|
for statusCode, headerValMap := range l.CustomResponseHeaders {
|
2021-11-23 22:30:25 +03:00
|
|
|
var customHeaderList []*logical.CustomHeader
|
2021-10-13 18:06:33 +03:00
|
|
|
for headerName, headerVal := range headerValMap {
|
|
|
|
// Sanitizing custom headers
|
|
|
|
// X-Vault- prefix is reserved for Vault internal processes
|
|
|
|
if strings.HasPrefix(headerName, "X-Vault-") {
|
|
|
|
logger.Warn("custom headers starting with X-Vault are not valid", "header", headerName)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checking for UI headers, if any common header exists, we just log an error
|
|
|
|
if uiHeaders != nil {
|
|
|
|
exist := uiHeaders.Get(headerName)
|
|
|
|
if exist != "" {
|
2022-01-27 21:06:34 +03:00
|
|
|
logger.Warn(fmt.Sprintf("found a duplicate header in UI: header=%s. Headers defined in the server configuration take precedence.", headerName))
|
2021-10-13 18:06:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checking if the header value is not an empty string
|
|
|
|
if headerVal == "" {
|
|
|
|
logger.Warn("header value is an empty string", "header", headerName, "value", headerVal)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-11-23 22:30:25 +03:00
|
|
|
ch := &logical.CustomHeader{
|
2021-10-13 18:06:33 +03:00
|
|
|
Name: headerName,
|
|
|
|
Value: headerVal,
|
|
|
|
}
|
|
|
|
|
|
|
|
customHeaderList = append(customHeaderList, ch)
|
|
|
|
|
|
|
|
// setting up the reverse map of header to status code for easy lookups
|
|
|
|
listenerCustomHeaderStruct.configuredHeadersStatusCodeMap[headerName] = append(listenerCustomHeaderStruct.configuredHeadersStatusCodeMap[headerName], statusCode)
|
|
|
|
}
|
|
|
|
listenerCustomHeaderStruct.StatusCodeHeaderMap[statusCode] = customHeaderList
|
|
|
|
}
|
|
|
|
listenerCustomHeadersList = append(listenerCustomHeadersList, listenerCustomHeaderStruct)
|
|
|
|
}
|
|
|
|
|
|
|
|
return listenerCustomHeadersList
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *ListenerCustomHeaders) ExistCustomResponseHeader(header string) bool {
|
|
|
|
if header == "" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if l.StatusCodeHeaderMap == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
headerName := textproto.CanonicalMIMEHeaderKey(header)
|
|
|
|
|
|
|
|
headerMap := l.configuredHeadersStatusCodeMap
|
|
|
|
_, ok := headerMap[headerName]
|
|
|
|
return ok
|
|
|
|
}
|