From 4efb06849eb3d29357453adf759dbba0ea4c68b7 Mon Sep 17 00:00:00 2001 From: Jarek Kowalski Date: Sat, 13 Mar 2021 09:58:27 -0800 Subject: [PATCH] server: ensure we reject access to the UI static files for users other than the UI user (#884) This is for a scenario where a user provides valid username/password but such that the username is not authorized to access the UI. Previously we'd make it look like they got access (because they can see the UI at leaast partially), but all API calls would fail. With this change we're failing early with HTTP 403 and pointing the users at a GH issue explaining what to do. Fixes #580. --- cli/command_server_start.go | 4 ++-- internal/server/server.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cli/command_server_start.go b/cli/command_server_start.go index afa9d7be3..83e106c06 100644 --- a/cli/command_server_start.go +++ b/cli/command_server_start.go @@ -87,10 +87,10 @@ func runServer(ctx context.Context, rep repo.Repository) error { mux.Handle("/api/", srv.APIHandlers(*serverStartLegacyRepositoryAPI)) if *serverStartHTMLPath != "" { - fileServer := serveIndexFileForKnownUIRoutes(http.Dir(*serverStartHTMLPath)) + fileServer := srv.RequireUIUserAuth(serveIndexFileForKnownUIRoutes(http.Dir(*serverStartHTMLPath))) mux.Handle("/", fileServer) } else if *serverStartUI { - mux.Handle("/", serveIndexFileForKnownUIRoutes(server.AssetFile())) + mux.Handle("/", srv.RequireUIUserAuth(serveIndexFileForKnownUIRoutes(server.AssetFile()))) } httpServer := &http.Server{Addr: stripProtocol(*serverAddress)} diff --git a/internal/server/server.go b/internal/server/server.go index 766315990..1aae33e95 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -238,6 +238,18 @@ func (s *Server) handleAPI(isAuthorized isAuthorizedFunc, f apiRequestFunc) http }) } +// RequireUIUserAuth wraps the provided http.Handler to only allow UI user and return 403 otherwise. +func (s *Server) RequireUIUserAuth(hf http.Handler) http.Handler { + return s.requireAuth(func(rw http.ResponseWriter, r *http.Request) { + if !requireUIUser(s, r) { + http.Error(rw, `UI Access denied. See https://github.com/kopia/kopia/issues/880#issuecomment-798421751 for more information.`, http.StatusForbidden) + return + } + + hf.ServeHTTP(rw, r) + }) +} + func (s *Server) handleAPIPossiblyNotConnected(isAuthorized isAuthorizedFunc, f apiRequestFunc) http.HandlerFunc { return s.requireAuth(func(w http.ResponseWriter, r *http.Request) { // we must pre-read request body before acquiring the lock as it sometimes leads to deadlock