package auth import ( "regexp" "strings" ) // dataCodeRe findet den AD-spezifischen data-Code im Text eines // LDAP-Result-Code-49-Fehlers, z. B. "... error, data 52e, v4563". var dataCodeRe = regexp.MustCompile(`(?i)\bdata\s+([0-9a-f]{3,4})\b`) // dataCodeReasons bildet AD-data-Codes auf Audit-Reasons ab. // 525 (kein solcher User) wird bewusst wie ein falsches Passwort behandelt, // damit die Fehlermeldung keine Benutzerexistenz verrät. var dataCodeReasons = map[string]string{ "525": ReasonInvalidCredentials, "52e": ReasonInvalidCredentials, "530": ReasonInvalidCredentials, // Anmeldung außerhalb erlaubter Zeiten "531": ReasonInvalidCredentials, // Anmeldung an dieser Station nicht erlaubt "532": ReasonPasswordExpired, "533": ReasonAccountDisabled, "701": ReasonAccountDisabled, // Konto abgelaufen "773": ReasonPasswordChangeRequired, "775": ReasonAccountLocked, } // ReasonFromLDAPError leitet den Audit-Reason aus einem LDAP-Bind-Fehler ab. // Fehler ohne erkennbaren data-Code gelten als Backend-Problem, nicht als // falsches Passwort — sonst würde ein DC-Ausfall als Fehlanmeldung gezählt // und den Benutzer über den Rate-Limiter aussperren. func ReasonFromLDAPError(err error) string { if err == nil { return "" } msg := err.Error() if m := dataCodeRe.FindStringSubmatch(msg); m != nil { if reason, ok := dataCodeReasons[strings.ToLower(m[1])]; ok { return reason } // data-Code vorhanden, aber unbekannt: es war eine echte Ablehnung. return ReasonInvalidCredentials } if strings.Contains(msg, "Result Code 49") || strings.Contains(msg, "Invalid Credentials") { return ReasonInvalidCredentials } return ReasonBackendUnavailable }