From fa3589944361a5fe320b31422869581b1d82d0de Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Wed, 25 Mar 2026 22:41:36 -0700 Subject: [PATCH] Use absolute realm URL in WWW-Authenticate and add service_name OCI clients (podman, docker) require an absolute URL in the WWW-Authenticate realm. Derive it from the request Host header so it works behind any proxy. Add service_name to rift config. Co-Authored-By: Claude Opus 4.6 (1M context) --- deploy/mcr-rift.toml | 1 + internal/server/middleware.go | 8 ++++++-- internal/server/middleware_test.go | 2 +- internal/server/routes_test.go | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/deploy/mcr-rift.toml b/deploy/mcr-rift.toml index c793c49..e8a0a68 100644 --- a/deploy/mcr-rift.toml +++ b/deploy/mcr-rift.toml @@ -26,6 +26,7 @@ uploads_path = "/srv/mcr/uploads" [mcias] server_url = "https://mcias.metacircular.net:8443" ca_cert = "/srv/mcr/certs/ca.pem" +service_name = "mcr" service_token = "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL21jaWFzLm1ldGFjaXJjdWxhci5uZXQiLCJzdWIiOiIwYWM3NDk3ZS0wZTE5LTRhOWMtYWI3Yi03YWZjMzc0ZDU3NzIiLCJleHAiOjE4MDYwMzczNzMsIm5iZiI6MTc3NDUwMTM3MywiaWF0IjoxNzc0NTAxMzczLCJqdGkiOiI1NTM0ZDU0OS1kYzY5LTRiNzctYTY5MC0xNzQ3NjE0MDUzYzEiLCJyb2xlcyI6bnVsbH0.bsnoGMrFzJJCIanGuiAvpqmlO2OssvFjYynQgiSt_TPMuLxziRuwuRIL9C_kRnHdF7C6c1mTHncKVj1hkLPiCg" [web] diff --git a/internal/server/middleware.go b/internal/server/middleware.go index d83ef48..e4fc862 100644 --- a/internal/server/middleware.go +++ b/internal/server/middleware.go @@ -19,10 +19,14 @@ type TokenValidator interface { // into the request context. On failure a 401 with an OCI-format error // body and a WWW-Authenticate header is returned. func RequireAuth(validator TokenValidator, serviceName string) func(http.Handler) http.Handler { - wwwAuth := fmt.Sprintf(`Bearer realm="/v2/token",service="%s"`, serviceName) - return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Build the WWW-Authenticate header with an absolute realm URL + // derived from the request Host, per OCI Distribution Spec. + scheme := "https" + realm := fmt.Sprintf("%s://%s/v2/token", scheme, r.Host) + wwwAuth := fmt.Sprintf(`Bearer realm="%s",service="%s"`, realm, serviceName) + token := extractBearerToken(r) if token == "" { w.Header().Set("WWW-Authenticate", wwwAuth) diff --git a/internal/server/middleware_test.go b/internal/server/middleware_test.go index 1d9b35a..5b71a9f 100644 --- a/internal/server/middleware_test.go +++ b/internal/server/middleware_test.go @@ -68,7 +68,7 @@ func TestRequireAuthMissing(t *testing.T) { } wwwAuth := rec.Header().Get("WWW-Authenticate") - want := `Bearer realm="/v2/token",service="mcr-test"` + want := `Bearer realm="https://example.com/v2/token",service="mcr-test"` if wwwAuth != want { t.Fatalf("WWW-Authenticate: got %q, want %q", wwwAuth, want) } diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go index ffb2f08..fb2041e 100644 --- a/internal/server/routes_test.go +++ b/internal/server/routes_test.go @@ -55,7 +55,7 @@ func TestRoutesV2Unauthenticated(t *testing.T) { } wwwAuth := rec.Header().Get("WWW-Authenticate") - want := `Bearer realm="/v2/token",service="mcr-test"` + want := `Bearer realm="https://example.com/v2/token",service="mcr-test"` if wwwAuth != want { t.Fatalf("WWW-Authenticate: got %q, want %q", wwwAuth, want) }