package auth import ( "context" "crypto/tls" "crypto/x509" "fmt" "net" "os" "strconv" "time" "github.com/go-ldap/ldap/v3" ) // conn ist der Ausschnitt der LDAP-Verbindung, den der Authenticator braucht. // Das Interface existiert, damit Tests ohne echten Verzeichnisdienst laufen. type conn interface { Bind(username, password string) error Search(req *ldap.SearchRequest) (*ldap.SearchResult, error) Close() error } // ldapConn adaptiert *ldap.Conn an conn (Close hat dort keine Fehlerrückgabe). type ldapConn struct{ *ldap.Conn } func (c ldapConn) Close() error { c.Conn.Close(); return nil } // tlsConfigFor baut die TLS-Konfiguration. Verifikation ist immer aktiv — // für LDAP gibt es bewusst keine Insecure-Option. func tlsConfigFor(server, caFile string) (*tls.Config, error) { cfg := &tls.Config{ServerName: server, MinVersion: tls.VersionTLS12} if caFile == "" { return cfg, nil } pem, err := os.ReadFile(caFile) if err != nil { return nil, fmt.Errorf("ad.ca_file %s: %w", caFile, err) } pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(pem) { return nil, fmt.Errorf("ad.ca_file %s enthält kein gültiges PEM-Zertifikat", caFile) } cfg.RootCAs = pool return cfg, nil } // realDialer erzeugt die Dial-Funktion für den Produktivbetrieb. func realDialer(port int, tlsMode, caFile string, timeout time.Duration) func(context.Context, string) (conn, error) { return func(ctx context.Context, server string) (conn, error) { tlsCfg, err := tlsConfigFor(server, caFile) if err != nil { return nil, err } addr := net.JoinHostPort(server, strconv.Itoa(port)) dialer := &net.Dialer{Timeout: timeout} var c *ldap.Conn if tlsMode == "starttls" { c, err = ldap.DialURL("ldap://"+addr, ldap.DialWithDialer(dialer)) if err != nil { return nil, fmt.Errorf("Verbindung zu %s: %w", addr, err) } if err := c.StartTLS(tlsCfg); err != nil { c.Close() return nil, fmt.Errorf("StartTLS zu %s: %w", addr, err) } } else { c, err = ldap.DialURL("ldaps://"+addr, ldap.DialWithDialer(dialer), ldap.DialWithTLSConfig(tlsCfg)) if err != nil { return nil, fmt.Errorf("LDAPS-Verbindung zu %s: %w", addr, err) } } c.SetTimeout(timeout) return ldapConn{c}, nil } }