internal/server/oidc_domains_test.go
Rama main · réplica de lectura del repositorio original.
// SPDX-License-Identifier: Apache-2.0
package server
import (
"reflect"
"testing"
)
// v2.67.0: SSO sign-in can be restricted to named email domains.
//
// The motivating case is a public identity provider. With a private IdP,
// "anyone my provider authenticates" means your own staff; point CaddyUI at
// Google and it means every account in the world, which with auto-create on
// is a CaddyUI account for anyone who finds the login page. These tests pin
// down the refusals rather than just the happy path.
func TestAllowedDomainsParsing(t *testing.T) {
got := parseOIDCAllowedDomains("Example.com\n@example.org, \n EXAMPLE.NET \n# a comment\n\n")
want := []string{"example.com", "example.org", "example.net"}
if !reflect.DeepEqual(got, want) {
t.Errorf("parsed = %#v, want %#v — lowercased, '@' tolerated, comments and blanks dropped", got, want)
}
}
// An empty list must not restrict anything, or upgrading would lock out every
// existing SSO user.
func TestEmptyListAllowsEveryone(t *testing.T) {
cfg := oidcConfig{}
for _, e := range []string{"anyone@gmail.com", "staff@example.com", "odd@sub.example.co.uk"} {
if !cfg.emailDomainAllowed(e) {
t.Errorf("%s was refused with no domain list configured", e)
}
}
}
func TestOnlyListedDomainsAreAdmitted(t *testing.T) {
cfg := oidcConfig{AllowedDomains: parseOIDCAllowedDomains("example.com, example.org")}
for e, want := range map[string]bool{
"staff@example.com": true,
"other@example.org": true,
"Staff@Example.Com": true, // address casing must not matter
"attacker@gmail.com": false, // the whole point
"staff@notexample.com": false,
"staff@example.com.evil": false, // suffix games must not pass
} {
if got := cfg.emailDomainAllowed(e); got != want {
t.Errorf("emailDomainAllowed(%q) = %v, want %v", e, got, want)
}
}
}
// Listing a domain must not silently admit its subdomains — mail.example.com
// can be a different tenant entirely.
func TestSubdomainsAreNotImplied(t *testing.T) {
cfg := oidcConfig{AllowedDomains: []string{"example.com"}}
if cfg.emailDomainAllowed("user@mail.example.com") {
t.Error("a subdomain was admitted by listing the parent domain")
}
cfg2 := oidcConfig{AllowedDomains: []string{"example.com", "mail.example.com"}}
if !cfg2.emailDomainAllowed("user@mail.example.com") {
t.Error("an explicitly listed subdomain was refused")
}
}
// A malformed address must fail closed rather than slipping through.
func TestMalformedAddressesAreRefused(t *testing.T) {
cfg := oidcConfig{AllowedDomains: []string{"example.com"}}
for _, e := range []string{"", "no-at-sign", "trailing@", "@example.com "} {
if cfg.emailDomainAllowed(e) {
t.Errorf("malformed address %q was admitted", e)
}
}
// "@example.com" with no local part has a valid domain; it is the
// provider's job to not assert that, and ours not to crash on it.
_ = cfg.emailDomainAllowed("@example.com")
}
// An address whose domain differs only by case from the configured one must
// still match — IdPs are inconsistent about casing.
func TestConfiguredDomainCasingIsNormalised(t *testing.T) {
cfg := oidcConfig{AllowedDomains: parseOIDCAllowedDomains("ExAmPlE.CoM")}
if !cfg.emailDomainAllowed("user@example.com") {
t.Error("configured domain casing should be normalised at parse time")
}
}