diff --git a/cmd/cc-backend/main.go b/cmd/cc-backend/main.go index 0ac66c1..fdddb99 100644 --- a/cmd/cc-backend/main.go +++ b/cmd/cc-backend/main.go @@ -373,6 +373,8 @@ func main() { secured := r.PathPrefix("/").Subrouter() securedapi := r.PathPrefix("/api").Subrouter() userapi := r.PathPrefix("/userapi").Subrouter() + configapi := r.PathPrefix("/config").Subrouter() + userconfigapi := r.PathPrefix("/userconfig").Subrouter() if !config.Keys.DisableAuthentication { r.Handle("/login", authentication.Login( @@ -475,6 +477,42 @@ func main() { }) }) }) + + configapi.Use(func(next http.Handler) http.Handler { + return authentication.AuthConfigApi( + // On success; + next, + + // On failure: + func(rw http.ResponseWriter, r *http.Request, err error) { + rw.WriteHeader(http.StatusUnauthorized) + web.RenderTemplate(rw, "login.tmpl", &web.Page{ + Title: "Authentication failed - ClusterCockpit", + MsgType: "alert-danger", + Message: err.Error(), + Build: buildInfo, + Infos: info, + }) + }) + }) + + userconfigapi.Use(func(next http.Handler) http.Handler { + return authentication.AuthUserConfigApi( + // On success; + next, + + // On failure: + func(rw http.ResponseWriter, r *http.Request, err error) { + rw.WriteHeader(http.StatusUnauthorized) + web.RenderTemplate(rw, "login.tmpl", &web.Page{ + Title: "Authentication failed - ClusterCockpit", + MsgType: "alert-danger", + Message: err.Error(), + Build: buildInfo, + Infos: info, + }) + }) + }) } if flagDev { @@ -491,9 +529,10 @@ func main() { // Mount all /monitoring/... and /api/... routes. routerConfig.SetupRoutes(secured, buildInfo) - api.MountConfigApiRoutes(secured) api.MountApiRoutes(securedapi) api.MountUserApiRoutes(userapi) + api.MountConfigApiRoutes(configapi) + api.MountUserConfigApiRoutes(userconfigapi) if config.Keys.EmbedStaticFiles { if i, err := os.Stat("./var/img"); err == nil { diff --git a/internal/api/rest.go b/internal/api/rest.go index cd4a497..17a3183 100644 --- a/internal/api/rest.go +++ b/internal/api/rest.go @@ -92,23 +92,25 @@ func (api *RestApi) MountUserApiRoutes(r *mux.Router) { r.HandleFunc("/jobs/{id}", api.getJobById).Methods(http.MethodPost) r.HandleFunc("/jobs/{id}", api.getCompleteJobById).Methods(http.MethodGet) r.HandleFunc("/jobs/metrics/{id}", api.getJobMetrics).Methods(http.MethodGet) - - if api.Authentication != nil { - r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet) - } } func (api *RestApi) MountConfigApiRoutes(r *mux.Router) { - r = r.PathPrefix("/config").Subrouter() r.StrictSlash(true) if api.Authentication != nil { - r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet) r.HandleFunc("/roles/", api.getRoles).Methods(http.MethodGet) r.HandleFunc("/users/", api.createUser).Methods(http.MethodPost, http.MethodPut) r.HandleFunc("/users/", api.getUsers).Methods(http.MethodGet) r.HandleFunc("/users/", api.deleteUser).Methods(http.MethodDelete) r.HandleFunc("/user/{id}", api.updateUser).Methods(http.MethodPost) + } +} + +func (api *RestApi) MountUserConfigApiRoutes(r *mux.Router) { + r.StrictSlash(true) + + if api.Authentication != nil { + r.HandleFunc("/jwt/", api.getJWT).Methods(http.MethodGet) // Role:Admin Check in r.HandleFunc("/configuration/", api.updateConfiguration).Methods(http.MethodPost) } } diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 9b42072..7e6f30e 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -314,6 +314,48 @@ func (auth *Authentication) AuthUserApi( }) } +func (auth *Authentication) AuthConfigApi( + onsuccess http.Handler, + onfailure func(rw http.ResponseWriter, r *http.Request, authErr error), +) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + user, err := auth.AuthViaSession(rw, r) + if err != nil { + log.Infof("authentication failed: %s", err.Error()) + http.Error(rw, err.Error(), http.StatusUnauthorized) + return + } + if user != nil && user.HasRole(schema.RoleAdmin) { + ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) + onsuccess.ServeHTTP(rw, r.WithContext(ctx)) + return + } + log.Debug("authentication failed") + onfailure(rw, r, errors.New("unauthorized (no auth)")) + }) +} + +func (auth *Authentication) AuthUserConfigApi( + onsuccess http.Handler, + onfailure func(rw http.ResponseWriter, r *http.Request, authErr error), +) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + user, err := auth.AuthViaSession(rw, r) + if err != nil { + log.Infof("authentication failed: %s", err.Error()) + http.Error(rw, err.Error(), http.StatusUnauthorized) + return + } + if user != nil { + ctx := context.WithValue(r.Context(), repository.ContextUserKey, user) + onsuccess.ServeHTTP(rw, r.WithContext(ctx)) + return + } + log.Debug("authentication failed") + onfailure(rw, r, errors.New("unauthorized (no auth)")) + }) +} + func (auth *Authentication) Logout(onsuccess http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { session, err := auth.sessionStore.Get(r, "session") diff --git a/web/frontend/src/config/PlotSettings.svelte b/web/frontend/src/config/PlotSettings.svelte index 93018a3..b5ea5e5 100644 --- a/web/frontend/src/config/PlotSettings.svelte +++ b/web/frontend/src/config/PlotSettings.svelte @@ -283,7 +283,7 @@
handleSettingSubmit("#line-width-form", "lw")} @@ -329,7 +329,7 @@ handleSettingSubmit("#plots-per-row-form", "ppr")} @@ -375,7 +375,7 @@ handleSettingSubmit("#backgrounds-form", "bg")} @@ -429,7 +429,7 @@ handleSettingSubmit("#paging-form", "pag")} @@ -485,7 +485,7 @@ diff --git a/web/frontend/src/config/admin/ShowUsersRow.svelte b/web/frontend/src/config/admin/ShowUsersRow.svelte index 4dae0c9..2971365 100644 --- a/web/frontend/src/config/admin/ShowUsersRow.svelte +++ b/web/frontend/src/config/admin/ShowUsersRow.svelte @@ -5,7 +5,7 @@ let jwt = ""; function getUserJwt(username) { - fetch(`/config/jwt/?username=${username}`) + fetch(`/userconfig/jwt/?username=${username}`) .then((res) => res.text()) .then((text) => { jwt = text;