fix(api): ownerOnly/adminOnly 包在已有的包装外层,路由的每层门禁都生效
This commit is contained in:
2 files changed
+43
-2
No files matched your search
+2
-2
@@ -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
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user