forked from grafana/grafana
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathkerberos.go
106 lines (91 loc) · 3.69 KB
/
kerberos.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package kerberos
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
)
type KerberosLookup struct {
User string `json:"user"`
DBName string `json:"database"`
Address string `json:"address"`
CredentialCacheFilename string `json:"credentialCache"`
}
type KerberosAuth struct {
KeytabFilePath string
CredentialCache string
CredentialCacheLookupFile string
ConfigFilePath string
UDPConnectionLimit string
EnableDNSLookupKDC string
}
func GetKerberosSettings(settings backend.DataSourceInstanceSettings) (kerberosAuth KerberosAuth, err error) {
err = json.Unmarshal(settings.JSONData, &kerberosAuth)
return kerberosAuth, err
}
func Krb5ParseAuthCredentials(host string, port string, db string, user string, pass string, kerberosAuth KerberosAuth) string {
//params for driver conn str
//More details: https://github.com/microsoft/go-mssqldb#kerberos-active-directory-authentication-outside-windows
krb5CCLookupFile := kerberosAuth.CredentialCacheLookupFile
krb5CacheCredsFile := kerberosAuth.CredentialCache
// if there is a lookup file specified, use it to find the correct credential cache file and overwrite var
// getCredentialCacheFromLookup implementation taken from mysql kerberos solution - https://github.com/grafana/mysql/commit/b5e73c8d536150c054d310123643683d3b18f0da
if krb5CCLookupFile != "" {
krb5CacheCredsFile = getCredentialCacheFromLookup(krb5CCLookupFile, host, port, db, user)
if krb5CacheCredsFile == "" {
logger.Error("No valid credential cache file found in lookup.")
return ""
}
}
krb5DriverParams := fmt.Sprintf("authenticator=krb5;krb5-configfile=%s;", kerberosAuth.ConfigFilePath)
// There are 3 main connection types:
// - credentials cache
// - user, realm, keytab
// - realm, user, pass
if krb5CacheCredsFile != "" {
krb5DriverParams += fmt.Sprintf("server=%s;database=%s;krb5-credcachefile=%s;", host, db, krb5CacheCredsFile)
} else if kerberosAuth.KeytabFilePath != "" {
krb5DriverParams += fmt.Sprintf("server=%s;database=%s;user id=%s;krb5-keytabfile=%s;", host, db, user, kerberosAuth.KeytabFilePath)
} else if kerberosAuth.KeytabFilePath == "" {
krb5DriverParams += fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;", host, db, user, pass)
} else {
logger.Error("invalid kerberos configuration")
return ""
}
if kerberosAuth.UDPConnectionLimit != "" {
krb5DriverParams += "krb5-udppreferencelimit=" + kerberosAuth.UDPConnectionLimit + ";"
}
if kerberosAuth.EnableDNSLookupKDC != "" {
krb5DriverParams += "krb5-dnslookupkdc=" + kerberosAuth.EnableDNSLookupKDC + ";"
}
logger.Info(fmt.Sprintf("final krb connstr: %s", krb5DriverParams))
return krb5DriverParams
}
func getCredentialCacheFromLookup(lookupFile string, host string, port string, dbName string, user string) string {
logger.Info(fmt.Sprintf("reading credential cache lookup: %s", lookupFile))
content, err := os.ReadFile(filepath.Clean(lookupFile))
if err != nil {
logger.Error(fmt.Sprintf("error reading: %s, %v", lookupFile, err))
return ""
}
var lookups []KerberosLookup
err = json.Unmarshal(content, &lookups)
if err != nil {
logger.Error(fmt.Sprintf("error parsing: %s, %v", lookupFile, err))
return ""
}
// find cache file
for _, item := range lookups {
if port == "0" {
item.Address = host + ":0"
}
if item.Address == host+":"+port && item.DBName == dbName && item.User == user {
logger.Info(fmt.Sprintf("matched: %+v", item))
return item.CredentialCacheFilename
}
}
logger.Error(fmt.Sprintf("no match found for %s", host+":"+port))
return ""
}