From 063374150c3acbf553a6faf8d03dc7e8cb09e418 Mon Sep 17 00:00:00 2001 From: benya Date: Thu, 4 Jun 2026 20:36:31 +0300 Subject: [PATCH] Fix LuCI menu authentication through proxy --- server/internal/httpapi/server.go | 13 ++++++------- server/internal/httpapi/server_test.go | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/server/internal/httpapi/server.go b/server/internal/httpapi/server.go index c58e17f..7e2b2fe 100644 --- a/server/internal/httpapi/server.go +++ b/server/internal/httpapi/server.go @@ -1183,7 +1183,7 @@ func rewriteLuCIHeaders(header http.Header, prefix string) { } } -func rewriteLuCICookie(cookie, prefix string) string { +func rewriteLuCICookie(cookie, _ string) string { parts := strings.Split(cookie, ";") pathFound := false for index := 1; index < len(parts); index++ { @@ -1191,15 +1191,14 @@ func rewriteLuCICookie(cookie, prefix string) string { if !strings.HasPrefix(strings.ToLower(attribute), "path=") { continue } - path := strings.TrimSpace(attribute[len("path="):]) - if !strings.HasPrefix(path, "/") { - path = "/" + path - } - parts[index] = " Path=" + prefix + path + // LuCI themes and JavaScript use absolute /cgi-bin, /ubus and + // /luci-static requests. The auth cookie must cover those fallback + // routes as well as the session-prefixed entry point. + parts[index] = " Path=/" pathFound = true } if !pathFound { - parts = append(parts, " Path="+prefix+"/") + parts = append(parts, " Path=/") } return strings.Join(parts, ";") } diff --git a/server/internal/httpapi/server_test.go b/server/internal/httpapi/server_test.go index 67e7a18..f237eb8 100644 --- a/server/internal/httpapi/server_test.go +++ b/server/internal/httpapi/server_test.go @@ -432,7 +432,7 @@ func TestLuCIProxyRequiresActiveSessionAndRewritesPaths(t *testing.T) { w.WriteHeader(http.StatusFound) return } - if r.URL.Path == "/cgi-bin/luci/admin/status/overview" { + if r.URL.Path == "/cgi-bin/luci/admin/status/overview" || r.URL.Path == "/cgi-bin/luci/admin/menu" { cookie, err := r.Cookie("sysauth") authenticated = err == nil && cookie.Value == "session-token" if !authenticated { @@ -548,6 +548,19 @@ func TestLuCIProxyRequiresActiveSessionAndRewritesPaths(t *testing.T) { if resp.StatusCode != http.StatusOK || !authenticated { t.Fatalf("LuCI login cookie was not preserved, status=%d authenticated=%t", resp.StatusCode, authenticated) } + menuReq, err := http.NewRequest(http.MethodGet, srv.URL+"/cgi-bin/luci/admin/menu", nil) + if err != nil { + t.Fatal(err) + } + menuReq.Header.Set("Authorization", "Bearer operator-test") + menuResp, err := client.Do(menuReq) + if err != nil { + t.Fatal(err) + } + _ = menuResp.Body.Close() + if menuResp.StatusCode != http.StatusOK || !authenticated { + t.Fatalf("LuCI auth cookie was not sent to absolute menu route, status=%d authenticated=%t", menuResp.StatusCode, authenticated) + } } func TestServesStaticWebUI(t *testing.T) {