checker-ldap/checker/rule.go

99 lines
2.4 KiB
Go

package checker
import (
"context"
"fmt"
sdk "git.happydns.org/checker-sdk-go/checker"
)
func Rule() sdk.CheckRule {
return &ldapRule{}
}
type ldapRule struct{}
func (r *ldapRule) Name() string {
return "ldap_server"
}
func (r *ldapRule) Description() string {
return "Checks discovery, transport security (StartTLS / LDAPS), RootDSE, SASL posture and (optionally) bind credentials of an LDAP directory."
}
func (r *ldapRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts sdk.CheckerOptions) []sdk.CheckState {
var data LDAPData
if err := obs.Get(ctx, ObservationKeyLDAP, &data); err != nil {
return []sdk.CheckState{{
Status: sdk.StatusError,
Message: fmt.Sprintf("failed to load LDAP observation: %v", err),
Code: "ldap.observation_error",
}}
}
issues := append([]Issue(nil), data.Issues...)
// Fold related TLS observations (from a downstream TLS checker, if any)
// into the LDAP issue list so cert/chain problems show up on the LDAP
// service page without requiring a separate glance at the TLS checker.
related, _ := obs.GetRelated(ctx, TLSRelatedKey)
issues = append(issues, tlsIssuesFromRelated(related)...)
withIssue := make(map[string]bool, len(issues))
out := make([]sdk.CheckState, 0, len(issues)+len(data.Endpoints))
for _, is := range issues {
st := sdk.CheckState{
Status: severityToStatus(is.Severity),
Message: is.Message,
Code: is.Code,
Subject: is.Endpoint,
}
if is.Fix != "" {
st.Meta = map[string]any{"fix": is.Fix}
}
out = append(out, st)
if is.Endpoint != "" {
withIssue[is.Endpoint] = true
}
}
for _, ep := range data.Endpoints {
if withIssue[ep.Address] || !ep.TCPConnected {
continue
}
out = append(out, sdk.CheckState{
Status: sdk.StatusOK,
Message: fmt.Sprintf("%s endpoint operational (TLS=%v)", ep.Mode, ep.TLSEstablished),
Code: "ldap.ok",
Subject: ep.Address,
Meta: map[string]any{
"mode": string(ep.Mode),
"tls_established": ep.TLSEstablished,
"rootdse_read": ep.RootDSERead,
},
})
}
if len(out) == 0 {
return []sdk.CheckState{{
Status: sdk.StatusInfo,
Message: "no LDAP endpoint discovered",
Code: "ldap.nothing_to_evaluate",
}}
}
return out
}
func severityToStatus(sev string) sdk.Status {
switch sev {
case SeverityCrit:
return sdk.StatusCrit
case SeverityWarn:
return sdk.StatusWarn
case SeverityInfo:
return sdk.StatusInfo
default:
return sdk.StatusOK
}
}