Browse Source

MSSQL: Change connectionstring to URL format to fix using passwords with semicolon (#18384)

Fixes #17665
Elykov Alexandr 6 years ago
parent
commit
2514209083
2 changed files with 41 additions and 16 deletions
  1. 14 16
      pkg/tsdb/mssql/mssql.go
  2. 27 0
      pkg/tsdb/mssql/mssql_test.go

+ 14 - 16
pkg/tsdb/mssql/mssql.go

@@ -4,6 +4,7 @@ import (
 	"database/sql"
 	"fmt"
 	"github.com/grafana/grafana/pkg/setting"
+	"net/url"
 	"strconv"
 
 	_ "github.com/denisenkom/go-mssqldb"
@@ -21,10 +22,7 @@ func init() {
 func newMssqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
 	logger := log.New("tsdb.mssql")
 
-	cnnstr, err := generateConnectionString(datasource)
-	if err != nil {
-		return nil, err
-	}
+	cnnstr := generateConnectionString(datasource)
 	if setting.Env == setting.DEV {
 		logger.Debug("getEngine", "connection", cnnstr)
 	}
@@ -43,21 +41,21 @@ func newMssqlQueryEndpoint(datasource *models.DataSource) (tsdb.TsdbQueryEndpoin
 	return tsdb.NewSqlQueryEndpoint(&config, &rowTransformer, newMssqlMacroEngine(), logger)
 }
 
-func generateConnectionString(datasource *models.DataSource) (string, error) {
+func generateConnectionString(datasource *models.DataSource) string {
 	server, port := util.SplitHostPortDefault(datasource.Url, "localhost", "1433")
-
 	encrypt := datasource.JsonData.Get("encrypt").MustString("false")
-	connStr := fmt.Sprintf("server=%s;port=%s;database=%s;user id=%s;password=%s;",
-		server,
-		port,
-		datasource.Database,
-		datasource.User,
-		datasource.DecryptedPassword(),
-	)
-	if encrypt != "false" {
-		connStr += fmt.Sprintf("encrypt=%s;", encrypt)
+
+	query := url.Values{}
+	query.Add("database", datasource.Database)
+	query.Add("encrypt", encrypt)
+
+	u := &url.URL{
+		Scheme:   "sqlserver",
+		User:     url.UserPassword(datasource.User, datasource.DecryptedPassword()),
+		Host:     fmt.Sprintf("%s:%s", server, port),
+		RawQuery: query.Encode(),
 	}
-	return connStr, nil
+	return u.String()
 }
 
 type mssqlRowTransformer struct {

+ 27 - 0
pkg/tsdb/mssql/mssql_test.go

@@ -27,6 +27,33 @@ import (
 // If needed, change the variable below to the IP address of the database.
 var serverIP = "localhost"
 
+func TestGenerateConnectionString(t *testing.T) {
+	encrypted, _ := simplejson.NewJson([]byte(`{"encrypt":"false"}`))
+	testSet := []struct {
+		ds       *models.DataSource
+		expected string
+	}{
+		{
+			&models.DataSource{
+				User:     "user",
+				Database: "db",
+				Url:      "localhost:1433",
+				SecureJsonData: securejsondata.GetEncryptedJsonData(map[string]string{
+					"password": "pass;word",
+				}),
+				JsonData: encrypted,
+			},
+			"sqlserver://user:pass;word@localhost:1433?database=db&encrypt=false",
+		},
+	}
+	for i := range testSet {
+		got := generateConnectionString(testSet[i].ds)
+		if got != testSet[i].expected {
+			t.Errorf("mssql connString error for testCase %d got: %s expected: %s", i, got, testSet[i].expected)
+		}
+	}
+}
+
 func TestMSSQL(t *testing.T) {
 	SkipConvey("MSSQL", t, func() {
 		x := InitMSSQLTestDB(t)