mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 12:22:15 +08:00
132 lines
4.3 KiB
Go
132 lines
4.3 KiB
Go
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"
|
|
)
|
|
|
|
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 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
|
|
}
|
|
|
|
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 != 1 {
|
|
krb5DriverParams += fmt.Sprintf("krb5-udppreferencelimit=%d;", kerberosAuth.UDPConnectionLimit)
|
|
}
|
|
|
|
if kerberosAuth.EnableDNSLookupKDC != "" {
|
|
krb5DriverParams += "krb5-dnslookupkdc=" + kerberosAuth.EnableDNSLookupKDC + ";"
|
|
}
|
|
|
|
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 ""
|
|
}
|