Ctrl K
ComunidadGuías…

internal/server/oidc_domains_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// 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")
	}
}