package checker import ( sdk "git.happydns.org/checker-sdk-go/checker" tlsct "git.happydns.org/checker-tls/contract" ) func Provider() sdk.ObservationProvider { return &ldapProvider{} } type ldapProvider struct{} func (p *ldapProvider) Key() sdk.ObservationKey { return ObservationKeyLDAP } // DiscoverEntries implements sdk.DiscoveryPublisher. // // It publishes TLS endpoint contract entries for every SRV target we found, // so a downstream TLS checker can verify the certificate chain / SAN / // expiry on each one without re-doing the SRV lookup. The LDAP checker // itself only confirms a TLS session can be established -- certificate // posture lives in the TLS checker. // // SNI is set to the bare domain, which is usually the hostname clients // connect to. On _ldaps._tcp we emit direct-TLS endpoints (STARTTLS=""). // On _ldap._tcp we emit STARTTLS="ldap" so the TLS checker performs an // RFC 2830 extended-op upgrade before the handshake. RequireSTARTTLS is // set to true on 389: a misconfigured server that drops StartTLS must // show up as a CRIT on the TLS side, not a WARN. func (p *ldapProvider) DiscoverEntries(data any) ([]sdk.DiscoveryEntry, error) { d, ok := data.(*LDAPData) if !ok || d == nil { return nil, nil } var out []sdk.DiscoveryEntry emit := func(recs []SRVRecord, starttls string, require bool) error { for _, r := range recs { ep := tlsct.TLSEndpoint{ Host: r.Target, Port: r.Port, SNI: d.Domain, STARTTLS: starttls, RequireSTARTTLS: require, } entry, err := tlsct.NewEntry(ep) if err != nil { return err } out = append(out, entry) } return nil } if err := emit(d.SRV.LDAP, "ldap", true); err != nil { return nil, err } if err := emit(d.SRV.LDAPS, "", false); err != nil { return nil, err } return out, nil }