Skip to content

Commit

Permalink
Changes for OSCAR MinIO user
Browse files Browse the repository at this point in the history
  • Loading branch information
catttam committed Jan 31, 2024
1 parent b568d5f commit 62de966
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 118 deletions.
139 changes: 81 additions & 58 deletions pkg/handlers/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,70 +46,90 @@ var errInput = errors.New("unrecognized input (valid inputs are MinIO and dCache

// Custom logger
var createLogger = log.New(os.Stdout, "[CREATE] ", log.Flags())
var isAdminUser = false

// MakeCreateHandler makes a handler for creating services
func MakeCreateHandler(cfg *types.Config, back types.ServerlessBackend) gin.HandlerFunc {
return func(c *gin.Context) {
var service types.Service
authHeader := c.GetHeader("Authorization")
if len(strings.Split(authHeader, "Bearer")) > 0 {
isAdminUser = true
}

uidOrigin, uidExists := c.Get("uidOrigin")
mcUntyped, mcExists := c.Get("multitenancyConfig")
// Check service values and set defaults
checkValues(&service, cfg)

if !mcExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing multitenancy config"))
}
if !uidExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing EGI user uid"))
}
///////////////////////////////////
////////////// here ///////////////
///////////////////////////////////
// Check if users in allowed_users have a MinIO associated user
minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg)

mc, mcParsed := mcUntyped.(*auth.MultitenancyConfig)
uid, uidParsed := uidOrigin.(string)
// Service is created by an EGI user
if !isAdminUser {

if !mcParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing multitenancy config: %v", mcParsed))
return
}
uidOrigin, uidExists := c.Get("uidOrigin")
mcUntyped, mcExists := c.Get("multitenancyConfig")

createLogger.Println("Multitenancy config: ", mc)
if !mcExists {
c.String(http.StatusInternalServerError, "Missing multitenancy config")
}

if !uidParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing uid origin: %v", uidParsed))
return
}
if !uidExists {
c.String(http.StatusInternalServerError, "Missing EGI user uid")
}

if err := c.ShouldBindJSON(&service); err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("The service specification is not valid: %v", err))
return
}
mc, mcParsed := mcUntyped.(*auth.MultitenancyConfig)
uid, uidParsed := uidOrigin.(string)

// Check service values and set defaults
checkValues(&service, cfg)
full_uid := auth.FormatUID(uid)
// Check if the service VO is present on the cluster VO's and if the user creating the service is enrrolled in such
if service.VO != "" {
for _, vo := range cfg.OIDCGroups {
if vo == service.VO {
authHeader := c.GetHeader("Authorization")
err := checkIdentity(&service, cfg, authHeader)
if err != nil {
c.String(http.StatusBadRequest, fmt.Sprintln(err))
if !mcParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing multitenancy config: %v", mcParsed))
return
}

createLogger.Println("Multitenancy config: ", mc)

if !uidParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing uid origin: %v", uidParsed))
return
}

if err := c.ShouldBindJSON(&service); err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("The service specification is not valid: %v", err))
return
}

full_uid := auth.FormatUID(uid)
// Check if the service VO is present on the cluster VO's and if the user creating the service is enrrolled in such
if service.VO != "" {
for _, vo := range cfg.OIDCGroups {
if vo == service.VO {
authHeader := c.GetHeader("Authorization")
err := checkIdentity(&service, cfg, authHeader)
if err != nil {
c.String(http.StatusBadRequest, fmt.Sprintln(err))
}

// If AllowedUsers is empty don't add uid
if len(service.AllowedUsers) == 0 {
service.Labels["uid"] = full_uid[0:8]
service.AllowedUsers = append(service.AllowedUsers, uid)
createLogger.Println("Creating service for user: ", uid)
}
break
}
service.Labels["uid"] = full_uid[0:8]
service.AllowedUsers = append(service.AllowedUsers, uid)
createLogger.Println("Creating service for user: ", uid)
break
}
}
}

// Check if users in allowed_users have a MinIO associated user
minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg)
uids := mc.CheckUsersInCache(service.AllowedUsers)
if len(uids) > 0 {
for _, uid := range uids {
sk, _ := auth.GenerateRandomKey(8)
minIOAdminClient.CreateMinIOUser(uid, sk)
mc.CreateSecretForOIDC(uid, sk)
if len(service.AllowedUsers) == 0 {
uids := mc.CheckUsersInCache(service.AllowedUsers)
if len(uids) > 0 {
for _, uid := range uids {
sk, _ := auth.GenerateRandomKey(8)
minIOAdminClient.CreateMinIOUser(uid, sk)
mc.CreateSecretForOIDC(uid, sk)
}
}
}
}

Expand Down Expand Up @@ -271,16 +291,20 @@ func createBuckets(service *types.Service, cfg *types.Config, minIOAdminClient *
}

// Create group for the service and add users
// TODO error control
err = minIOAdminClient.CreateServiceGroup(splitPath[0])
if err != nil {
return fmt.Errorf("error creating service group for bucket %s: %v", splitPath[0], err)
}
err = minIOAdminClient.AddUserToGroup(allowed_users, splitPath[0])
if err != nil {
return err
if !isAdminUser {
if len(allowed_users) < 1 {
err = minIOAdminClient.AddServiceToAllUsersGroup(splitPath[0])
} else {
err = minIOAdminClient.CreateServiceGroup(splitPath[0])
if err != nil {
return fmt.Errorf("error creating service group for bucket %s: %v", splitPath[0], err)
}
err = minIOAdminClient.AddUserToGroup(allowed_users, splitPath[0])
if err != nil {
return err
}
}
}

// Create folder(s)
if len(splitPath) == 2 {
// Add "/" to the end of the key in order to create a folder
Expand All @@ -298,7 +322,6 @@ func createBuckets(service *types.Service, cfg *types.Config, minIOAdminClient *
if err := enableInputNotification(s3Client, service.GetMinIOWebhookARN(), in); err != nil {
return err
}

}

// Create output buckets
Expand Down
41 changes: 25 additions & 16 deletions pkg/handlers/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package handlers
import (
"fmt"
"net/http"
"strings"

"github.com/gin-gonic/gin"
"github.com/grycap/oscar/v2/pkg/types"
Expand All @@ -27,34 +28,42 @@ import (
// MakeListHandler makes a handler for listing services
func MakeListHandler(back types.ServerlessBackend) gin.HandlerFunc {
return func(c *gin.Context) {

authHeader := c.GetHeader("Authorization")

services, err := back.ListServices()
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}

uidOrigin, uidExists := c.Get("uidOrigin")
if !uidExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing EGI user uid"))
}
if len(strings.Split(authHeader, "Bearer")) > 0 {
uidOrigin, uidExists := c.Get("uidOrigin")
if !uidExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing EGI user uid"))
}

uid, uidParsed := uidOrigin.(string)
uid, uidParsed := uidOrigin.(string)

if !uidParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing uid origin: %v", uidParsed))
return
}
if !uidParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing uid origin: %v", uidParsed))
return
}

var allowedServicesForUser []*types.Service
for _, service := range services {
for _, id := range service.AllowedUsers {
if uid == id {
allowedServicesForUser = append(allowedServicesForUser, service)
break
var allowedServicesForUser []*types.Service
for _, service := range services {
for _, id := range service.AllowedUsers {
if uid == id {
allowedServicesForUser = append(allowedServicesForUser, service)
break
}
}
}

c.JSON(http.StatusOK, allowedServicesForUser)
} else {
c.JSON(http.StatusOK, services)
}

c.JSON(http.StatusOK, allowedServicesForUser)
}
}
44 changes: 24 additions & 20 deletions pkg/handlers/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package handlers
import (
"fmt"
"net/http"
"strings"

"github.com/gin-gonic/gin"
"github.com/grycap/oscar/v2/pkg/types"
Expand All @@ -28,8 +29,10 @@ 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) {
Expand All @@ -39,30 +42,31 @@ func MakeReadHandler(back types.ServerlessBackend) gin.HandlerFunc {
}
return
}
if len(strings.Split(authHeader, "Bearer")) > 0 {
uidOrigin, uidExists := c.Get("uidOrigin")
if !uidExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing EGI user uid"))
}

uidOrigin, uidExists := c.Get("uidOrigin")
if !uidExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing EGI user uid"))
}

uid, uidParsed := uidOrigin.(string)
uid, uidParsed := uidOrigin.(string)

if !uidParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing uid origin: %v", uidParsed))
return
}
if !uidParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing uid origin: %v", uidParsed))
return
}

var isAllowed bool
for _, id := range service.AllowedUsers {
if uid == id {
isAllowed = true
break
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 !isAllowed {
c.String(http.StatusForbidden, "User %s doesn't have permision to get this service", uid)
return
}
}

c.JSON(http.StatusOK, service)
Expand Down
50 changes: 27 additions & 23 deletions pkg/handlers/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,6 @@ func MakeUpdateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand
return
}

mcUntyped, mcExists := c.Get("multitenancyConfig")

if !mcExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing multitenancy config"))
}

mc, mcParsed := mcUntyped.(auth.MultitenancyConfig)

if !mcParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing multitenancy config: %v", mcParsed))
}

// Check if users in allowed_users have a MinIO associated user
minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg)
uids := mc.CheckUsersInCache(newService.AllowedUsers)
if len(uids) == 0 {
for _, uid := range uids {
sk, _ := auth.GenerateRandomKey(8)
minIOAdminClient.CreateMinIOUser(uid, sk)
mc.CreateSecretForOIDC(uid, sk)
}
}

// Check service values and set defaults
checkValues(&newService, cfg)

Expand Down Expand Up @@ -91,6 +68,33 @@ func MakeUpdateHandler(cfg *types.Config, back types.ServerlessBackend) gin.Hand
}
}

minIOAdminClient, _ := utils.MakeMinIOAdminClient(cfg)
if !isAdminUser {
mcUntyped, mcExists := c.Get("multitenancyConfig")

if !mcExists {
c.String(http.StatusInternalServerError, fmt.Sprintln("Missing multitenancy config"))
}

mc, mcParsed := mcUntyped.(auth.MultitenancyConfig)

if !mcParsed {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error parsing multitenancy config: %v", mcParsed))
}

// Check if users in allowed_users have a MinIO associated user
if len(newService.AllowedUsers) == 0 {
uids := mc.CheckUsersInCache(newService.AllowedUsers)
if len(uids) == 0 {
for _, uid := range uids {
sk, _ := auth.GenerateRandomKey(8)
minIOAdminClient.CreateMinIOUser(uid, sk)
mc.CreateSecretForOIDC(uid, sk)
}
}
}
}

// Update the service
if err := back.UpdateService(newService); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("Error updating the service: %v", err))
Expand Down
6 changes: 5 additions & 1 deletion pkg/utils/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@ func CustomAuth(cfg *types.Config, kubeClientset *kubernetes.Clientset) gin.Hand
cfg.Username: cfg.Password,
})

//TODO Initialize MinIO client and create all_users_group
minIOAdminClient, err := utils.MakeMinIOAdminClient(cfg)
if err != nil {
// TODO manage error
}

// Slice to add default user to all users group on MinIO
var oscarUser []string
oscarUser[0] = "console"

minIOAdminClient.CreateAllUsersGroup()
minIOAdminClient.AddUserToGroup(oscarUser, "all_users_group")

oidcHandler := getOIDCMiddleware(kubeClientset, minIOAdminClient, cfg.OIDCIssuer, cfg.OIDCSubject, cfg.OIDCGroups)
return func(c *gin.Context) {
Expand Down
Loading

0 comments on commit 62de966

Please sign in to comment.