Commit 6a3a2f5f by Marcus Efraimsson Committed by GitHub

CLI: Fix encrypt-datasource-passwords fails with sql error (#18014)

Now handles secure_json_data stored as null in database when
running the encrypt-datasource-passwords migration.

Fixes #17948
parent 5d3a60d4
......@@ -62,7 +62,7 @@ func EncryptDatasourcePaswords(c utils.CommandLine, sqlStore *sqlstore.SqlStore)
}
func migrateColumn(session *sqlstore.DBSession, column string) (int, error) {
var rows []map[string]string
var rows []map[string][]byte
session.Cols("id", column, "secure_json_data")
session.Table("data_source")
......@@ -78,7 +78,7 @@ func migrateColumn(session *sqlstore.DBSession, column string) (int, error) {
return rowsUpdated, errutil.Wrapf(err, "failed to update column: %s", column)
}
func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordFieldName string) (int, error) {
func updateRows(session *sqlstore.DBSession, rows []map[string][]byte, passwordFieldName string) (int, error) {
var rowsUpdated int
for _, row := range rows {
......@@ -94,7 +94,7 @@ func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordF
newRow := map[string]interface{}{"secure_json_data": data, passwordFieldName: ""}
session.Table("data_source")
session.Where("id = ?", row["id"])
session.Where("id = ?", string(row["id"]))
// Setting both columns while having value only for secure_json_data should clear the [passwordFieldName] column
session.Cols("secure_json_data", passwordFieldName)
......@@ -108,17 +108,21 @@ func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordF
return rowsUpdated, nil
}
func getUpdatedSecureJSONData(row map[string]string, passwordFieldName string) (map[string]interface{}, error) {
encryptedPassword, err := util.Encrypt([]byte(row[passwordFieldName]), setting.SecretKey)
func getUpdatedSecureJSONData(row map[string][]byte, passwordFieldName string) (map[string]interface{}, error) {
encryptedPassword, err := util.Encrypt(row[passwordFieldName], setting.SecretKey)
if err != nil {
return nil, err
}
var secureJSONData map[string]interface{}
if err := json.Unmarshal([]byte(row["secure_json_data"]), &secureJSONData); err != nil {
if len(row["secure_json_data"]) > 0 {
if err := json.Unmarshal(row["secure_json_data"], &secureJSONData); err != nil {
return nil, err
}
} else {
secureJSONData = map[string]interface{}{}
}
jsonFieldName := util.ToCamelCase(passwordFieldName)
secureJSONData[jsonFieldName] = encryptedPassword
......
......@@ -20,19 +20,30 @@ func TestPasswordMigrationCommand(t *testing.T) {
datasources := []*models.DataSource{
{Type: "influxdb", Name: "influxdb", Password: "foobar"},
{Type: "graphite", Name: "graphite", BasicAuthPassword: "foobar"},
{Type: "prometheus", Name: "prometheus", SecureJsonData: securejsondata.GetEncryptedJsonData(map[string]string{})},
{Type: "prometheus", Name: "prometheus"},
{Type: "elasticsearch", Name: "elasticsearch", Password: "pwd"},
}
// set required default values
for _, ds := range datasources {
ds.Created = time.Now()
ds.Updated = time.Now()
if ds.Name == "elasticsearch" {
ds.SecureJsonData = securejsondata.GetEncryptedJsonData(map[string]string{
"key": "value",
})
} else {
ds.SecureJsonData = securejsondata.GetEncryptedJsonData(map[string]string{})
}
}
_, err := session.Insert(&datasources)
assert.Nil(t, err)
// force secure_json_data to be null to verify that migration can handle that
_, err = session.Exec("update data_source set secure_json_data = null where name = 'influxdb'")
assert.Nil(t, err)
//run migration
err = EncryptDatasourcePaswords(&commandstest.FakeCommandLine{}, sqlstore)
assert.Nil(t, err)
......@@ -41,7 +52,7 @@ func TestPasswordMigrationCommand(t *testing.T) {
var dss []*models.DataSource
err = session.SQL("select * from data_source").Find(&dss)
assert.Nil(t, err)
assert.Equal(t, len(dss), 3)
assert.Equal(t, len(dss), 4)
for _, ds := range dss {
sj := ds.SecureJsonData.Decrypt()
......@@ -63,5 +74,15 @@ func TestPasswordMigrationCommand(t *testing.T) {
if ds.Name == "prometheus" {
assert.Equal(t, len(sj), 0)
}
if ds.Name == "elasticsearch" {
assert.Equal(t, ds.Password, "")
key, exist := sj["key"]
assert.True(t, exist)
password, exist := sj["password"]
assert.True(t, exist)
assert.Equal(t, password, "pwd", "expected password to be moved to securejson")
assert.Equal(t, key, "value", "expected existing key to be kept intact in securejson")
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment