mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-31 18:48:08 +00:00
Re-process .well-known redirects with a recursive handler call rather than a 302 redirect (#24890)
* Re-process .well-known redirects with a recursive handler call rather than a 302 redirect * Track when the RequestURI mismatches path (in a redirect) and add it to the audit log * call cancelFunc
This commit is contained in:
@@ -255,6 +255,10 @@ func (f *EntryFormatter) FormatRequest(ctx context.Context, in *logical.LogInput
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.HTTPRequest != nil && req.HTTPRequest.RequestURI != req.Path {
|
||||||
|
reqEntry.Request.RequestURI = req.HTTPRequest.RequestURI
|
||||||
|
}
|
||||||
|
|
||||||
if !auth.IssueTime.IsZero() {
|
if !auth.IssueTime.IsZero() {
|
||||||
reqEntry.Auth.TokenIssueTime = auth.IssueTime.Format(time.RFC3339)
|
reqEntry.Auth.TokenIssueTime = auth.IssueTime.Format(time.RFC3339)
|
||||||
}
|
}
|
||||||
@@ -472,6 +476,10 @@ func (f *EntryFormatter) FormatResponse(ctx context.Context, in *logical.LogInpu
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.HTTPRequest != nil && req.HTTPRequest.RequestURI != req.Path {
|
||||||
|
respEntry.Request.RequestURI = req.HTTPRequest.RequestURI
|
||||||
|
}
|
||||||
|
|
||||||
if auth.PolicyResults != nil {
|
if auth.PolicyResults != nil {
|
||||||
respEntry.Auth.PolicyResults = &PolicyResults{
|
respEntry.Auth.PolicyResults = &PolicyResults{
|
||||||
Allowed: auth.PolicyResults.Allowed,
|
Allowed: auth.PolicyResults.Allowed,
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ type Request struct {
|
|||||||
WrapTTL int `json:"wrap_ttl,omitempty"`
|
WrapTTL int `json:"wrap_ttl,omitempty"`
|
||||||
Headers map[string][]string `json:"headers,omitempty"`
|
Headers map[string][]string `json:"headers,omitempty"`
|
||||||
ClientCertificateSerialNumber string `json:"client_certificate_serial_number,omitempty"`
|
ClientCertificateSerialNumber string `json:"client_certificate_serial_number,omitempty"`
|
||||||
|
RequestURI string `json:"request_uri,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
|||||||
@@ -347,7 +347,8 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
|
|||||||
// return an HTTP error here. This information is best effort.
|
// return an HTTP error here. This information is best effort.
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
var hf func(w http.ResponseWriter, r *http.Request)
|
||||||
|
hf = func(w http.ResponseWriter, r *http.Request) {
|
||||||
// This block needs to be here so that upon sending SIGHUP, custom response
|
// This block needs to be here so that upon sending SIGHUP, custom response
|
||||||
// headers are also reloaded into the handlers.
|
// headers are also reloaded into the handlers.
|
||||||
var customHeaders map[string][]*logical.CustomHeader
|
var customHeaders map[string][]*logical.CustomHeader
|
||||||
@@ -422,16 +423,9 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
|
|||||||
core.Logger().Warn("error resolving potential API redirect", "error", err)
|
core.Logger().Warn("error resolving potential API redirect", "error", err)
|
||||||
} else {
|
} else {
|
||||||
if redir != "" {
|
if redir != "" {
|
||||||
dest := url.URL{
|
newReq := r.Clone(ctx)
|
||||||
Path: redir,
|
newReq.URL.Path = redir
|
||||||
RawQuery: r.URL.RawQuery,
|
hf(w, newReq)
|
||||||
}
|
|
||||||
w.Header().Set("Location", dest.String())
|
|
||||||
if r.Method == http.MethodGet || r.Proto == "HTTP/1.0" {
|
|
||||||
w.WriteHeader(http.StatusFound)
|
|
||||||
} else {
|
|
||||||
w.WriteHeader(http.StatusTemporaryRedirect)
|
|
||||||
}
|
|
||||||
cancelFunc()
|
cancelFunc()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -487,7 +481,8 @@ func wrapGenericHandler(core *vault.Core, h http.Handler, props *vault.HandlerPr
|
|||||||
h.ServeHTTP(nw, r)
|
h.ServeHTTP(nw, r)
|
||||||
|
|
||||||
cancelFunc()
|
cancelFunc()
|
||||||
})
|
}
|
||||||
|
return http.HandlerFunc(hf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapForwardedForHandler(h http.Handler, l *configutil.Listener) http.Handler {
|
func WrapForwardedForHandler(h http.Handler, l *configutil.Listener) http.Handler {
|
||||||
|
|||||||
@@ -110,10 +110,8 @@ func buildLogicalRequestNoAuth(perfStandby bool, ra *vault.RouterAccess, w http.
|
|||||||
// add the HTTP request to the logical request object for later consumption.
|
// add the HTTP request to the logical request object for later consumption.
|
||||||
contentType := r.Header.Get("Content-Type")
|
contentType := r.Header.Get("Content-Type")
|
||||||
|
|
||||||
if ra != nil && ra.IsBinaryPath(r.Context(), path) {
|
if (ra != nil && ra.IsBinaryPath(r.Context(), path)) ||
|
||||||
passHTTPReq = true
|
path == "sys/storage/raft/snapshot" || path == "sys/storage/raft/snapshot-force" {
|
||||||
origBody = r.Body
|
|
||||||
} else if path == "sys/storage/raft/snapshot" || path == "sys/storage/raft/snapshot-force" {
|
|
||||||
passHTTPReq = true
|
passHTTPReq = true
|
||||||
origBody = r.Body
|
origBody = r.Body
|
||||||
} else {
|
} else {
|
||||||
@@ -194,6 +192,11 @@ func buildLogicalRequestNoAuth(perfStandby bool, ra *vault.RouterAccess, w http.
|
|||||||
return nil, nil, http.StatusMethodNotAllowed, nil
|
return nil, nil, http.StatusMethodNotAllowed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RFC 5785 Redirect, keep the request for auditing purposes
|
||||||
|
if r.URL.Path != r.RequestURI {
|
||||||
|
passHTTPReq = true
|
||||||
|
}
|
||||||
|
|
||||||
requestId, err := uuid.GenerateUUID()
|
requestId, err := uuid.GenerateUUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, http.StatusInternalServerError, fmt.Errorf("failed to generate identifier for the request: %w", err)
|
return nil, nil, http.StatusInternalServerError, fmt.Errorf("failed to generate identifier for the request: %w", err)
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ package router
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/audit"
|
||||||
|
"github.com/hashicorp/vault/helper/testhelpers/corehelpers"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/helper/testhelpers"
|
"github.com/hashicorp/vault/helper/testhelpers"
|
||||||
vaulthttp "github.com/hashicorp/vault/http"
|
vaulthttp "github.com/hashicorp/vault/http"
|
||||||
|
|
||||||
@@ -90,7 +94,11 @@ func TestRouter_UnmountRollbackIsntFatal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWellKnownRedirect_HA(t *testing.T) {
|
func TestWellKnownRedirect_HA(t *testing.T) {
|
||||||
|
var records *[][]byte
|
||||||
cluster := vault.NewTestCluster(t, &vault.CoreConfig{
|
cluster := vault.NewTestCluster(t, &vault.CoreConfig{
|
||||||
|
AuditBackends: map[string]audit.Factory{
|
||||||
|
"noop": corehelpers.NoopAuditFactory(&records),
|
||||||
|
},
|
||||||
DisablePerformanceStandby: true,
|
DisablePerformanceStandby: true,
|
||||||
LogicalBackends: map[string]logical.Factory{
|
LogicalBackends: map[string]logical.Factory{
|
||||||
"noop": func(_ context.Context, _ *logical.BackendConfig) (logical.Backend, error) {
|
"noop": func(_ context.Context, _ *logical.BackendConfig) (logical.Backend, error) {
|
||||||
@@ -114,6 +122,12 @@ func TestWellKnownRedirect_HA(t *testing.T) {
|
|||||||
standbys := testhelpers.DeriveStandbyCores(t, cluster)
|
standbys := testhelpers.DeriveStandbyCores(t, cluster)
|
||||||
standby := standbys[0].Client
|
standby := standbys[0].Client
|
||||||
|
|
||||||
|
if err := active.Client.Sys().EnableAuditWithOptions("noop", &api.EnableAuditOptions{
|
||||||
|
Type: "noop",
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("failed to enable audit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := active.Client.Sys().Mount("noop", &api.MountInput{
|
if err := active.Client.Sys().Mount("noop", &api.MountInput{
|
||||||
Type: "noop",
|
Type: "noop",
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -143,4 +157,15 @@ func TestWellKnownRedirect_HA(t *testing.T) {
|
|||||||
} else if resp2.StatusCode != http.StatusOK {
|
} else if resp2.StatusCode != http.StatusOK {
|
||||||
t.Fatal("did not get expected response from noop backend after redirect")
|
t.Fatal("did not get expected response from noop backend after redirect")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(*records) < 2 {
|
||||||
|
t.Fatal("audit entries not populated")
|
||||||
|
} else {
|
||||||
|
rs := *records
|
||||||
|
// Make sure RequestURI is present in the redirect audit entries
|
||||||
|
if !strings.Contains(string(rs[len(rs)-1]), "request_uri\":\"/.well-known/foo/baz") ||
|
||||||
|
!strings.Contains(string(rs[len(rs)-2]), "request_uri\":\"/.well-known/foo/baz") {
|
||||||
|
t.Fatal("did not find request_uri in audit entries")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user