[perf] Move to Roles.
Only roles.Editor's are allowed to triage, create alerts, etc.
Also remove InternalOnly support as that can now be handled
by auth-proxy also.
Bug: b/249507110
Change-Id: Ib9a8a6efa22aaf753e47c3b580fc9562f0d01e1c
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/586702
Reviewed-by: Ravi Mistry <rmistry@google.com>
Commit-Queue: Joe Gregorio <jcgregorio@google.com>
diff --git a/perf/go/config/config.go b/perf/go/config/config.go
index 6bd5d9b..2ac0e37 100644
--- a/perf/go/config/config.go
+++ b/perf/go/config/config.go
@@ -243,7 +243,7 @@
// FrontendFlags are the command-line flags for the web UI.
type FrontendFlags struct {
- AuthBypassList string
+ AuthBypassList string // TODO(jcgregorio) Remove after migrating to Roles.
ConfigFilename string
ConnectionString string
CommitRangeURL string
@@ -252,7 +252,7 @@
NoEmail bool
EventDrivenRegressionDetection bool
Interesting float64
- InternalOnly bool
+ InternalOnly bool // TODO(jcgregorio) Remove after migrating to Roles.
KeyOrder string
Local bool
NumContinuous int
@@ -266,7 +266,7 @@
Radius int
StepUpOnly bool
DisplayGroupBy bool
- ProxyLogin bool
+ ProxyLogin bool // TODO(jcgregorio) Remove after migrating to Roles.
}
// AsCliFlags returns a slice of cli.Flag.
diff --git a/perf/go/frontend/BUILD.bazel b/perf/go/frontend/BUILD.bazel
index 6f3cd7d..81035f4 100644
--- a/perf/go/frontend/BUILD.bazel
+++ b/perf/go/frontend/BUILD.bazel
@@ -8,7 +8,6 @@
deps = [
"//go/alogin",
"//go/alogin/proxylogin",
- "//go/alogin/sklogin",
"//go/auditlog",
"//go/calc",
"//go/email",
@@ -16,6 +15,7 @@
"//go/metrics2",
"//go/paramtools",
"//go/query",
+ "//go/roles",
"//go/skerr",
"//go/sklog",
"//go/sklog/sklogimpl",
diff --git a/perf/go/frontend/frontend.go b/perf/go/frontend/frontend.go
index b25a005..ae602f6 100644
--- a/perf/go/frontend/frontend.go
+++ b/perf/go/frontend/frontend.go
@@ -25,7 +25,6 @@
"go.opencensus.io/trace"
"go.skia.org/infra/go/alogin"
"go.skia.org/infra/go/alogin/proxylogin"
- "go.skia.org/infra/go/alogin/sklogin"
"go.skia.org/infra/go/auditlog"
"go.skia.org/infra/go/calc"
"go.skia.org/infra/go/email"
@@ -33,6 +32,7 @@
"go.skia.org/infra/go/metrics2"
"go.skia.org/infra/go/paramtools"
"go.skia.org/infra/go/query"
+ "go.skia.org/infra/go/roles"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
"go.skia.org/infra/go/sklog/sklogimpl"
@@ -289,20 +289,13 @@
cfg := config.Config
// Configure login.
- if f.flags.ProxyLogin {
- f.loginProvider, err = proxylogin.New(
- cfg.AuthConfig.HeaderName,
- cfg.AuthConfig.EmailRegex,
- cfg.AuthConfig.LoginURL,
- cfg.AuthConfig.LogoutURL)
- if err != nil {
- sklog.Fatalf("Failed to initialize login: %s", err)
- }
- } else {
- f.loginProvider, err = sklogin.New(f.flags.Port, f.flags.Local, f.flags.AuthBypassList)
- if err != nil {
- sklog.Fatalf("Failed to initialize the login system: %s", err)
- }
+ f.loginProvider, err = proxylogin.New(
+ cfg.AuthConfig.HeaderName,
+ cfg.AuthConfig.EmailRegex,
+ cfg.AuthConfig.LoginURL,
+ cfg.AuthConfig.LogoutURL)
+ if err != nil {
+ sklog.Fatalf("Failed to initialize login: %s", err)
}
ctx := context.Background()
@@ -820,6 +813,16 @@
}
}
+func (f *Frontend) isEditor(w http.ResponseWriter, r *http.Request, action string, body interface{}) bool {
+ user := f.loginProvider.LoggedInAs(r)
+ if f.loginProvider.HasRole(r, roles.Editor) {
+ httputils.ReportError(w, fmt.Errorf("Not logged in."), "You must be logged in to complete this action.", http.StatusInternalServerError)
+ return false
+ }
+ auditlog.LogWithUser(r, user.String(), "triage", body)
+ return true
+}
+
// TriageRequest is used in triageHandler.
type TriageRequest struct {
Cid types.CommitNumber `json:"cid"`
@@ -840,17 +843,14 @@
func (f *Frontend) triageHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
w.Header().Set("Content-Type", "application/json")
- user := f.loginProvider.LoggedInAs(r)
- if user == alogin.NotLoggedIn {
- httputils.ReportError(w, fmt.Errorf("Not logged in."), "You must be logged in to triage.", http.StatusInternalServerError)
- return
- }
tr := &TriageRequest{}
if err := json.NewDecoder(r.Body).Decode(tr); err != nil {
httputils.ReportError(w, err, "Failed to decode JSON.", http.StatusInternalServerError)
return
}
- auditlog.LogWithUser(r, user.String(), "triage", tr)
+ if !f.isEditor(w, r, "triage", tr) {
+ return
+ }
detail, err := f.perfGit.CommitFromCommitNumber(ctx, tr.Cid)
if err != nil {
httputils.ReportError(w, err, "Failed to find CommitID.", http.StatusInternalServerError)
@@ -1294,18 +1294,17 @@
func (f *Frontend) alertUpdateHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
- user := f.loginProvider.LoggedInAs(r)
- if user == alogin.NotLoggedIn {
- httputils.ReportError(w, fmt.Errorf("Not logged in."), "You must be logged in to edit alerts.", http.StatusInternalServerError)
- return
- }
cfg := &alerts.Alert{}
if err := json.NewDecoder(r.Body).Decode(cfg); err != nil {
httputils.ReportError(w, err, "Failed to decode JSON.", http.StatusInternalServerError)
return
}
- auditlog.LogWithUser(r, user.String(), "alert-update", cfg)
+
+ if !f.isEditor(w, r, "alert-update", cfg) {
+ return
+ }
+
if err := f.alertStore.Save(r.Context(), cfg); err != nil {
httputils.ReportError(w, err, "Failed to save alerts.Config.", http.StatusInternalServerError)
}
@@ -1319,18 +1318,17 @@
func (f *Frontend) alertDeleteHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
- user := f.loginProvider.LoggedInAs(r)
- if user == alogin.NotLoggedIn {
- httputils.ReportError(w, fmt.Errorf("Not logged in."), "You must be logged in to delete alerts.", http.StatusInternalServerError)
- return
- }
sid := mux.Vars(r)["id"]
id, err := strconv.ParseInt(sid, 10, 64)
if err != nil {
httputils.ReportError(w, err, "Failed to parse alert id.", http.StatusInternalServerError)
}
- auditlog.LogWithUser(r, user.String(), "alert-delete", sid)
+
+ if !f.isEditor(w, r, "alert-delete", sid) {
+ return
+ }
+
if err := f.alertStore.Delete(r.Context(), int(id)); err != nil {
httputils.ReportError(w, err, "Failed to delete the alerts.Config.", http.StatusInternalServerError)
return
@@ -1349,18 +1347,17 @@
func (f *Frontend) alertBugTryHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
- user := f.loginProvider.LoggedInAs(r)
- if user == alogin.NotLoggedIn {
- httputils.ReportError(w, fmt.Errorf("Not logged in."), "You must be logged in to test alerts.", http.StatusInternalServerError)
- return
- }
req := &TryBugRequest{}
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
httputils.ReportError(w, err, "Failed to decode JSON.", http.StatusInternalServerError)
return
}
- auditlog.LogWithUser(r, user.String(), "alert-bug-try", req)
+
+ if !f.isEditor(w, r, "alert-bug-try", req) {
+ return
+ }
+
resp := &TryBugResponse{
URL: bug.ExampleExpand(req.BugURITemplate),
}
@@ -1371,18 +1368,17 @@
func (f *Frontend) alertNotifyTryHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
- user := f.loginProvider.LoggedInAs(r)
- if user == alogin.NotLoggedIn {
- httputils.ReportError(w, fmt.Errorf("Not logged in."), "You must be logged in to try alerts.", http.StatusInternalServerError)
- return
- }
req := &alerts.Alert{}
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
httputils.ReportError(w, err, "Failed to decode JSON.", http.StatusInternalServerError)
return
}
- auditlog.LogWithUser(r, user.String(), "alert-notify-try", req)
+
+ if !f.isEditor(w, r, "alert-notify-try", req) {
+ return
+ }
+
if err := f.notifier.ExampleSend(r.Context(), req); err != nil {
httputils.ReportError(w, err, fmt.Sprintf("Failed to send email: %s", err), http.StatusInternalServerError)
}
@@ -1416,24 +1412,6 @@
http.Redirect(w, r, "/t/", http.StatusMovedPermanently)
}
-var internalOnlyExceptions = []string{
- "/oauth2callback/",
- "/_/reg/count",
-}
-
-// internalOnlyHandler wraps the handler with a handler that only allows
-// authenticated access, with the exception of the endpoints listed in
-// internalOnlyExceptions.
-func (f *Frontend) internalOnlyHandler(h http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if util.In(r.URL.Path, internalOnlyExceptions) || f.loginProvider.LoggedInAs(r) != alogin.NotLoggedIn {
- h.ServeHTTP(w, r)
- } else {
- f.loginProvider.NeedsAuthentication(w, r)
- }
- })
-}
-
// Serve content on the configured endpoints.Serve.
//
// This method does not return.
@@ -1510,9 +1488,6 @@
router.HandleFunc("/_/login/status", f.loginStatus).Methods("GET")
var h http.Handler = router
- if f.flags.InternalOnly {
- h = f.internalOnlyHandler(h)
- }
h = httputils.LoggingGzipRequestResponse(h)
if !f.flags.Local {
h = httputils.HealthzAndHTTPS(h)