Unverified Commit b8da4e23 authored by Lemon-miaow's avatar Lemon-miaow
Browse files

fix(api): ownerOnly/adminOnly 包在已有的包装外层,路由的每层门禁都生效

parent fef8d962
Loading
Loading
Loading
Loading
+2 −2
Changes for internal/api/api.go: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -752,10 +752,10 @@ func (a *API) buildFace(face string, routes []apiRoute, guard func(http.Handler)
			h = callersOnly(rt.Callers, h)
		}
		if rt.Owner {
			h = a.ownerOnly(rt.h)
			h = a.ownerOnly(h)
		}
		if rt.Admin {
			h = a.adminOnly(rt.h)
			h = a.adminOnly(h)
		}
		// Default-deny setup-lockdown: wrap every authenticated route unless it
		// explicitly opts out. The wrapper is nil-principal safe, so it is inert on
+41 −0
Changes for internal/api/route_tiers_test.go: 41 added lines, 0 removed lines.
Original line number Diff line number Diff line
package api

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
)

// Each tier a route sets is one more gate in front of its handler: a route marked
// both Owner and Admin still refuses an admin who is not the owner.
func TestBuildFaceStacksTierGates(t *testing.T) {
	a := newTestAPI(newFakeRepo(), newFakeCluster())
	ran := false
	ok := func(w http.ResponseWriter, r *http.Request) { ran = true }
	as := func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			p := &Principal{UserID: "u1", Role: r.Header.Get("X-Test-Role"), ViaAdminAccess: true, EmailVerified: true}
			h.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), ctxKeyPrincipal, p)))
		})
	}
	h := a.buildFace("external", []apiRoute{{Method: "GET", Pattern: "/api/v1/tiered", Owner: true, Admin: true, h: ok}}, as)

	for _, c := range []struct {
		role string
		code int
	}{
		{"admin", http.StatusForbidden},
		{"user", http.StatusForbidden},
		{"owner", http.StatusOK},
	} {
		ran = false
		r := httptest.NewRequest("GET", "/api/v1/tiered", nil)
		r.Header.Set("X-Test-Role", c.role)
		w := httptest.NewRecorder()
		h.ServeHTTP(w, r)
		if w.Code != c.code || ran != (c.code == http.StatusOK) {
			t.Errorf("%s: status %d, handler ran %v; want %d", c.role, w.Code, ran, c.code)
		}
	}
}