feat(auth): AD-Authenticator mit Zwei-Schritt-Bind, DC-Failover und verschachtelter Gruppenprüfung
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
This commit is contained in:
parent
2eb69bdcfe
commit
99ee8758cc
8 changed files with 908 additions and 1 deletions
47
internal/auth/addata.go
Normal file
47
internal/auth/addata.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue