1
0
Fork 0
telegraf/plugins/inputs/ldap/ldap.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

179 lines
3.7 KiB
Go

//go:generate ../../../tools/config_includer/generator
//go:generate ../../../tools/readme_config_includer/generator
package ldap
import (
"crypto/tls"
_ "embed"
"fmt"
"net/url"
"time"
"github.com/go-ldap/ldap/v3"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
common_tls "github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
type LDAP struct {
Server string `toml:"server"`
Dialect string `toml:"dialect"`
BindDn string `toml:"bind_dn"`
BindPassword config.Secret `toml:"bind_password"`
ReverseFieldNames bool `toml:"reverse_field_names"`
common_tls.ClientConfig
tlsCfg *tls.Config
requests []request
mode string
host string
port string
}
type request struct {
query *ldap.SearchRequest
convert func(*ldap.SearchResult, time.Time) []telegraf.Metric
}
func (*LDAP) SampleConfig() string {
return sampleConfig
}
func (l *LDAP) Init() error {
if l.Server == "" {
l.Server = "ldap://localhost:389"
}
u, err := url.Parse(l.Server)
if err != nil {
return fmt.Errorf("parsing server failed: %w", err)
}
// Verify the server setting and set the defaults
var tlsEnable bool
switch u.Scheme {
case "ldap":
if u.Port() == "" {
u.Host = u.Host + ":389"
}
tlsEnable = false
case "starttls":
if u.Port() == "" {
u.Host = u.Host + ":389"
}
tlsEnable = true
case "ldaps":
if u.Port() == "" {
u.Host = u.Host + ":636"
}
tlsEnable = true
default:
return fmt.Errorf("invalid scheme: %q", u.Scheme)
}
l.mode = u.Scheme
l.Server = u.Host
l.host, l.port = u.Hostname(), u.Port()
// Force TLS depending on the selected mode
l.ClientConfig.Enable = &tlsEnable
// Setup TLS configuration
tlsCfg, err := l.ClientConfig.TLSConfig()
if err != nil {
return fmt.Errorf("creating TLS config failed: %w", err)
}
l.tlsCfg = tlsCfg
// Initialize the search request(s)
switch l.Dialect {
case "", "openldap":
l.requests = l.newOpenLDAPConfig()
case "389ds":
l.requests = l.new389dsConfig()
default:
return fmt.Errorf("invalid dialect %q", l.Dialect)
}
return nil
}
func (l *LDAP) Gather(acc telegraf.Accumulator) error {
// Connect
conn, err := l.connect()
if err != nil {
return fmt.Errorf("connection failed: %w", err)
}
defer conn.Close()
// Query the server
for _, req := range l.requests {
now := time.Now()
result, err := conn.Search(req.query)
if err != nil {
acc.AddError(err)
continue
}
// Collect metrics
for _, m := range req.convert(result, now) {
acc.AddMetric(m)
}
}
return nil
}
func (l *LDAP) connect() (*ldap.Conn, error) {
var conn *ldap.Conn
switch l.mode {
case "ldap":
var err error
conn, err = ldap.DialURL("ldap://" + l.Server)
if err != nil {
return nil, err
}
case "ldaps":
var err error
conn, err = ldap.DialURL("ldaps://"+l.Server, ldap.DialWithTLSConfig(l.tlsCfg))
if err != nil {
return nil, err
}
case "starttls":
var err error
conn, err = ldap.DialURL("ldap://" + l.Server)
if err != nil {
return nil, err
}
if err := conn.StartTLS(l.tlsCfg); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("invalid tls_mode: %s", l.mode)
}
if l.BindDn == "" && l.BindPassword.Empty() {
return conn, nil
}
// Bind username and password
passwd, err := l.BindPassword.Get()
if err != nil {
return nil, fmt.Errorf("getting password failed: %w", err)
}
defer passwd.Destroy()
if err := conn.Bind(l.BindDn, passwd.String()); err != nil {
return nil, fmt.Errorf("binding credentials failed: %w", err)
}
return conn, nil
}
func init() {
inputs.Add("ldap", func() telegraf.Input { return &LDAP{} })
}