From 89e3060db004cfff0cae005595dbfacaa3f6749d Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Tue, 18 Aug 2026 12:16:57 +0200 Subject: [PATCH] api: redact password in responses (#6110) passwords are not exposed anymore through the API. They can only be set, not read. --- internal/api/api.go | 29 ++++++++++++++++++++ internal/api/api_config_global.go | 2 +- internal/api/api_config_global_test.go | 11 +++++++- internal/api/api_config_pathdefaults.go | 2 +- internal/api/api_config_pathdefaults_test.go | 6 +++- internal/api/api_config_paths.go | 4 +-- internal/api/api_config_paths_test.go | 5 ++-- 7 files changed, 51 insertions(+), 8 deletions(-) diff --git a/internal/api/api.go b/internal/api/api.go index 98309177..b37803e7 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -20,6 +20,7 @@ import ( const ( maxInboundConfigSize = 10 * 1024 * 1024 + redactedCredential = "" ) func interfaceIsEmpty(i any) bool { @@ -47,6 +48,34 @@ func paramName(ctx *gin.Context) (string, bool) { return name[1:], true } +func redactCredentials(c *conf.Conf) *conf.Conf { + c = c.Clone() + + for i := range c.AuthInternalUsers { + if c.AuthInternalUsers[i].Pass != "" { + c.AuthInternalUsers[i].Pass = conf.Credential(redactedCredential) + } + } + + if c.PathDefaults.PublishPass != nil && *c.PathDefaults.PublishPass != "" { + *c.PathDefaults.PublishPass = conf.Credential(redactedCredential) + } + if c.PathDefaults.ReadPass != nil && *c.PathDefaults.ReadPass != "" { + *c.PathDefaults.ReadPass = conf.Credential(redactedCredential) + } + + for _, pathConf := range c.Paths { + if pathConf.PublishPass != nil && *pathConf.PublishPass != "" { + *pathConf.PublishPass = conf.Credential(redactedCredential) + } + if pathConf.ReadPass != nil && *pathConf.ReadPass != "" { + *pathConf.ReadPass = conf.Credential(redactedCredential) + } + } + + return c +} + type apiAuthManager interface { Authenticate(req *auth.Request) (string, *auth.Error) RefreshJWTJWKS() diff --git a/internal/api/api_config_global.go b/internal/api/api_config_global.go index f38c377a..c784def8 100644 --- a/internal/api/api_config_global.go +++ b/internal/api/api_config_global.go @@ -10,7 +10,7 @@ import ( ) func (a *API) onConfigGlobalGet(ctx *gin.Context) { - c := a.Parent.APIConfigSnapshot() + c := redactCredentials(a.Parent.APIConfigSnapshot()) ctx.JSON(http.StatusOK, c.Global()) } diff --git a/internal/api/api_config_global_test.go b/internal/api/api_config_global_test.go index def06b0d..f90c3698 100644 --- a/internal/api/api_config_global_test.go +++ b/internal/api/api_config_global_test.go @@ -15,7 +15,12 @@ import ( ) func TestConfigGlobalGet(t *testing.T) { - cnf := tempConf(t, "api: yes\n") + cnf := tempConf(t, "api: yes\n"+ + "authInternalUsers:\n"+ + " - user: myuser\n"+ + " pass: mypass\n"+ + " permissions:\n"+ + " - action: api\n") checked := false api := API{ @@ -45,6 +50,10 @@ func TestConfigGlobalGet(t *testing.T) { httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/global/get", nil, &out) require.Equal(t, true, out["api"]) + authInternalUsers := out["authInternalUsers"].([]any) + require.Len(t, authInternalUsers, 1) + require.Equal(t, redactedCredential, authInternalUsers[0].(map[string]any)["pass"]) + require.True(t, checked) } diff --git a/internal/api/api_config_pathdefaults.go b/internal/api/api_config_pathdefaults.go index 72060daf..661c4d59 100644 --- a/internal/api/api_config_pathdefaults.go +++ b/internal/api/api_config_pathdefaults.go @@ -10,7 +10,7 @@ import ( ) func (a *API) onConfigPathDefaultsGet(ctx *gin.Context) { - c := a.Parent.APIConfigSnapshot() + c := redactCredentials(a.Parent.APIConfigSnapshot()) ctx.JSON(http.StatusOK, c.PathDefaults) } diff --git a/internal/api/api_config_pathdefaults_test.go b/internal/api/api_config_pathdefaults_test.go index 46302d70..4937de71 100644 --- a/internal/api/api_config_pathdefaults_test.go +++ b/internal/api/api_config_pathdefaults_test.go @@ -12,7 +12,10 @@ import ( ) func TestConfigPathDefaultsGet(t *testing.T) { - cnf := tempConf(t, "api: yes\n") + cnf := tempConf(t, "api: yes\n"+ + "pathDefaults:\n"+ + " readUser: myuser\n"+ + " readPass: mypass\n") api := API{ Address: "localhost:9997", @@ -32,6 +35,7 @@ func TestConfigPathDefaultsGet(t *testing.T) { var out map[string]any httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/pathdefaults/get", nil, &out) require.Equal(t, "publisher", out["source"]) + require.Equal(t, redactedCredential, out["readPass"]) } func TestConfigPathDefaultsPatch(t *testing.T) { diff --git a/internal/api/api_config_paths.go b/internal/api/api_config_paths.go index 46d4d4d8..c080cd6a 100644 --- a/internal/api/api_config_paths.go +++ b/internal/api/api_config_paths.go @@ -13,7 +13,7 @@ import ( ) func (a *API) onConfigPathsList(ctx *gin.Context) { - c := a.Parent.APIConfigSnapshot() + c := redactCredentials(a.Parent.APIConfigSnapshot()) data := &defs.APIPathConfList{ Items: make([]conf.Path, len(c.Paths)), @@ -41,7 +41,7 @@ func (a *API) onConfigPathsGet(ctx *gin.Context) { return } - c := a.Parent.APIConfigSnapshot() + c := redactCredentials(a.Parent.APIConfigSnapshot()) p, ok := c.Paths[confName] if !ok { diff --git a/internal/api/api_config_paths_test.go b/internal/api/api_config_paths_test.go index 9a81205e..cfe7760b 100644 --- a/internal/api/api_config_paths_test.go +++ b/internal/api/api_config_paths_test.go @@ -52,10 +52,10 @@ func TestConfigPathsList(t *testing.T) { require.Equal(t, 1, out.PageCount) require.Equal(t, "path1", out.Items[0]["name"]) require.Equal(t, "myuser1", out.Items[0]["readUser"]) - require.Equal(t, "mypass1", out.Items[0]["readPass"]) + require.Equal(t, redactedCredential, out.Items[0]["readPass"]) require.Equal(t, "path2", out.Items[1]["name"]) require.Equal(t, "myuser2", out.Items[1]["readUser"]) - require.Equal(t, "mypass2", out.Items[1]["readPass"]) + require.Equal(t, redactedCredential, out.Items[1]["readPass"]) } func TestConfigPathsGet(t *testing.T) { @@ -84,6 +84,7 @@ func TestConfigPathsGet(t *testing.T) { httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/paths/get/my/path", nil, &out) require.Equal(t, "my/path", out["name"]) require.Equal(t, "myuser", out["readUser"]) + require.Equal(t, redactedCredential, out["readPass"]) } func TestConfigPathsAdd(t *testing.T) {