From 2533f210155b852b22a21a42a8443950f41878be Mon Sep 17 00:00:00 2001
From: Guilherme Caulada <guilherme.caulada@grafana.com>
Date: Mon, 2 May 2022 11:29:13 -0300
Subject: [PATCH] DataSource: Fix secure json data reset on datasource update
 (#48557)

* Fix secure json data reset on datasource update

* Update fillWithSecureJSONData to use DecryptedValues

* Remove unecessary conversion

* Move fillWithSecureJsonData logic to datasource service

* Add sanity check for nil secure json data
---
 pkg/api/datasources.go                        | 32 ------------------
 .../datasources/service/datasource_service.go | 33 ++++++++++++++++---
 2 files changed, 29 insertions(+), 36 deletions(-)

diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go
index 7eb21d0562c..a35471d31fa 100644
--- a/pkg/api/datasources.go
+++ b/pkg/api/datasources.go
@@ -302,11 +302,6 @@ func (hs *HTTPServer) UpdateDataSource(c *models.ReqContext) response.Response {
 		return response.Error(403, "Cannot update read-only data source", nil)
 	}
 
-	err = hs.fillWithSecureJSONData(c.Req.Context(), &cmd)
-	if err != nil {
-		return response.Error(500, "Failed to update datasource", err)
-	}
-
 	err = hs.DataSourcesService.UpdateDataSource(c.Req.Context(), &cmd)
 	if err != nil {
 		if errors.Is(err, models.ErrDataSourceUpdatingOldVersion) {
@@ -339,33 +334,6 @@ func (hs *HTTPServer) UpdateDataSource(c *models.ReqContext) response.Response {
 	})
 }
 
-func (hs *HTTPServer) fillWithSecureJSONData(ctx context.Context, cmd *models.UpdateDataSourceCommand) error {
-	if len(cmd.SecureJsonData) == 0 {
-		return nil
-	}
-
-	ds, err := hs.getRawDataSourceById(ctx, cmd.Id, cmd.OrgId)
-	if err != nil {
-		return err
-	}
-
-	if ds.ReadOnly {
-		return models.ErrDatasourceIsReadOnly
-	}
-
-	for k, v := range ds.SecureJsonData {
-		if _, ok := cmd.SecureJsonData[k]; !ok {
-			decrypted, err := hs.SecretsService.Decrypt(ctx, v)
-			if err != nil {
-				return err
-			}
-			cmd.SecureJsonData[k] = string(decrypted)
-		}
-	}
-
-	return nil
-}
-
 func (hs *HTTPServer) getRawDataSourceById(ctx context.Context, id int64, orgID int64) (*models.DataSource, error) {
 	query := models.GetDataSourceQuery{
 		Id:    id,
diff --git a/pkg/services/datasources/service/datasource_service.go b/pkg/services/datasources/service/datasource_service.go
index 24c9ff6b47c..572ea48c1ca 100644
--- a/pkg/services/datasources/service/datasource_service.go
+++ b/pkg/services/datasources/service/datasource_service.go
@@ -192,10 +192,6 @@ func (s *Service) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSo
 
 func (s *Service) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error {
 	var err error
-	secret, err := json.Marshal(cmd.SecureJsonData)
-	if err != nil {
-		return err
-	}
 
 	query := &models.GetDataSourceQuery{
 		Id:    cmd.Id,
@@ -206,6 +202,11 @@ func (s *Service) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSo
 		return err
 	}
 
+	err = s.fillWithSecureJSONData(ctx, cmd, query.Result)
+	if err != nil {
+		return err
+	}
+
 	err = s.SQLStore.UpdateDataSource(ctx, cmd)
 	if err != nil {
 		return err
@@ -218,6 +219,11 @@ func (s *Service) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSo
 		}
 	}
 
+	secret, err := json.Marshal(cmd.SecureJsonData)
+	if err != nil {
+		return err
+	}
+
 	return s.SecretsStore.Set(ctx, cmd.OrgId, cmd.Name, secretType, string(secret))
 }
 
@@ -559,3 +565,22 @@ func awsServiceNamespace(dsType string) string {
 		panic(fmt.Sprintf("Unsupported datasource %q", dsType))
 	}
 }
+
+func (s *Service) fillWithSecureJSONData(ctx context.Context, cmd *models.UpdateDataSourceCommand, ds *models.DataSource) error {
+	decrypted, err := s.DecryptedValues(ctx, ds)
+	if err != nil {
+		return err
+	}
+
+	if cmd.SecureJsonData == nil {
+		cmd.SecureJsonData = make(map[string]string)
+	}
+
+	for k, v := range decrypted {
+		if _, ok := cmd.SecureJsonData[k]; !ok {
+			cmd.SecureJsonData[k] = v
+		}
+	}
+
+	return nil
+}