79 lines
2.8 KiB
Go
79 lines
2.8 KiB
Go
package webui
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestScopedAdminCannotAccessServerSettingsOrLetsEncrypt guards against a regression
|
|
// where a domain-scoped admin (delegated access to specific domains only, not a
|
|
// global admin) could still read/change server-wide config that has nothing to do
|
|
// with any one domain — the admin dashboard's own port, TLS certs, database URL,
|
|
// Let's Encrypt/ACME credentials, etc.
|
|
func TestScopedAdminCannotAccessServerSettingsOrLetsEncrypt(t *testing.T) {
|
|
app := newTestApp(t)
|
|
mux := app.Mux()
|
|
domains, err := app.DB.ListDomains()
|
|
if err != nil || len(domains) == 0 {
|
|
t.Fatal("no seeded domain")
|
|
}
|
|
cookie := scopedLogin(t, app, "scoped-settings-admin", []int64{domains[0].ID})
|
|
|
|
routes := []struct {
|
|
method, path string
|
|
}{
|
|
{http.MethodGet, "/pymta-manager/settings"},
|
|
{http.MethodPost, "/pymta-manager/settings_update"},
|
|
{http.MethodGet, "/pymta-manager/letsencrypt"},
|
|
{http.MethodPost, "/pymta-manager/letsencrypt/save"},
|
|
{http.MethodPost, "/pymta-manager/letsencrypt/obtain"},
|
|
{http.MethodGet, "/pymta-manager/api/settings/get_public_ip"},
|
|
}
|
|
for _, rt := range routes {
|
|
req := httptest.NewRequest(rt.method, rt.path, nil)
|
|
req.AddCookie(cookie)
|
|
rec := httptest.NewRecorder()
|
|
mux.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusNotFound {
|
|
t.Errorf("%s %s: status=%d, want 404 for a scoped admin", rt.method, rt.path, rec.Code)
|
|
}
|
|
}
|
|
|
|
// A global admin must still reach these routes normally.
|
|
globalCookie := loginSession(t, app)
|
|
req := httptest.NewRequest(http.MethodGet, "/pymta-manager/settings", nil)
|
|
req.AddCookie(globalCookie)
|
|
rec := httptest.NewRecorder()
|
|
mux.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("global admin GET /settings: status=%d, want 200", rec.Code)
|
|
}
|
|
}
|
|
|
|
// TestScopedAdminSidebarHidesServerWideLinks confirms the sidebar doesn't even show
|
|
// Server Settings/Let's Encrypt to a scoped admin (backend enforcement is the real
|
|
// gate, this is just the corresponding UI affordance).
|
|
func TestScopedAdminSidebarHidesServerWideLinks(t *testing.T) {
|
|
app := newTestApp(t)
|
|
mux := app.Mux()
|
|
domains, _ := app.DB.ListDomains()
|
|
cookie := scopedLogin(t, app, "scoped-sidebar-admin", []int64{domains[0].ID})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/pymta-manager/", nil)
|
|
req.AddCookie(cookie)
|
|
rec := httptest.NewRecorder()
|
|
mux.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("dashboard: status=%d body=%s", rec.Code, rec.Body.String())
|
|
}
|
|
body := rec.Body.String()
|
|
if strings.Contains(body, `href="/pymta-manager/settings"`) {
|
|
t.Error("scoped admin's sidebar should not link to Server Settings")
|
|
}
|
|
if strings.Contains(body, `href="/pymta-manager/letsencrypt"`) {
|
|
t.Error("scoped admin's sidebar should not link to Let's Encrypt")
|
|
}
|
|
}
|