Preserve LuCI login cookie path

This commit is contained in:
benya
2026-06-04 19:51:47 +03:00
parent aa50728a2d
commit 4709293c4f
2 changed files with 52 additions and 3 deletions

View File

@@ -1179,12 +1179,31 @@ func rewriteLuCIHeaders(header http.Header, prefix string) {
header.Set("Location", prefix+location)
}
for index, cookie := range header.Values("Set-Cookie") {
cookie = strings.ReplaceAll(cookie, "Path=/;", "Path="+prefix+"/;")
cookie = strings.ReplaceAll(cookie, "Path=/ ", "Path="+prefix+"/ ")
header["Set-Cookie"][index] = cookie
header["Set-Cookie"][index] = rewriteLuCICookie(cookie, prefix)
}
}
func rewriteLuCICookie(cookie, prefix string) string {
parts := strings.Split(cookie, ";")
pathFound := false
for index := 1; index < len(parts); index++ {
attribute := strings.TrimSpace(parts[index])
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
pathFound = true
}
if !pathFound {
parts = append(parts, " Path="+prefix+"/")
}
return strings.Join(parts, ";")
}
func (a *App) handleCloseRemoteSession(w http.ResponseWriter, r *http.Request) {
deviceID, sessionID, ok := remoteSessionCloseIDsFromPath(r.URL.Path)
if !ok {

View File

@@ -407,6 +407,7 @@ func TestAgentOperatorSmokeFlow(t *testing.T) {
func TestLuCIProxyRequiresActiveSessionAndRewritesPaths(t *testing.T) {
var upstreamPath string
var authenticated bool
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Host != "127.0.0.1" {
http.Error(w, "rejected host", http.StatusForbidden)
@@ -425,6 +426,20 @@ func TestLuCIProxyRequiresActiveSessionAndRewritesPaths(t *testing.T) {
t.Fatal("LuCI route cookie leaked to LuCI upstream")
}
upstreamPath = r.URL.Path
if r.Method == http.MethodPost && r.URL.Path == "/cgi-bin/luci/" {
http.SetCookie(w, &http.Cookie{Name: "sysauth", Value: "session-token", Path: "/cgi-bin/luci"})
w.Header().Set("Location", "/cgi-bin/luci/admin/status/overview")
w.WriteHeader(http.StatusFound)
return
}
if r.URL.Path == "/cgi-bin/luci/admin/status/overview" {
cookie, err := r.Cookie("sysauth")
authenticated = err == nil && cookie.Value == "session-token"
if !authenticated {
http.Error(w, "login required", http.StatusForbidden)
return
}
}
if r.URL.Path == "/luci-static/resources/luci.js" {
w.Header().Set("Content-Type", "application/javascript")
_, _ = io.WriteString(w, `const untouched = '/cgi-bin/luci';`)
@@ -518,6 +533,21 @@ func TestLuCIProxyRequiresActiveSessionAndRewritesPaths(t *testing.T) {
if script != `const untouched = '/cgi-bin/luci';` {
t.Fatalf("LuCI JavaScript was unexpectedly rewritten: %s", script)
}
loginURL := srv.URL + prefix + "/cgi-bin/luci/"
req, err := http.NewRequest(http.MethodPost, loginURL, strings.NewReader("luci_username=root&luci_password=test"))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Authorization", "Bearer operator-test")
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
_ = resp.Body.Close()
if resp.StatusCode != http.StatusOK || !authenticated {
t.Fatalf("LuCI login cookie was not preserved, status=%d authenticated=%t", resp.StatusCode, authenticated)
}
}
func TestServesStaticWebUI(t *testing.T) {