mirror of
https://github.com/grafana/grafana.git
synced 2025-01-27 16:57:14 -06:00
Merge branch 'ldap-improvements' of https://github.com/abligh/grafana into abligh-ldap-improvements
This commit is contained in:
commit
38bd0d1aec
@ -2,7 +2,7 @@
|
||||
verbose_logging = false
|
||||
|
||||
[[servers]]
|
||||
# Ldap server host
|
||||
# Ldap server host (specify multiple hosts space separated)
|
||||
host = "127.0.0.1"
|
||||
# Default port is 389 or 636 if use_ssl = true
|
||||
port = 389
|
||||
@ -10,17 +10,40 @@ port = 389
|
||||
use_ssl = false
|
||||
# set to true if you want to skip ssl cert validation
|
||||
ssl_skip_verify = false
|
||||
# set to the path to your root CA certificate or leave unset to use system defaults
|
||||
# root_ca_cert = /path/to/certificate.crt
|
||||
|
||||
# Search user bind dn
|
||||
bind_dn = "cn=admin,dc=grafana,dc=org"
|
||||
# Search user bind password
|
||||
bind_password = 'grafana'
|
||||
|
||||
# Schema's supporting memberOf
|
||||
|
||||
# Search filter, for example "(cn=%s)" or "(sAMAccountName=%s)"
|
||||
search_filter = "(cn=%s)"
|
||||
# An array of base dns to search through
|
||||
search_base_dns = ["dc=grafana,dc=org"]
|
||||
|
||||
# Uncomment this section (and comment out the previous 2 entries) to use POSIX schema.
|
||||
# In POSIX LDAP schemas, querying the people 'ou' gives you entries that do not have a
|
||||
# memberOf attribute, so a secondary query must be made for groups. This is done by
|
||||
# enabling group_search_filter below. You must also set
|
||||
# member_of = "cn"
|
||||
# in [servers.attributes] below.
|
||||
#
|
||||
# Search filter, used to retrieve the user
|
||||
# search_filter = "(uid=%s)"
|
||||
#
|
||||
# An array of the base DNs to search through for users. Typically uses ou=people.
|
||||
# search_base_dns = ["ou=people,dc=grafana,dc=org"]
|
||||
#
|
||||
# Group search filter, to retrieve the groups of which the user is a member
|
||||
# group_search_filter = "(&(objectClass=posixGroup)(memberUid=%s))"
|
||||
#
|
||||
# An array of the base DNs to search through for groups. Typically uses ou=groups
|
||||
# group_search_base_dns = ["ou=groups,dc=grafana,dc=org"]
|
||||
|
||||
# Specify names of the ldap attributes your ldap uses
|
||||
[servers.attributes]
|
||||
name = "givenName"
|
||||
|
@ -2,8 +2,10 @@ package login
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
@ -24,18 +26,37 @@ func NewLdapAuthenticator(server *LdapServerConf) *ldapAuther {
|
||||
}
|
||||
|
||||
func (a *ldapAuther) Dial() error {
|
||||
address := fmt.Sprintf("%s:%d", a.server.Host, a.server.Port)
|
||||
var err error
|
||||
if a.server.UseSSL {
|
||||
tlsCfg := &tls.Config{
|
||||
InsecureSkipVerify: a.server.SkipVerifySSL,
|
||||
ServerName: a.server.Host,
|
||||
var certPool *x509.CertPool
|
||||
if a.server.RootCACert != "" {
|
||||
certPool := x509.NewCertPool()
|
||||
for _, caCertFile := range strings.Split(a.server.RootCACert, " ") {
|
||||
if pem, err := ioutil.ReadFile(caCertFile); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if !certPool.AppendCertsFromPEM(pem) {
|
||||
return errors.New("Failed to append CA certficate " + caCertFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
a.conn, err = ldap.DialTLS("tcp", address, tlsCfg)
|
||||
} else {
|
||||
a.conn, err = ldap.Dial("tcp", address)
|
||||
}
|
||||
for _, host := range strings.Split(a.server.Host, " ") {
|
||||
address := fmt.Sprintf("%s:%d", host, a.server.Port)
|
||||
if a.server.UseSSL {
|
||||
tlsCfg := &tls.Config{
|
||||
InsecureSkipVerify: a.server.SkipVerifySSL,
|
||||
ServerName: host,
|
||||
RootCAs: certPool,
|
||||
}
|
||||
a.conn, err = ldap.DialTLS("tcp", address, tlsCfg)
|
||||
} else {
|
||||
a.conn, err = ldap.Dial("tcp", address)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@ -290,18 +311,51 @@ func (a *ldapAuther) searchForUser(username string) (*ldapUserInfo, error) {
|
||||
return nil, errors.New("Ldap search matched more than one entry, please review your filter setting")
|
||||
}
|
||||
|
||||
var memberOf []string
|
||||
if a.server.GroupSearchFilter == "" {
|
||||
memberOf = getLdapAttrArray(a.server.Attr.MemberOf, searchResult)
|
||||
} else {
|
||||
// If we are using a POSIX LDAP schema it won't support memberOf, so we manually search the groups
|
||||
var groupSearchResult *ldap.SearchResult
|
||||
for _, groupSearchBase := range a.server.GroupSearchBaseDNs {
|
||||
filter := strings.Replace(a.server.GroupSearchFilter, "%s", username, -1)
|
||||
groupSearchReq := ldap.SearchRequest{
|
||||
BaseDN: groupSearchBase,
|
||||
Scope: ldap.ScopeWholeSubtree,
|
||||
DerefAliases: ldap.NeverDerefAliases,
|
||||
Attributes: []string{
|
||||
// Here MemberOf would be the thing that identifies the group, which is normally 'cn'
|
||||
a.server.Attr.MemberOf,
|
||||
},
|
||||
Filter: filter,
|
||||
}
|
||||
|
||||
groupSearchResult, err = a.conn.Search(&groupSearchReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(groupSearchResult.Entries) > 0 {
|
||||
for i := range groupSearchResult.Entries {
|
||||
memberOf = append(memberOf, getLdapAttrN(a.server.Attr.MemberOf, groupSearchResult, i))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &ldapUserInfo{
|
||||
DN: searchResult.Entries[0].DN,
|
||||
LastName: getLdapAttr(a.server.Attr.Surname, searchResult),
|
||||
FirstName: getLdapAttr(a.server.Attr.Name, searchResult),
|
||||
Username: getLdapAttr(a.server.Attr.Username, searchResult),
|
||||
Email: getLdapAttr(a.server.Attr.Email, searchResult),
|
||||
MemberOf: getLdapAttrArray(a.server.Attr.MemberOf, searchResult),
|
||||
MemberOf: memberOf,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getLdapAttr(name string, result *ldap.SearchResult) string {
|
||||
for _, attr := range result.Entries[0].Attributes {
|
||||
func getLdapAttrN(name string, result *ldap.SearchResult, n int) string {
|
||||
for _, attr := range result.Entries[n].Attributes {
|
||||
if attr.Name == name {
|
||||
if len(attr.Values) > 0 {
|
||||
return attr.Values[0]
|
||||
@ -311,6 +365,10 @@ func getLdapAttr(name string, result *ldap.SearchResult) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func getLdapAttr(name string, result *ldap.SearchResult) string {
|
||||
return getLdapAttrN(name, result, 0)
|
||||
}
|
||||
|
||||
func getLdapAttrArray(name string, result *ldap.SearchResult) []string {
|
||||
for _, attr := range result.Entries[0].Attributes {
|
||||
if attr.Name == name {
|
||||
|
@ -19,6 +19,7 @@ type LdapServerConf struct {
|
||||
Port int `toml:"port"`
|
||||
UseSSL bool `toml:"use_ssl"`
|
||||
SkipVerifySSL bool `toml:"ssl_skip_verify"`
|
||||
RootCACert string `toml:"root_ca_cert"`
|
||||
BindDN string `toml:"bind_dn"`
|
||||
BindPassword string `toml:"bind_password"`
|
||||
Attr LdapAttributeMap `toml:"attributes"`
|
||||
@ -26,6 +27,9 @@ type LdapServerConf struct {
|
||||
SearchFilter string `toml:"search_filter"`
|
||||
SearchBaseDNs []string `toml:"search_base_dns"`
|
||||
|
||||
GroupSearchFilter string `toml:"group_search_filter"`
|
||||
GroupSearchBaseDNs []string `toml:"group_search_base_dns"`
|
||||
|
||||
LdapGroups []*LdapGroupToOrgRole `toml:"group_mappings"`
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user