diff --git a/backend/auth/iam.go b/backend/auth/iam.go index 3d9b909c..74ffb166 100644 --- a/backend/auth/iam.go +++ b/backend/auth/iam.go @@ -70,10 +70,17 @@ func (c *AccountsCache) updateAccounts() error { return nil } +func (c *AccountsCache) deleteAccount(access string) { + c.mu.Lock() + defer c.mu.Unlock() + delete(c.Accounts, access) +} + type IAMService interface { GetIAMConfig() (*IAMConfig, error) CreateAccount(access string, account *Account) error GetUserAccount(access string) *Account + DeleteUserAccount(access string) error } type IAMServiceUnsupported struct { @@ -135,3 +142,36 @@ func (s IAMServiceUnsupported) GetUserAccount(access string) *Account { return acc } + +func (s IAMServiceUnsupported) DeleteUserAccount(access string) error { + var data IAMConfig + + file, err := os.ReadFile("users.json") + if err != nil { + return fmt.Errorf("unable to read config file: %w", err) + } + + if err := json.Unmarshal(file, &data); err != nil { + return fmt.Errorf("failed to parse the config file: %w", err) + } + + _, ok := data.AccessAccounts[access] + if !ok { + return fmt.Errorf("invalid access for the user: user does not exist") + } + + delete(data.AccessAccounts, access) + + updatedJSON, err := json.MarshalIndent(data, "", " ") + if err != nil { + return fmt.Errorf("failed to parse the data: %w", err) + } + + if err := os.WriteFile("users.json", updatedJSON, 0644); err != nil { + return fmt.Errorf("failed to saved the changes: %w", err) + } + + s.accCache.deleteAccount(access) + + return nil +} diff --git a/cmd/versitygw/admin.go b/cmd/versitygw/admin.go index 4a699cb2..c713a01d 100644 --- a/cmd/versitygw/admin.go +++ b/cmd/versitygw/admin.go @@ -73,6 +73,19 @@ func adminCommand() *cli.Command { }, }, }, + { + Name: "delete-user", + Usage: "Delete a user", + Action: deleteUser, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "access", + Usage: "access value for the user to be deleted", + Required: true, + Aliases: []string{"a"}, + }, + }, + }, }, Flags: []cli.Flag{ // TODO: create a configuration file for this @@ -143,3 +156,43 @@ func createUser(ctx *cli.Context) error { return nil } + +func deleteUser(ctx *cli.Context) error { + access := ctx.String("access") + if access == "" { + return fmt.Errorf("invalid input parameter for the new user") + } + + req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://localhost:7070/delete-user?access=%v", access), nil) + if err != nil { + return fmt.Errorf("failed to send the request: %w", err) + } + + signer := v4.NewSigner() + + hashedPayload := sha256.Sum256([]byte{}) + hexPayload := hex.EncodeToString(hashedPayload[:]) + + req.Header.Set("X-Amz-Content-Sha256", hexPayload) + + signErr := signer.SignHTTP(req.Context(), aws.Credentials{AccessKeyID: adminAccess, SecretAccessKey: adminSecret}, req, hexPayload, "s3", adminRegion, time.Now()) + if signErr != nil { + return fmt.Errorf("failed to sign the request: %w", err) + } + + client := http.Client{} + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("failed to send the request: %w", err) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + fmt.Printf("%s", body) + + return nil +} diff --git a/s3api/controllers/admin.go b/s3api/controllers/admin.go index 0abbabf1..e16ea083 100644 --- a/s3api/controllers/admin.go +++ b/s3api/controllers/admin.go @@ -47,3 +47,19 @@ func (c AdminController) CreateUser(ctx *fiber.Ctx) error { ctx.SendString("The user has been created successfully") return nil } + +func (c AdminController) DeleteUser(ctx *fiber.Ctx) error { + access := ctx.Query("access") + requesterRole := ctx.Locals("role") + if requesterRole != "admin" { + return fmt.Errorf("access denied: only admin users have access to this resource") + } + + err := c.IAMService.DeleteUserAccount(access) + if err != nil { + return err + } + + ctx.SendString("The user has been created successfully") + return nil +} diff --git a/s3api/router.go b/s3api/router.go index 637052f4..13d881f4 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -29,6 +29,9 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ // TODO: think of better routing system app.Post("/create-user", adminController.CreateUser) + + // Admin Delete api + app.Delete("/delete-user", adminController.DeleteUser) // ListBuckets action app.Get("/", s3ApiController.ListBuckets)