diff --git a/pkg/tsdb/mssql/kerberos/kerberos.go b/pkg/tsdb/mssql/kerberos/kerberos.go index 207f324672a..43e6ae178ba 100644 --- a/pkg/tsdb/mssql/kerberos/kerberos.go +++ b/pkg/tsdb/mssql/kerberos/kerberos.go @@ -2,9 +2,11 @@ package kerberos import ( "encoding/json" + "errors" "fmt" "os" "path/filepath" + "strconv" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" @@ -22,12 +24,37 @@ type KerberosAuth struct { CredentialCache string CredentialCacheLookupFile string ConfigFilePath string - UDPConnectionLimit string + UDPConnectionLimit int EnableDNSLookupKDC string } func GetKerberosSettings(settings backend.DataSourceInstanceSettings) (kerberosAuth KerberosAuth, err error) { + kerberosAuth = KerberosAuth{ + KeytabFilePath: "", + CredentialCache: "", + CredentialCacheLookupFile: "", + ConfigFilePath: "", + UDPConnectionLimit: 1, + EnableDNSLookupKDC: "", + } + err = json.Unmarshal(settings.JSONData, &kerberosAuth) + var unmarshalErr *json.UnmarshalTypeError + if err != nil && errors.As(err, &unmarshalErr) { + stringMap := map[string]any{} + err = json.Unmarshal(settings.JSONData, &stringMap) + if err != nil { + return kerberosAuth, err + } + + if stringMap["UDPConnectionLimit"] != "" { + udpConnLimit, err := strconv.Atoi(stringMap["UDPConnectionLimit"].(string)) + if err != nil { + return kerberosAuth, err + } + kerberosAuth.UDPConnectionLimit = udpConnLimit + } + } return kerberosAuth, err } @@ -65,8 +92,8 @@ func Krb5ParseAuthCredentials(host string, port string, db string, user string, return "" } - if kerberosAuth.UDPConnectionLimit != "" { - krb5DriverParams += "krb5-udppreferencelimit=" + kerberosAuth.UDPConnectionLimit + ";" + if kerberosAuth.UDPConnectionLimit != 1 { + krb5DriverParams += fmt.Sprintf("krb5-udppreferencelimit=%d;", kerberosAuth.UDPConnectionLimit) } if kerberosAuth.EnableDNSLookupKDC != "" { diff --git a/pkg/tsdb/mssql/kerberos/kerberos_test.go b/pkg/tsdb/mssql/kerberos/kerberos_test.go new file mode 100644 index 00000000000..096fdfab43f --- /dev/null +++ b/pkg/tsdb/mssql/kerberos/kerberos_test.go @@ -0,0 +1,63 @@ +package kerberos + +import ( + "testing" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/stretchr/testify/require" +) + +func TestGetKerberosSettings(t *testing.T) { + t.Run("Should correctly parse settings", func(t *testing.T) { + settings := backend.DataSourceInstanceSettings{ + JSONData: []byte(`{"keytabFilePath":"keytab","credentialCache":"cache","credentialCacheLookupFile":"lookup","configFilePath":"config","UDPConnectionLimit":1,"enableDNSLookupKDC":"dns"}`), + } + + kerberosSettings, err := GetKerberosSettings(settings) + + require.NoError(t, err) + require.Equal(t, "keytab", kerberosSettings.KeytabFilePath) + require.Equal(t, "cache", kerberosSettings.CredentialCache) + require.Equal(t, "lookup", kerberosSettings.CredentialCacheLookupFile) + require.Equal(t, "config", kerberosSettings.ConfigFilePath) + require.Equal(t, 1, kerberosSettings.UDPConnectionLimit) + require.Equal(t, "dns", kerberosSettings.EnableDNSLookupKDC) + }) + + t.Run("Should correctly parse legacy UDPConnectionLimit", func(t *testing.T) { + settings := backend.DataSourceInstanceSettings{ + JSONData: []byte(`{"UDPConnectionLimit":"0"}`), + } + + kerberosSettings, err := GetKerberosSettings(settings) + + require.NoError(t, err) + require.Equal(t, 0, kerberosSettings.UDPConnectionLimit) + }) + + t.Run("Should return defaults", func(t *testing.T) { + settings := backend.DataSourceInstanceSettings{ + JSONData: []byte(`{}`), + } + + kerberosSettings, err := GetKerberosSettings(settings) + + require.NoError(t, err) + require.Equal(t, "", kerberosSettings.KeytabFilePath) + require.Equal(t, "", kerberosSettings.CredentialCache) + require.Equal(t, "", kerberosSettings.CredentialCacheLookupFile) + require.Equal(t, "", kerberosSettings.ConfigFilePath) + require.Equal(t, 1, kerberosSettings.UDPConnectionLimit) + require.Equal(t, "", kerberosSettings.EnableDNSLookupKDC) + }) + + t.Run("Will error if legacy UDPConnectionLimit can't be converted to number", func(t *testing.T) { + settings := backend.DataSourceInstanceSettings{ + JSONData: []byte(`{"UDPConnectionLimit":"test"}`), + } + + _, err := GetKerberosSettings(settings) + + require.Error(t, err) + }) +} diff --git a/pkg/tsdb/mssql/mssql_test.go b/pkg/tsdb/mssql/mssql_test.go index f424fb0016f..b3b7f795af8 100644 --- a/pkg/tsdb/mssql/mssql_test.go +++ b/pkg/tsdb/mssql/mssql_test.go @@ -1360,8 +1360,9 @@ func TestGenerateConnectionString(t *testing.T) { { desc: "Use Kerberos Credential Cache", kerberosCfg: kerberos.KerberosAuth{ - CredentialCache: "/tmp/krb5cc_1000", - ConfigFilePath: "/etc/krb5.conf", + CredentialCache: "/tmp/krb5cc_1000", + ConfigFilePath: "/etc/krb5.conf", + UDPConnectionLimit: 1, }, dataSource: sqleng.DataSourceInfo{ URL: "localhost", @@ -1377,6 +1378,7 @@ func TestGenerateConnectionString(t *testing.T) { kerberosCfg: kerberos.KerberosAuth{ CredentialCacheLookupFile: tmpFile, ConfigFilePath: "/etc/krb5.conf", + UDPConnectionLimit: 1, }, dataSource: sqleng.DataSourceInfo{ URL: "example.host", @@ -1391,8 +1393,9 @@ func TestGenerateConnectionString(t *testing.T) { { desc: "Use Kerberos Keytab", kerberosCfg: kerberos.KerberosAuth{ - KeytabFilePath: "/foo/bar.keytab", - ConfigFilePath: "/etc/krb5.conf", + KeytabFilePath: "/foo/bar.keytab", + ConfigFilePath: "/etc/krb5.conf", + UDPConnectionLimit: 1, }, dataSource: sqleng.DataSourceInfo{ URL: "localhost", @@ -1407,7 +1410,8 @@ func TestGenerateConnectionString(t *testing.T) { { desc: "Use Kerberos Username and Password", kerberosCfg: kerberos.KerberosAuth{ - ConfigFilePath: "/etc/krb5.conf", + ConfigFilePath: "/etc/krb5.conf", + UDPConnectionLimit: 1, }, dataSource: sqleng.DataSourceInfo{ URL: "localhost", @@ -1422,6 +1426,25 @@ func TestGenerateConnectionString(t *testing.T) { }, expConnStr: "authenticator=krb5;krb5-configfile=/etc/krb5.conf;server=localhost;database=database;user id=foo@test.lab;password=foo;", }, + { + desc: "Use non-default UDP connection limit", + kerberosCfg: kerberos.KerberosAuth{ + ConfigFilePath: "/etc/krb5.conf", + UDPConnectionLimit: 0, + }, + dataSource: sqleng.DataSourceInfo{ + URL: "localhost", + Database: "database", + User: "foo@test.lab", + DecryptedSecureJSONData: map[string]string{ + "password": "foo", + }, + JsonData: sqleng.JsonData{ + AuthenticationType: "Windows AD: Username + password", + }, + }, + expConnStr: "authenticator=krb5;krb5-configfile=/etc/krb5.conf;server=localhost;database=database;user id=foo@test.lab;password=foo;krb5-udppreferencelimit=0;", + }, { desc: "From URL w/ port",