package cli import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" "net/http" "net/http/httptest" "net/netip" "testing" ) func TestTheMirrorAPIAnswersOnlyThisMachineUnlessTold(t *testing.T) { ok := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {}) call := func(h http.Handler, from string) int { r := httptest.NewRequest("DELETE", "/v1/models/m/v", nil) r.RemoteAddr = from + ":5000" w := httptest.NewRecorder() h.ServeHTTP(w, r) return w.Code } cp := []netip.Prefix{netip.MustParsePrefix("10.0.0.140/32")} // Nothing allowed and no TLS used to mean anyone: every node could delete // models. if got := call(apiGate(false, nil, ok), "10.0.0.141"); got != http.StatusForbidden { t.Errorf("a node reached an unconfigured mirror API: %d", got) } if got := call(apiGate(false, nil, ok), "127.0.0.1"); got != http.StatusOK { t.Errorf("the mirror's own machine was refused: %d", got) } if got := call(apiGate(false, cp, ok), "10.0.0.140"); got != http.StatusOK { t.Errorf("the allowed control plane was refused: %d", got) } if got := call(apiGate(false, cp, ok), "10.0.0.141"); got != http.StatusForbidden { t.Errorf("a node outside the allowlist got through: %d", got) } // With mutual TLS the certificate decides. if got := call(apiGate(true, nil, ok), "10.0.0.141"); got != http.StatusOK { t.Errorf("mTLS without an allowlist refused a client: %d", got) } } func TestOnlyANamedCertificateManagesTheMirror(t *testing.T) { ok := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {}) with := func(cn string) *http.Request { r := httptest.NewRequest("GET", "/", nil) if cn != "" { r.TLS = &tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: cn}}}}} } return r } h := onlyClients([]string{"control-plane"}, ok) for cn, want := range map[string]int{"control-plane": 200, "node01": 403, "": 403} { w := httptest.NewRecorder() h.ServeHTTP(w, with(cn)) if w.Code != want { t.Errorf("%q: %d, expected %d", cn, w.Code, want) } } w := httptest.NewRecorder() onlyClients(nil, ok).ServeHTTP(w, with("node01")) if w.Code != 200 { t.Error("no names given narrowed it anyway") } }