From d9a83c90e3962ab9ddbe3089790b8fda144abd87 Mon Sep 17 00:00:00 2001 From: catttam Date: Thu, 1 Feb 2024 12:46:56 +0100 Subject: [PATCH] Added user check to last handlers --- main.go | 6 ++--- pkg/handlers/create.go | 3 --- pkg/handlers/delete.go | 22 +++++++++++++++ pkg/handlers/logs.go | 61 ++++++++++++++++++++++++------------------ pkg/handlers/read.go | 3 +-- 5 files changed, 61 insertions(+), 34 deletions(-) diff --git a/main.go b/main.go index 3fdfdd25..69e1fce1 100644 --- a/main.go +++ b/main.go @@ -91,9 +91,9 @@ func main() { // Logs paths system.GET("/logs/:serviceName", handlers.MakeJobsInfoHandler(back, kubeClientset, cfg.ServicesNamespace)) - system.DELETE("/logs/:serviceName", handlers.MakeDeleteJobsHandler(kubeClientset, cfg.ServicesNamespace)) - system.GET("/logs/:serviceName/:jobName", handlers.MakeGetLogsHandler(kubeClientset, cfg.ServicesNamespace)) - system.DELETE("/logs/:serviceName/:jobName", handlers.MakeDeleteJobHandler(kubeClientset, cfg.ServicesNamespace)) + system.DELETE("/logs/:serviceName", handlers.MakeDeleteJobsHandler(back, kubeClientset, cfg.ServicesNamespace)) + system.GET("/logs/:serviceName/:jobName", handlers.MakeGetLogsHandler(back, kubeClientset, cfg.ServicesNamespace)) + system.DELETE("/logs/:serviceName/:jobName", handlers.MakeDeleteJobHandler(back, kubeClientset, cfg.ServicesNamespace)) // Job path for async invocations r.POST("/job/:serviceName", handlers.MakeJobHandler(cfg, kubeClientset, back, resMan)) diff --git a/pkg/handlers/create.go b/pkg/handlers/create.go index 050948c5..18e294ed 100644 --- a/pkg/handlers/create.go +++ b/pkg/handlers/create.go @@ -76,8 +76,6 @@ func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand c.String(http.StatusInternalServerError, fmt.Sprintln(err)) } - createLogger.Println("Multitenancy config: ", mc) - if err := c.ShouldBindJSON(&service); err != nil { c.String(http.StatusBadRequest, fmt.Sprintf("The service specification is not valid: %v", err)) return @@ -115,7 +113,6 @@ func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand } } - createLogger.Println("Service labels: ", service.Labels) // Create the service if err := back.CreateService(service); err != nil { // Check if error is caused because the service name provided already exists diff --git a/pkg/handlers/delete.go b/pkg/handlers/delete.go index 2877fc3e..c6d6ecdd 100644 --- a/pkg/handlers/delete.go +++ b/pkg/handlers/delete.go @@ -28,6 +28,7 @@ import ( "github.com/gin-gonic/gin" "github.com/grycap/oscar/v2/pkg/types" "github.com/grycap/oscar/v2/pkg/utils" + "github.com/grycap/oscar/v2/pkg/utils/auth" "k8s.io/apimachinery/pkg/api/errors" ) @@ -38,6 +39,27 @@ func MakeDeleteHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand return func(c *gin.Context) { // First get the Service service, _ := back.ReadService(c.Param("serviceName")) + authHeader := c.GetHeader("Authorization") + + if len(strings.Split(authHeader, "Bearer")) > 1 { + uid, err := auth.GetUIDFromContext(c) + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintln(err)) + } + + var isAllowed bool + for _, id := range service.AllowedUsers { + if uid == id { + isAllowed = true + break + } + } + + if !isAllowed { + c.String(http.StatusForbidden, "User %s doesn't have permision to get this service", uid) + return + } + } if err := back.DeleteService(c.Param("serviceName")); err != nil { // Check if error is caused because the service is not found diff --git a/pkg/handlers/logs.go b/pkg/handlers/logs.go index 224e1571..bb62c863 100644 --- a/pkg/handlers/logs.go +++ b/pkg/handlers/logs.go @@ -32,35 +32,15 @@ import ( "k8s.io/client-go/kubernetes" ) +// TODO Try using cookies to avoid excesive calls to the k8s API // + // MakeJobsInfoHandler makes a handler for listing all existing jobs from a service and show their JobInfo func MakeJobsInfoHandler(back types.ServerlessBackend, kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { return func(c *gin.Context) { jobsInfo := make(map[string]*types.JobInfo) - authHeader := c.GetHeader("Authorization") - // Get serviceName serviceName := c.Param("serviceName") - // If is oidc auth get service and check on allowed users - if len(strings.Split(authHeader, "Bearer")) > 1 { - service, _ := back.ReadService(c.Param("serviceName")) - uid, err := auth.GetUIDFromContext(c) - if err != nil { - c.String(http.StatusInternalServerError, fmt.Sprintln(err)) - } - - var isAllowed bool - for _, id := range service.AllowedUsers { - if uid == id { - isAllowed = true - break - } - } - - if !isAllowed { - c.String(http.StatusForbidden, "User %s doesn't have permision to get this service", uid) - return - } - } + isOIDCAuthorised(c, back, serviceName) // List jobs listOpts := metav1.ListOptions{ @@ -124,10 +104,12 @@ func MakeJobsInfoHandler(back types.ServerlessBackend, kubeClientset *kubernetes // TODO refactor // MakeDeleteJobsHandler makes a handler for deleting all jobs created by the provided service. // If 'all' querystring is set to 'true' pending, running and failed jobs will also be deleted -func MakeDeleteJobsHandler(kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { +func MakeDeleteJobsHandler(back types.ServerlessBackend, kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { return func(c *gin.Context) { // Get serviceName and jobName serviceName := c.Param("serviceName") + isOIDCAuthorised(c, back, serviceName) + // Get timestamps querystring (default to false) all, err := strconv.ParseBool(c.DefaultQuery("all", "false")) if err != nil { @@ -167,10 +149,11 @@ func MakeDeleteJobsHandler(kubeClientset *kubernetes.Clientset, namespace string // TODO refactor // MakeGetLogsHandler makes a handler for getting logs from the 'oscar-container' inside the pod created by the specified job -func MakeGetLogsHandler(kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { +func MakeGetLogsHandler(back types.ServerlessBackend, kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { return func(c *gin.Context) { // Get serviceName and jobName serviceName := c.Param("serviceName") + isOIDCAuthorised(c, back, serviceName) jobName := c.Param("jobName") // Get timestamps querystring (default to false) timestamps, err := strconv.ParseBool(c.DefaultQuery("timestamps", "false")) @@ -220,10 +203,11 @@ func MakeGetLogsHandler(kubeClientset *kubernetes.Clientset, namespace string) g // TODO refactor // MakeDeleteJobHandler makes a handler for removing a job -func MakeDeleteJobHandler(kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { +func MakeDeleteJobHandler(back types.ServerlessBackend, kubeClientset *kubernetes.Clientset, namespace string) gin.HandlerFunc { return func(c *gin.Context) { // Get serviceName and jobName serviceName := c.Param("serviceName") + isOIDCAuthorised(c, back, serviceName) jobName := c.Param("jobName") // Get job in order to check if it is associated with the provided serviceName @@ -265,3 +249,28 @@ func MakeDeleteJobHandler(kubeClientset *kubernetes.Clientset, namespace string) c.Status(http.StatusNoContent) } } + +func isOIDCAuthorised(c *gin.Context, back types.ServerlessBackend, serviceName string) { + // If is oidc auth get service and check on allowed users + authHeader := c.GetHeader("Authorization") + if len(strings.Split(authHeader, "Bearer")) > 1 { + service, _ := back.ReadService(c.Param("serviceName")) + uid, err := auth.GetUIDFromContext(c) + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintln(err)) + } + + var isAllowed bool + for _, id := range service.AllowedUsers { + if uid == id { + isAllowed = true + break + } + } + + if !isAllowed { + c.String(http.StatusForbidden, "User %s doesn't have permision to get this service", uid) + return + } + } +} diff --git a/pkg/handlers/read.go b/pkg/handlers/read.go index 1e60eb99..62c7927d 100644 --- a/pkg/handlers/read.go +++ b/pkg/handlers/read.go @@ -30,10 +30,9 @@ import ( // MakeReadHandler makes a handler for reading a service func MakeReadHandler(back types.ServerlessBackend) gin.HandlerFunc { return func(c *gin.Context) { - + service, err := back.ReadService(c.Param("serviceName")) authHeader := c.GetHeader("Authorization") - service, err := back.ReadService(c.Param("serviceName")) if err != nil { // Check if error is caused because the service is not found if errors.IsNotFound(err) || errors.IsGone(err) {