package config import ( "strings" "testing" ) func validCfg(t *testing.T) *Config { t.Helper() cfg, err := Parse(strings.NewReader(minimalYAML)) if err != nil { t.Fatal(err) } return cfg } func TestBaseDNFromDomain(t *testing.T) { cases := map[string]string{ "firma.local": "DC=firma,DC=local", "ad.firma.example": "DC=ad,DC=firma,DC=example", "FIRMA.LOCAL": "DC=FIRMA,DC=LOCAL", } for in, want := range cases { got, err := BaseDNFromDomain(in) if err != nil { t.Errorf("BaseDNFromDomain(%q): %v", in, err) continue } if got != want { t.Errorf("BaseDNFromDomain(%q) = %q, want %q", in, got, want) } } if _, err := BaseDNFromDomain("firmalocal"); err == nil { t.Error("Domain ohne Punkt muss abgelehnt werden") } if _, err := BaseDNFromDomain(""); err == nil { t.Error("leere Domain muss abgelehnt werden") } } func TestEffectiveBaseDNPrefersOverride(t *testing.T) { cfg := validCfg(t) cfg.AD.BaseDN = "OU=Users,DC=firma,DC=local" if got := cfg.EffectiveBaseDN(); got != "OU=Users,DC=firma,DC=local" { t.Errorf("Override muss gewinnen, got %q", got) } cfg.AD.BaseDN = "" if got := cfg.EffectiveBaseDN(); got != "DC=firma,DC=local" { t.Errorf("Ableitung falsch, got %q", got) } } func TestValidateAcceptsMinimalConfig(t *testing.T) { if err := validCfg(t).Validate(); err != nil { t.Fatalf("minimale Config sollte gültig sein: %v", err) } } func TestValidateRejectsIPServers(t *testing.T) { cfg := validCfg(t) cfg.AD.Servers = []string{"10.1.1.10"} err := cfg.Validate() if err == nil || !strings.Contains(err.Error(), "10.1.1.10") { t.Fatalf("IP-Adresse als DC muss abgelehnt werden, got: %v", err) } } func TestValidateRejectsHTTPOPNsense(t *testing.T) { cfg := validCfg(t) cfg.OPNsense.URL = "http://fw01.firma.local" if err := cfg.Validate(); err == nil { t.Fatal("http:// muss abgelehnt werden") } } func TestValidateRejectsPatternAndRegexTogether(t *testing.T) { cfg := validCfg(t) cfg.Matching.CNRegex = "^.*$" if err := cfg.Validate(); err == nil { t.Fatal("cn_pattern und cn_regex gleichzeitig muss abgelehnt werden") } } func TestValidateRejectsBadRegex(t *testing.T) { cfg := validCfg(t) cfg.Matching.CNPattern = "" cfg.Matching.CNRegex = "([unbalanced" if err := cfg.Validate(); err == nil { t.Fatal("unkompilierbare Regex muss abgelehnt werden") } } func TestValidateCollectsMultipleErrors(t *testing.T) { cfg := validCfg(t) cfg.Portal.TLSCert = "" cfg.Portal.TLSKey = "" cfg.AD.VPNGroup = "" err := cfg.Validate() if err == nil { t.Fatal("mehrere Fehler erwartet") } for _, want := range []string{"tls_cert", "tls_key", "vpn_group"} { if !strings.Contains(err.Error(), want) { t.Errorf("Sammelfehler muss %q nennen, got: %v", want, err) } } } func TestMinTLSVersionDefaultsTo12(t *testing.T) { cfg := validCfg(t) if cfg.AD.MinTLSVersion != "1.2" { t.Errorf("MinTLSVersion = %q, want Default 1.2", cfg.AD.MinTLSVersion) } if err := cfg.Validate(); err != nil { t.Fatalf("Default muss gültig sein: %v", err) } } func TestValidateAcceptsLegacyMinTLSVersions(t *testing.T) { // Alte Domain Controller (z. B. Windows Server 2012 R2 mit abgeschaltetem // TLS 1.2) müssen erreichbar bleiben. for _, v := range []string{"1.0", "1.1", "1.2", "1.3"} { cfg := validCfg(t) cfg.AD.MinTLSVersion = v if err := cfg.Validate(); err != nil { t.Errorf("min_tls_version %q muss zulässig sein: %v", v, err) } } } func TestValidateRejectsUnknownMinTLSVersion(t *testing.T) { for _, v := range []string{"1.4", "tls1.2", "TLSv1", "", "12"} { cfg := validCfg(t) cfg.AD.MinTLSVersion = v if err := cfg.Validate(); err == nil { t.Errorf("min_tls_version %q muss abgelehnt werden", v) } } } func TestMinTLSVersionIsWeakBelow12(t *testing.T) { cfg := validCfg(t) for v, wantWeak := range map[string]bool{"1.0": true, "1.1": true, "1.2": false, "1.3": false} { cfg.AD.MinTLSVersion = v if got := cfg.AD.MinTLSVersionIsWeak(); got != wantWeak { t.Errorf("MinTLSVersionIsWeak() für %q = %v, want %v", v, got, wantWeak) } } } func TestValidateRejectsPatternWithoutPlaceholder(t *testing.T) { cfg := validCfg(t) cfg.Matching.CNPattern = "fester-cn" if err := cfg.Validate(); err == nil { t.Fatal("cn_pattern ohne {username} muss abgelehnt werden") } }