route-proxy: a policy refusal is also not-my-token #67
@@ -7,6 +7,8 @@ package main
|
|||||||
// three behaviours tokenOrRoute exists for.
|
// three behaviours tokenOrRoute exists for.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
@@ -73,6 +75,27 @@ func TestASecondAuthorityIsProbedBeforeRouting(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAnAuthorityWhosePolicyRefusesTheNameIsProbedPast(t *testing.T) {
|
||||||
|
// autocert checks the host policy before the token and answers 403 — the internal authority
|
||||||
|
// does this for every public name. A policy refusal is as much "not mine" as a missing token:
|
||||||
|
// the request must still reach plain routing, where the workload's own ACME client answers.
|
||||||
|
refusing := &autocert.Manager{
|
||||||
|
Prompt: autocert.AcceptTOS,
|
||||||
|
Cache: autocert.DirCache(t.TempDir()),
|
||||||
|
HostPolicy: func(ctx context.Context, host string) error {
|
||||||
|
return fmt.Errorf("no internal-only route for %q in this mesh", host)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
h := tokenOrRoute(routedTo(t, "the workload answered"), refusing)
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(rec, httptest.NewRequest("GET", "http://mail.example/.well-known/acme-challenge/mailus-token", nil))
|
||||||
|
|
||||||
|
if rec.Code != http.StatusOK || rec.Body.String() != "the workload answered" {
|
||||||
|
t.Fatalf("a policy refusal must fall through to routing; got %d %q", rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAnOrdinaryPathNeverTouchesTheChallengeMachinery(t *testing.T) {
|
func TestAnOrdinaryPathNeverTouchesTheChallengeMachinery(t *testing.T) {
|
||||||
m := &autocert.Manager{Prompt: autocert.AcceptTOS, Cache: autocert.DirCache(t.TempDir())}
|
m := &autocert.Manager{Prompt: autocert.AcceptTOS, Cache: autocert.DirCache(t.TempDir())}
|
||||||
h := tokenOrRoute(routedTo(t, "routed"), m)
|
h := tokenOrRoute(routedTo(t, "routed"), m)
|
||||||
|
|||||||
@@ -458,8 +458,11 @@ func tokenOrRoute(routes http.Handler, managers ...*autocert.Manager) http.Handl
|
|||||||
for _, probe := range probes {
|
for _, probe := range probes {
|
||||||
buffered := &probedResponse{header: make(http.Header)}
|
buffered := &probedResponse{header: make(http.Header)}
|
||||||
probe.ServeHTTP(buffered, r)
|
probe.ServeHTTP(buffered, r)
|
||||||
if buffered.status == http.StatusNotFound {
|
// Two shapes of "not mine": 404, a token this manager is not holding — and 403, a
|
||||||
continue // not this manager's token
|
// name its host policy would never certify at all (autocert checks the policy before
|
||||||
|
// the token, so the internal authority answers 403 for every public name).
|
||||||
|
if buffered.status == http.StatusNotFound || buffered.status == http.StatusForbidden {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
buffered.replayTo(w)
|
buffered.replayTo(w)
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user