LDAP: Allow specifying LDAP timeout (#48870)

* Allow specifying LDAP timeout

* Update docs/sources/auth/ldap.md

Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com>

* LDAP timeout: Add annotations; Make functions "private"

* Setting the default timeout if unspecified

* fix goimports lint issue

Co-authored-by: brendamuir <100768211+brendamuir@users.noreply.github.com>
Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
Co-authored-by: jguer <joao.guerreiro@grafana.com>
pull/51526/head^2
hannes-256 3 years ago committed by GitHub
parent cff763ca1d
commit 62b0a8bae6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      conf/ldap.toml
  2. 3
      docs/sources/setup-grafana/configure-security/configure-authentication/ldap.md
  3. 34
      pkg/services/ldap/ldap.go
  4. 10
      pkg/services/ldap/settings.go

@ -25,6 +25,9 @@ bind_dn = "cn=admin,dc=grafana,dc=org"
# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
bind_password = 'grafana'
# Timeout in seconds (applies to each host specified in the 'host' entry (space separated))
timeout = 10
# User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)"
search_filter = "(cn=%s)"

@ -72,6 +72,9 @@ bind_dn = "cn=admin,dc=grafana,dc=org"
# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
bind_password = "grafana"
# Timeout in seconds. Applies to each host specified in the 'host' entry (space separated).
timeout = 10
# User search filter, for example "(cn=%s)" or "(sAMAccountName=%s)" or "(uid=%s)"
# Allow login from email or username, example "(|(sAMAccountName=%s)(userPrincipalName=%s))"
search_filter = "(cn=%s)"

@ -10,6 +10,7 @@ import (
"net"
"strconv"
"strings"
"time"
"github.com/davecgh/go-spew/spew"
"gopkg.in/ldap.v3"
@ -114,6 +115,9 @@ func (server *Server) Dial() error {
return err
}
}
timeout := time.Duration(server.Config.Timeout) * time.Second
for _, host := range strings.Split(server.Config.Host, " ") {
// Remove any square brackets enclosing IPv6 addresses, a format we support for backwards compatibility
host = strings.TrimSuffix(strings.TrimPrefix(host, "["), "]")
@ -128,17 +132,17 @@ func (server *Server) Dial() error {
tlsCfg.Certificates = append(tlsCfg.Certificates, clientCert)
}
if server.Config.StartTLS {
server.Connection, err = ldap.Dial("tcp", address)
server.Connection, err = dialWithTimeout("tcp", address, timeout)
if err == nil {
if err = server.Connection.StartTLS(tlsCfg); err == nil {
return nil
}
}
} else {
server.Connection, err = ldap.DialTLS("tcp", address, tlsCfg)
server.Connection, err = dialTLSWithTimeout("tcp", address, tlsCfg, timeout)
}
} else {
server.Connection, err = ldap.Dial("tcp", address)
server.Connection, err = dialWithTimeout("tcp", address, timeout)
}
if err == nil {
@ -148,6 +152,30 @@ func (server *Server) Dial() error {
return err
}
// dialWithTimeout applies the specified timeout
// and connects to the given address on the given network using net.Dial
func dialWithTimeout(network, addr string, timeout time.Duration) (*ldap.Conn, error) {
c, err := net.DialTimeout(network, addr, timeout)
if err != nil {
return nil, err
}
conn := ldap.NewConn(c, false)
conn.Start()
return conn, nil
}
// dialTLSWithTimeout applies the specified timeout
// connects to the given address on the given network using tls.Dial
func dialTLSWithTimeout(network, addr string, config *tls.Config, timeout time.Duration) (*ldap.Conn, error) {
c, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, network, addr, config)
if err != nil {
return nil, err
}
conn := ldap.NewConn(c, true)
conn.Start()
return conn, nil
}
// Close closes the LDAP connection
// Dial() sets the connection with the server for this Struct. Therefore, we require a
// call to Dial() before being able to execute this function.

@ -12,6 +12,8 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
const defaultTimeout = 10
// Config holds list of connections to LDAP
type Config struct {
Servers []*ServerConfig `toml:"servers"`
@ -29,6 +31,7 @@ type ServerConfig struct {
ClientKey string `toml:"client_key"`
BindDN string `toml:"bind_dn"`
BindPassword string `toml:"bind_password"`
Timeout int `toml:"timeout"`
Attr AttributeMap `toml:"attributes"`
SearchFilter string `toml:"search_filter"`
@ -140,8 +143,8 @@ func readConfig(configFile string) (*Config, error) {
return nil, fmt.Errorf("LDAP enabled but no LDAP servers defined in config file")
}
// set default org id
for _, server := range result.Servers {
// set default org id
err = assertNotEmptyCfg(server.SearchFilter, "search_filter")
if err != nil {
return nil, fmt.Errorf("%v: %w", "Failed to validate SearchFilter section", err)
@ -160,6 +163,11 @@ func readConfig(configFile string) (*Config, error) {
groupMap.OrgId = 1
}
}
// set default timeout if unspecified
if server.Timeout == 0 {
server.Timeout = defaultTimeout
}
}
return result, nil

Loading…
Cancel
Save