mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	Redacted Information With Valid Token (#25735)
This commit is contained in:
		| @@ -57,8 +57,20 @@ func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	opts, err := getOpts(opt...) | 	var tokenPresent bool | ||||||
|  | 	token := r.Header.Get(consts.AuthHeaderName) | ||||||
|  |  | ||||||
|  | 	if token != "" { | ||||||
|  | 		// We don't care about the error, we just want to know if the token exists | ||||||
|  | 		lock := core.HALock() | ||||||
|  | 		lock.Lock() | ||||||
|  | 		tokenEntry, err := core.LookupToken(r.Context(), token) | ||||||
|  | 		lock.Unlock() | ||||||
|  | 		tokenPresent = err == nil && tokenEntry != nil | ||||||
|  | 	} | ||||||
|  | 	opts, _ := getOpts(opt...) | ||||||
|  |  | ||||||
|  | 	if !tokenPresent { | ||||||
| 		if opts.withRedactVersion { | 		if opts.withRedactVersion { | ||||||
| 			body.Version = opts.withRedactionValue | 			body.Version = opts.withRedactionValue | ||||||
| 		} | 		} | ||||||
| @@ -66,6 +78,7 @@ func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request | |||||||
| 		if opts.withRedactClusterName { | 		if opts.withRedactClusterName { | ||||||
| 			body.ClusterName = opts.withRedactionValue | 			body.ClusterName = opts.withRedactionValue | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	w.Header().Set("Content-Type", "application/json") | 	w.Header().Set("Content-Type", "application/json") | ||||||
| 	w.WriteHeader(code) | 	w.WriteHeader(code) | ||||||
|   | |||||||
| @@ -4,9 +4,9 @@ | |||||||
| package http | package http | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"github.com/hashicorp/vault/sdk/helper/consts" | ||||||
| 	"github.com/hashicorp/vault/sdk/logical" | 	"github.com/hashicorp/vault/sdk/logical" | ||||||
| 	"github.com/hashicorp/vault/vault" | 	"github.com/hashicorp/vault/vault" | ||||||
| ) | ) | ||||||
| @@ -17,19 +17,29 @@ func handleSysLeader(core *vault.Core, opt ...ListenerConfigOption) http.Handler | |||||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		switch r.Method { | 		switch r.Method { | ||||||
| 		case "GET": | 		case "GET": | ||||||
| 			handleSysLeaderGet(core, w, opt...) | 			handleSysLeaderGet(core, w, r, opt...) | ||||||
| 		default: | 		default: | ||||||
| 			respondError(w, http.StatusMethodNotAllowed, nil) | 			respondError(w, http.StatusMethodNotAllowed, nil) | ||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, opt ...ListenerConfigOption) { | func handleSysLeaderGet(core *vault.Core, w http.ResponseWriter, r *http.Request, opt ...ListenerConfigOption) { | ||||||
| 	ctx := context.Background() | 	var tokenPresent bool | ||||||
|  | 	token := r.Header.Get(consts.AuthHeaderName) | ||||||
|  | 	ctx := r.Context() | ||||||
|  |  | ||||||
| 	opts, _ := getOpts(opt...) | 	if token != "" { | ||||||
| 	if opts.withRedactAddresses { | 		// We don't care about the error, we just want to know if token exists | ||||||
| 		ctx = logical.CreateContextRedactionSettings(ctx, false, true, false) | 		lock := core.HALock() | ||||||
|  | 		lock.Lock() | ||||||
|  | 		tokenEntry, err := core.LookupToken(ctx, token) | ||||||
|  | 		lock.Unlock() | ||||||
|  | 		tokenPresent = err == nil && tokenEntry != nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if tokenPresent { | ||||||
|  | 		ctx = logical.CreateContextRedactionSettings(r.Context(), false, false, false) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	resp, err := core.GetLeaderStatus(ctx) | 	resp, err := core.GetLeaderStatus(ctx) | ||||||
|   | |||||||
| @@ -98,7 +98,7 @@ func handleSysUnseal(core *vault.Core) http.Handler { | |||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 			core.ResetUnsealProcess() | 			core.ResetUnsealProcess() | ||||||
| 			handleSysSealStatusRaw(core, w) | 			handleSysSealStatusRaw(core, w, r) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -148,7 +148,7 @@ func handleSysUnseal(core *vault.Core) http.Handler { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Return the seal status | 		// Return the seal status | ||||||
| 		handleSysSealStatusRaw(core, w) | 		handleSysSealStatusRaw(core, w, r) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -159,7 +159,7 @@ func handleSysSealStatus(core *vault.Core, opt ...ListenerConfigOption) http.Han | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		handleSysSealStatusRaw(core, w, opt...) | 		handleSysSealStatusRaw(core, w, r, opt...) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -174,25 +174,30 @@ func handleSysSealBackendStatus(core *vault.Core) http.Handler { | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, opt ...ListenerConfigOption) { | func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Request, opt ...ListenerConfigOption) { | ||||||
| 	ctx := context.Background() | 	ctx := r.Context() | ||||||
|  |  | ||||||
|  | 	var tokenPresent bool | ||||||
|  | 	token := r.Header.Get(consts.AuthHeaderName) | ||||||
|  | 	if token != "" { | ||||||
|  | 		// We don't care about the error, we just want to know if the token exists | ||||||
|  | 		lock := core.HALock() | ||||||
|  | 		lock.Lock() | ||||||
|  | 		tokenEntry, err := core.LookupToken(ctx, token) | ||||||
|  | 		lock.Unlock() | ||||||
|  | 		tokenPresent = err == nil && tokenEntry != nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If there are is no valid token then we will redact the specified values | ||||||
|  | 	if tokenPresent { | ||||||
|  | 		ctx = logical.CreateContextRedactionSettings(ctx, false, false, false) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	status, err := core.GetSealStatus(ctx, true) | 	status, err := core.GetSealStatus(ctx, true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		respondError(w, http.StatusInternalServerError, err) | 		respondError(w, http.StatusInternalServerError, err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	opts, err := getOpts(opt...) |  | ||||||
|  |  | ||||||
| 	if opts.withRedactVersion { |  | ||||||
| 		status.Version = opts.withRedactionValue |  | ||||||
| 		status.BuildDate = opts.withRedactionValue |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if opts.withRedactClusterName { |  | ||||||
| 		status.ClusterName = opts.withRedactionValue |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	respondOk(w, status) | 	respondOk(w, status) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -203,7 +208,6 @@ func handleSysSealBackendStatusRaw(core *vault.Core, w http.ResponseWriter, r *h | |||||||
| 		respondError(w, http.StatusInternalServerError, err) | 		respondError(w, http.StatusInternalServerError, err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	respondOk(w, status) | 	respondOk(w, status) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,11 +15,18 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/go-test/deep" | 	"github.com/go-test/deep" | ||||||
|  | 	"github.com/hashicorp/go-cleanhttp" | ||||||
|  | 	"github.com/hashicorp/vault/audit" | ||||||
|  | 	auditFile "github.com/hashicorp/vault/builtin/audit/file" | ||||||
| 	"github.com/hashicorp/vault/helper/namespace" | 	"github.com/hashicorp/vault/helper/namespace" | ||||||
|  | 	"github.com/hashicorp/vault/helper/testhelpers/corehelpers" | ||||||
|  | 	"github.com/hashicorp/vault/internalshared/configutil" | ||||||
|  | 	"github.com/hashicorp/vault/sdk/helper/consts" | ||||||
| 	"github.com/hashicorp/vault/sdk/logical" | 	"github.com/hashicorp/vault/sdk/logical" | ||||||
| 	"github.com/hashicorp/vault/vault" | 	"github.com/hashicorp/vault/vault" | ||||||
| 	"github.com/hashicorp/vault/vault/seal" | 	"github.com/hashicorp/vault/vault/seal" | ||||||
| 	"github.com/hashicorp/vault/version" | 	"github.com/hashicorp/vault/version" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestSysSealStatus(t *testing.T) { | func TestSysSealStatus(t *testing.T) { | ||||||
| @@ -556,3 +563,64 @@ func TestSysStepDown(t *testing.T) { | |||||||
| 	resp := testHttpPut(t, token, addr+"/v1/sys/step-down", nil) | 	resp := testHttpPut(t, token, addr+"/v1/sys/step-down", nil) | ||||||
| 	testResponseStatus(t, resp, 204) | 	testResponseStatus(t, resp, 204) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TestSysSealStatusRedaction tests that the response from a | ||||||
|  | // a request to sys/seal-status are redacted only if no valid token | ||||||
|  | // is provided with the request | ||||||
|  | func TestSysSealStatusRedaction(t *testing.T) { | ||||||
|  | 	conf := &vault.CoreConfig{ | ||||||
|  | 		EnableUI:        false, | ||||||
|  | 		EnableRaw:       true, | ||||||
|  | 		BuiltinRegistry: corehelpers.NewMockBuiltinRegistry(), | ||||||
|  | 		AuditBackends: map[string]audit.Factory{ | ||||||
|  | 			"file": auditFile.Factory, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	core, _, token := vault.TestCoreUnsealedWithConfig(t, conf) | ||||||
|  |  | ||||||
|  | 	// Setup new custom listener | ||||||
|  | 	ln, addr := TestListener(t) | ||||||
|  | 	props := &vault.HandlerProperties{ | ||||||
|  | 		Core: core, | ||||||
|  | 		ListenerConfig: &configutil.Listener{ | ||||||
|  | 			RedactVersion: true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	TestServerWithListenerAndProperties(t, ln, addr, core, props) | ||||||
|  | 	defer ln.Close() | ||||||
|  | 	TestServerAuth(t, addr, token) | ||||||
|  |  | ||||||
|  | 	client := cleanhttp.DefaultClient() | ||||||
|  |  | ||||||
|  | 	// Check seal-status | ||||||
|  | 	req, err := http.NewRequest("GET", addr+"/v1/sys/seal-status", nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("err: %s", err) | ||||||
|  | 	} | ||||||
|  | 	req.Header.Set(consts.AuthHeaderName, token) | ||||||
|  | 	resp, err := client.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("err: %s", err) | ||||||
|  | 	} | ||||||
|  | 	testResponseStatus(t, resp, 200) | ||||||
|  |  | ||||||
|  | 	// Verify that version exists when provided a valid token | ||||||
|  | 	var actual map[string]interface{} | ||||||
|  | 	testResponseStatus(t, resp, 200) | ||||||
|  | 	testResponseBody(t, resp, &actual) | ||||||
|  | 	assert.NotEmpty(t, actual["version"]) | ||||||
|  |  | ||||||
|  | 	// Verify that version is redacted when no token is provided | ||||||
|  | 	req, err = http.NewRequest("GET", addr+"/v1/sys/seal-status", nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("err: %s", err) | ||||||
|  | 	} | ||||||
|  | 	req.Header.Set(consts.AuthHeaderName, "") | ||||||
|  | 	resp, err = client.Do(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("err: %s", err) | ||||||
|  | 	} | ||||||
|  | 	testResponseStatus(t, resp, 200) | ||||||
|  | 	testResponseBody(t, resp, &actual) | ||||||
|  | 	assert.Empty(t, actual["version"]) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -640,6 +640,9 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption | |||||||
| 			listener := cfg["tcp"].(map[string]interface{}) | 			listener := cfg["tcp"].(map[string]interface{}) | ||||||
| 			listener["address"] = fmt.Sprintf("%s:%d", "0.0.0.0", config.Port) | 			listener["address"] = fmt.Sprintf("%s:%d", "0.0.0.0", config.Port) | ||||||
| 			listener["chroot_namespace"] = config.ChrootNamespace | 			listener["chroot_namespace"] = config.ChrootNamespace | ||||||
|  | 			listener["redact_addresses"] = config.RedactAddresses | ||||||
|  | 			listener["redact_cluster_name"] = config.RedactClusterName | ||||||
|  | 			listener["redact_version"] = config.RedactVersion | ||||||
| 			listenerConfig = append(listenerConfig, cfg) | 			listenerConfig = append(listenerConfig, cfg) | ||||||
| 			portStr := fmt.Sprintf("%d/tcp", config.Port) | 			portStr := fmt.Sprintf("%d/tcp", config.Port) | ||||||
| 			if strutil.StrListContains(ports, portStr) { | 			if strutil.StrListContains(ports, portStr) { | ||||||
|   | |||||||
| @@ -107,6 +107,9 @@ type ClusterOptions struct { | |||||||
| type VaultNodeListenerConfig struct { | type VaultNodeListenerConfig struct { | ||||||
| 	Port              int | 	Port              int | ||||||
| 	ChrootNamespace   string | 	ChrootNamespace   string | ||||||
|  | 	RedactAddresses   bool | ||||||
|  | 	RedactClusterName bool | ||||||
|  | 	RedactVersion     bool | ||||||
| } | } | ||||||
|  |  | ||||||
| type CA struct { | type CA struct { | ||||||
|   | |||||||
| @@ -743,6 +743,10 @@ func (c *Core) HAStateWithLock() consts.HAState { | |||||||
| 	return c.HAState() | 	return c.HAState() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (c *Core) HALock() sync.Locker { | ||||||
|  | 	return c.stateLock.RLocker() | ||||||
|  | } | ||||||
|  |  | ||||||
| // CoreConfig is used to parameterize a core | // CoreConfig is used to parameterize a core | ||||||
| type CoreConfig struct { | type CoreConfig struct { | ||||||
| 	entCoreConfig | 	entCoreConfig | ||||||
|   | |||||||
| @@ -5675,6 +5675,17 @@ func (core *Core) GetLeaderStatusLocked(ctx context.Context) (*LeaderResponse, e | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | ||||||
|  | 	var tokenPresent bool | ||||||
|  | 	token := req.ClientToken | ||||||
|  | 	if token != "" { | ||||||
|  | 		// We don't care about the error, we just want to know if the token exists | ||||||
|  | 		_, tokenEntry, _, _, err := b.Core.fetchACLTokenEntryAndEntity(ctx, req) | ||||||
|  | 		tokenPresent = err == nil && tokenEntry != nil | ||||||
|  | 	} | ||||||
|  | 	// If there is a valid token then we will not redact any values | ||||||
|  | 	if tokenPresent { | ||||||
|  | 		ctx = logical.CreateContextRedactionSettings(ctx, false, false, false) | ||||||
|  | 	} | ||||||
| 	status, err := b.Core.GetSealStatus(ctx, false) | 	status, err := b.Core.GetSealStatus(ctx, false) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -5694,6 +5705,18 @@ func (b *SystemBackend) handleSealStatus(ctx context.Context, req *logical.Reque | |||||||
| } | } | ||||||
|  |  | ||||||
| func (b *SystemBackend) handleLeaderStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | func (b *SystemBackend) handleLeaderStatus(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | ||||||
|  | 	var tokenPresent bool | ||||||
|  | 	token := req.ClientToken | ||||||
|  |  | ||||||
|  | 	if token != "" { | ||||||
|  | 		// We don't care about the error, we just want to know if token exists | ||||||
|  | 		_, tokenEntry, _, _, err := b.Core.fetchACLTokenEntryAndEntity(ctx, req) | ||||||
|  | 		tokenPresent = err == nil && tokenEntry != nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if tokenPresent { | ||||||
|  | 		ctx = logical.CreateContextRedactionSettings(ctx, false, false, false) | ||||||
|  | 	} | ||||||
| 	status, err := b.Core.GetLeaderStatusLocked(ctx) | 	status, err := b.Core.GetLeaderStatusLocked(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 divyaac
					divyaac