Skip to content

Commit

Permalink
feat: Concealing Passwords in Config Key Retrieval (#2319)
Browse files Browse the repository at this point in the history
Signed-off-by: Rui-Gan <[email protected]>
  • Loading branch information
Rui-Gan authored and ngjaying committed Oct 18, 2023
1 parent 794dd12 commit c4fa1c1
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 3 deletions.
5 changes: 4 additions & 1 deletion docs/en_US/api/restapi/configKey.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ Example request to get all Config Keys from an MQTT source:
"insecureSkipVerify": false,
"protocolVersion": "3.1.1",
"qos": 1,
"server": "tcp://122.9.166.75:1883"
"server": "tcp://122.9.166.75:1883",
"password": "******"
},
"default": {
"qos": 2,
Expand All @@ -40,6 +41,8 @@ Example request to get all Config Keys from an MQTT source:
}
```

Note: When retrieving Config Keys, if the properties contain a password field (case-insensitive, such as Password), the API will not return the actual password value, but instead replace it with "******" to conceal the password information.

## Delete a configKey

This API is used to delete a Config Key configuration under a specific source name
Expand Down
5 changes: 4 additions & 1 deletion docs/zh_CN/api/restapi/configKey.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ GET http://localhost:9081/metadata/sources/yaml/{name}
"insecureSkipVerify": false,
"protocolVersion": "3.1.1",
"qos": 1,
"server": "tcp://122.9.166.75:1883"
"server": "tcp://122.9.166.75:1883",
"password": "******"
},
"default": {
"qos": 2,
Expand All @@ -39,6 +40,8 @@ GET http://localhost:9081/metadata/sources/yaml/{name}
}
```

注意:当获取 Config Key 时,如果属性中包含 password 字段(不区分大小写,例如 Password 等),API 不会返回实际密码值,而会用"******"代替以隐藏密码信息。

## 删除某个 configKey

该 API 用于删除特定源名下某个 Config Key
Expand Down
33 changes: 32 additions & 1 deletion internal/meta/yamlConfigMeta.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2022 EMQ Technologies Co., Ltd.
// Copyright 2022-2023 EMQ Technologies Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@ package meta
import (
"encoding/json"
"fmt"
"net/url"
"strings"
"sync"

Expand Down Expand Up @@ -56,6 +57,7 @@ const (
SinkCfgOperatorKeyPrefix = "sinks."
ConnectionCfgOperatorKeyTemplate = "connections.%s"
ConnectionCfgOperatorKeyPrefix = "connections."
PASSWORD = "******"
)

// loadConfigOperatorForSource
Expand Down Expand Up @@ -153,13 +155,42 @@ func GetYamlConf(configOperatorKey, language string) (b []byte, err error) {
}

cf := cfgOps.CopyConfContent()
for key, kvs := range cf {
cf[key] = hiddenPassword(kvs)
}
if b, err = json.Marshal(cf); nil != err {
return nil, fmt.Errorf(`%s%v`, getMsg(language, source, "json_marshal_fail"), cf)
} else {
return b, err
}
}

func hiddenPassword(kvs map[string]interface{}) map[string]interface{} {
for k, v := range kvs {
if m, ok := v.(map[string]interface{}); ok {
kvs[k] = hiddenPassword(m)
}
if strings.ToLower(k) == "password" {
kvs[k] = PASSWORD
}
if strings.ToLower(k) == "url" {
if _, ok := v.(string); !ok {
continue
}
u, err := url.Parse(v.(string))
if err != nil || u.User == nil {
continue
}
password, _ := u.User.Password()
if password != "" {
u.User = url.UserPassword(u.User.Username(), PASSWORD)
kvs[k] = u.String()
}
}
}
return kvs
}

func addSourceConfKeys(plgName string, configurations YamlConfigurations) (err error) {
ConfigManager.lock.Lock()
defer ConfigManager.lock.Unlock()
Expand Down
20 changes: 20 additions & 0 deletions internal/server/meta_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,26 @@ func (suite *MetaTestSuite) TestResourcesHandler() {
assert.Equal(suite.T(), http.StatusOK, w.Code)
}

func (suite *MetaTestSuite) TestHiddenPassword() {
req, _ := http.NewRequest(http.MethodPut, "/metadata/connections/test/confKeys/test", bytes.NewBufferString(`{"password": "123456", "url": "sqlserver://username:[email protected]/testdb"}`))
w := httptest.NewRecorder()
DataDir, _ := conf.GetDataLoc()
os.MkdirAll(path.Join(DataDir, "connections"), 0o755)
if _, err := os.Create(path.Join(DataDir, "connections", "connection.yaml")); err != nil {
fmt.Println(err)
}
suite.r.ServeHTTP(w, req)
assert.Equal(suite.T(), http.StatusOK, w.Code)
req, _ = http.NewRequest(http.MethodGet, "/metadata/connections/yaml/test", bytes.NewBufferString("any"))
w = httptest.NewRecorder()
suite.r.ServeHTTP(w, req)
assert.Equal(suite.T(), http.StatusOK, w.Code)
assert.Equal(suite.T(), bytes.NewBufferString(`{"test":{"password":"******","url":"sqlserver://username:%2A%2A%2A%2A%2A%[email protected]/testdb"}}`), w.Body)

os.Remove(path.Join(DataDir, "connections", "connection.yaml"))
os.Remove(path.Join(DataDir, "connections"))
}

func TestMetaTestSuite(t *testing.T) {
suite.Run(t, new(MetaTestSuite))
}

0 comments on commit c4fa1c1

Please sign in to comment.