From dee20d1d40b877fd864a36a68add258270aad504 Mon Sep 17 00:00:00 2001 From: Son Roy Almerol Date: Mon, 18 Nov 2024 11:49:58 -0500 Subject: [PATCH] ensure all api paths are authenticated --- internal/proxy/controllers/agents/agents.go | 2 +- .../controllers/exclusions/exclusions.go | 12 ++++ internal/proxy/controllers/jobs/jobs.go | 16 ++++++ .../partial_files/partial_files.go | 12 ++++ internal/proxy/controllers/targets/targets.go | 14 ++++- internal/store/auth.go | 57 +++++++++++++++++-- 6 files changed, 107 insertions(+), 6 deletions(-) diff --git a/internal/proxy/controllers/agents/agents.go b/internal/proxy/controllers/agents/agents.go index 1f71fac..10e5e05 100644 --- a/internal/proxy/controllers/agents/agents.go +++ b/internal/proxy/controllers/agents/agents.go @@ -22,7 +22,7 @@ func AgentLogHandler(storeInstance *store.Store) func(http.ResponseWriter, *http http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } - if err := store.CheckAgentAuth(r); err != nil { + if err := storeInstance.CheckProxyAuth(r); err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) } diff --git a/internal/proxy/controllers/exclusions/exclusions.go b/internal/proxy/controllers/exclusions/exclusions.go index 7c6eaaa..75b998e 100644 --- a/internal/proxy/controllers/exclusions/exclusions.go +++ b/internal/proxy/controllers/exclusions/exclusions.go @@ -18,6 +18,10 @@ func D2DExclusionHandler(storeInstance *store.Store) func(http.ResponseWriter, * http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + if r.Method == http.MethodGet { all, err := storeInstance.GetAllExclusions() if err != nil { @@ -53,6 +57,10 @@ func ExtJsExclusionHandler(storeInstance *store.Store) func(http.ResponseWriter, http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") err := r.ParseForm() @@ -88,6 +96,10 @@ func ExtJsExclusionSingleHandler(storeInstance *store.Store) func(http.ResponseW http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodPut { diff --git a/internal/proxy/controllers/jobs/jobs.go b/internal/proxy/controllers/jobs/jobs.go index 6f93e43..0471fa4 100644 --- a/internal/proxy/controllers/jobs/jobs.go +++ b/internal/proxy/controllers/jobs/jobs.go @@ -20,6 +20,10 @@ func D2DJobHandler(storeInstance *store.Store) func(http.ResponseWriter, *http.R return } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + allJobs, err := storeInstance.GetAllJobs() if err != nil { controllers.WriteErrorResponse(w, err) @@ -52,6 +56,10 @@ func ExtJsJobRunHandler(storeInstance *store.Store) func(http.ResponseWriter, *h return } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + job, err := storeInstance.GetJob(pathVar["job"]) if err != nil { controllers.WriteErrorResponse(w, err) @@ -83,6 +91,10 @@ func ExtJsJobHandler(storeInstance *store.Store) func(http.ResponseWriter, *http return } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") err := r.ParseForm() @@ -123,6 +135,10 @@ func ExtJsJobSingleHandler(storeInstance *store.Store) func(http.ResponseWriter, return } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodPut { diff --git a/internal/proxy/controllers/partial_files/partial_files.go b/internal/proxy/controllers/partial_files/partial_files.go index 017839a..4c6b235 100644 --- a/internal/proxy/controllers/partial_files/partial_files.go +++ b/internal/proxy/controllers/partial_files/partial_files.go @@ -18,6 +18,10 @@ func D2DPartialFileHandler(storeInstance *store.Store) func(http.ResponseWriter, http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + if r.Method == http.MethodGet { all, err := storeInstance.GetAllPartialFiles() if err != nil { @@ -53,6 +57,10 @@ func ExtJsPartialFileHandler(storeInstance *store.Store) func(http.ResponseWrite http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") err := r.ParseForm() @@ -87,6 +95,10 @@ func ExtJsPartialFileSingleHandler(storeInstance *store.Store) func(http.Respons http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodPut { diff --git a/internal/proxy/controllers/targets/targets.go b/internal/proxy/controllers/targets/targets.go index f3d20af..502e9d8 100644 --- a/internal/proxy/controllers/targets/targets.go +++ b/internal/proxy/controllers/targets/targets.go @@ -28,6 +28,10 @@ func D2DTargetHandler(storeInstance *store.Store) func(http.ResponseWriter, *htt http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + if r.Method == http.MethodGet { all, err := storeInstance.GetAllTargets() if err != nil { @@ -104,7 +108,7 @@ func D2DTargetAgentHandler(storeInstance *store.Store) func(http.ResponseWriter, http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } - if err := store.CheckAgentAuth(r); err != nil { + if err := storeInstance.CheckProxyAuth(r); err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) } @@ -159,6 +163,10 @@ func ExtJsTargetHandler(storeInstance *store.Store) func(http.ResponseWriter, *h http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") err := r.ParseForm() @@ -198,6 +206,10 @@ func ExtJsTargetSingleHandler(storeInstance *store.Store) func(http.ResponseWrit http.Error(w, "Invalid HTTP method", http.StatusBadRequest) } + if err := storeInstance.CheckProxyAuth(r); err != nil { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + w.Header().Set("Content-Type", "application/json") if r.Method == http.MethodPut { diff --git a/internal/store/auth.go b/internal/store/auth.go index 86940f2..276abe4 100644 --- a/internal/store/auth.go +++ b/internal/store/auth.go @@ -1,22 +1,23 @@ +//go:build linux + package store import ( "encoding/base64" "fmt" + "io" "net/http" "os" "path/filepath" "reflect" "strings" + "time" "github.com/sonroyaalmerol/pbs-plus/internal/utils" ) -func CheckAgentAuth(r *http.Request) error { +func checkAgentAuth(r *http.Request) error { auth := r.Header.Get("Authorization") - if !strings.HasPrefix(auth, "PBSPlusAPIAgent=") { - return fmt.Errorf("CheckAgentAuth: invalid auth prefix") - } privKeyDir := filepath.Join(DbBasePath, "agent_keys") @@ -49,3 +50,51 @@ func CheckAgentAuth(r *http.Request) error { return nil } + +func (storeInstance *Store) CheckProxyAuth(r *http.Request) error { + auth := r.Header.Get("Authorization") + if strings.HasPrefix(auth, "PBSPlusAPIAgent=") { + return checkAgentAuth(r) + } + + checkEndpoint := "/api2/json/version" + req, err := http.NewRequest( + http.MethodGet, + fmt.Sprintf( + "%s%s", + ProxyTargetURL, + checkEndpoint, + ), + nil, + ) + + if err != nil { + return fmt.Errorf("CheckProxyAuth: error creating http request -> %w", err) + } + + for _, cookie := range r.Cookies() { + req.AddCookie(cookie) + } + + if authHead := r.Header.Get("Authorization"); authHead != "" { + req.Header.Set("Authorization", authHead) + } + + if storeInstance.HTTPClient == nil { + storeInstance.HTTPClient = &http.Client{ + Timeout: time.Second * 30, + Transport: utils.BaseTransport, + } + } + + resp, err := storeInstance.HTTPClient.Do(req) + if err != nil { + return fmt.Errorf("CheckProxyAuth: invalid auth -> %w", err) + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + resp.Body.Close() + }() + + return nil +}