diff --git a/pkg/services/ldap/ldap.go b/pkg/services/ldap/ldap.go index 7b153f067ce..cdef230d271 100644 --- a/pkg/services/ldap/ldap.go +++ b/pkg/services/ldap/ldap.go @@ -18,6 +18,7 @@ import ( "github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" ) // IConnection is interface for LDAP connection manipulation @@ -99,7 +100,7 @@ func (server *Server) Dial() error { var certPool *x509.CertPool if server.Config.RootCACert != "" { certPool = x509.NewCertPool() - for _, caCertFile := range strings.Split(server.Config.RootCACert, " ") { + for _, caCertFile := range util.SplitString(server.Config.RootCACert) { // nolint:gosec // We can ignore the gosec G304 warning on this one because `caCertFile` comes from ldap config. pem, err := os.ReadFile(caCertFile) diff --git a/pkg/util/strings.go b/pkg/util/strings.go index 2b469833e5c..44c5dcd4eb0 100644 --- a/pkg/util/strings.go +++ b/pkg/util/strings.go @@ -4,11 +4,14 @@ import ( "encoding/json" "fmt" "math" + "regexp" "strings" "time" "unicode" ) +var stringListItemMatcher = regexp.MustCompile(`"[^"]+"|[^,\t\n\v\f\r ]+`) + // StringsFallback2 returns the first of two not empty strings. func StringsFallback2(val1 string, val2 string) string { return stringsFallback(val1, val2) @@ -28,7 +31,8 @@ func stringsFallback(vals ...string) string { return "" } -// SplitString splits a string by commas or empty spaces. +// SplitString splits a string and returns a list of strings. It supports JSON list syntax and strings separated by commas or spaces. +// It supports quoted strings with spaces, e.g. "foo bar", "baz". func SplitString(str string) []string { if len(str) == 0 { return []string{} @@ -44,7 +48,12 @@ func SplitString(str string) []string { return res } - return strings.Fields(strings.ReplaceAll(str, ",", " ")) + var result []string + matches := stringListItemMatcher.FindAllString(str, -1) + for _, match := range matches { + result = append(result, strings.Trim(match, "\"")) + } + return result } // GetAgeString returns a string representing certain time from years to minutes. diff --git a/pkg/util/strings_test.go b/pkg/util/strings_test.go index 876cb705974..d3524f8539e 100644 --- a/pkg/util/strings_test.go +++ b/pkg/util/strings_test.go @@ -56,7 +56,14 @@ func TestSplitString(t *testing.T) { `["foo", "bar baz"]`: {"foo", "bar baz"}, `["foo", "bar \"baz\""]`: {"foo", "bar \"baz\""}, ` ["foo", "bar baz"]`: {"foo", "bar baz"}, - `[]`: {}, + `"foo", "bar", "baz"`: {"foo", "bar", "baz"}, + `"foo" "bar" "baz"`: {"foo", "bar", "baz"}, + ` "foo" "bar" "baz" `: {"foo", "bar", "baz"}, + `"foo", "bar baz"`: {"foo", "bar baz"}, + `"foo", bar "baz"`: {"foo", "bar", "baz"}, + `"first string", "second string", "third string"`: {"first string", "second string", "third string"}, + `"first string" "second string" "third string" "fourth string"`: {"first string", "second string", "third string", "fourth string"}, + `[]`: {}, } for input, expected := range tests { assert.EqualValues(t, expected, SplitString(input))