Skip to content

Commit

Permalink
feat: Refactoring admin APIs: changes i/o data transfer encoding to x…
Browse files Browse the repository at this point in the history
…ml, implements traditional aws-like error handling, adds admin role checker middleware. Refactoring admin CLI actions to handle aws-like error responses
  • Loading branch information
0x180 committed Oct 25, 2024
1 parent c02c177 commit c6359a7
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 433 deletions.
17 changes: 17 additions & 0 deletions auth/iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ const (
RoleUserPlus Role = "userplus"
)

func (r Role) IsValid() bool {
switch r {
case RoleAdmin:
return true
case RoleUser:
return true
case RoleUserPlus:
return true
default:
return false
}
}

// Account is a gateway IAM account
type Account struct {
Access string `json:"access"`
Expand All @@ -37,6 +50,10 @@ type Account struct {
GroupID int `json:"groupID"`
}

type ListUserAccountsResult struct {
Accounts []Account
}

// Mutable props, which could be changed when updating an IAM account
type MutableProps struct {
Secret *string `json:"secret"`
Expand Down
58 changes: 31 additions & 27 deletions cmd/versitygw/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"net/http"
Expand All @@ -29,6 +29,7 @@ import (

"github.com/aws/aws-sdk-go-v2/aws"
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
"github.com/aws/smithy-go"
"github.com/urfave/cli/v2"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3response"
Expand Down Expand Up @@ -224,19 +225,19 @@ func createUser(ctx *cli.Context) error {
GroupID: groupID,
}

accJson, err := json.Marshal(acc)
accxml, err := xml.Marshal(acc)
if err != nil {
return fmt.Errorf("failed to parse user data: %w", err)
}

req, err := http.NewRequest(http.MethodPatch, fmt.Sprintf("%v/create-user", adminEndpoint), bytes.NewBuffer(accJson))
req, err := http.NewRequest(http.MethodPatch, fmt.Sprintf("%v/create-user", adminEndpoint), bytes.NewBuffer(accxml))
if err != nil {
return fmt.Errorf("failed to send the request: %w", err)
}

signer := v4.NewSigner()

hashedPayload := sha256.Sum256(accJson)
hashedPayload := sha256.Sum256(accxml)
hexPayload := hex.EncodeToString(hashedPayload[:])

req.Header.Set("X-Amz-Content-Sha256", hexPayload)
Expand All @@ -260,11 +261,9 @@ func createUser(ctx *cli.Context) error {
}

if resp.StatusCode >= 400 {
return fmt.Errorf("%s", body)
return parseApiError(body)
}

fmt.Printf("%s\n", body)

return nil
}

Expand Down Expand Up @@ -305,11 +304,9 @@ func deleteUser(ctx *cli.Context) error {
}

if resp.StatusCode >= 400 {
return fmt.Errorf("%s", body)
return parseApiError(body)
}

fmt.Printf("%s\n", body)

return nil
}

Expand All @@ -326,19 +323,19 @@ func updateUser(ctx *cli.Context) error {
props.GroupID = &groupId
}

propsJSON, err := json.Marshal(props)
propsxml, err := xml.Marshal(props)
if err != nil {
return fmt.Errorf("failed to parse user attributes: %w", err)
}

req, err := http.NewRequest(http.MethodPatch, fmt.Sprintf("%v/update-user?access=%v", adminEndpoint, access), bytes.NewBuffer(propsJSON))
req, err := http.NewRequest(http.MethodPatch, fmt.Sprintf("%v/update-user?access=%v", adminEndpoint, access), bytes.NewBuffer(propsxml))
if err != nil {
return fmt.Errorf("failed to send the request: %w", err)
}

signer := v4.NewSigner()

hashedPayload := sha256.Sum256(propsJSON)
hashedPayload := sha256.Sum256(propsxml)
hexPayload := hex.EncodeToString(hashedPayload[:])

req.Header.Set("X-Amz-Content-Sha256", hexPayload)
Expand All @@ -362,11 +359,9 @@ func updateUser(ctx *cli.Context) error {
}

if resp.StatusCode >= 400 {
return fmt.Errorf("%s", body)
return parseApiError(body)
}

fmt.Printf("%s\n", body)

return nil
}

Expand Down Expand Up @@ -402,15 +397,15 @@ func listUsers(ctx *cli.Context) error {
}

if resp.StatusCode >= 400 {
return fmt.Errorf("%s", body)
return parseApiError(body)
}

var accs []auth.Account
if err := json.Unmarshal(body, &accs); err != nil {
var accs auth.ListUserAccountsResult
if err := xml.Unmarshal(body, &accs); err != nil {
return err
}

printAcctTable(accs)
printAcctTable(accs.Accounts)

return nil
}
Expand Down Expand Up @@ -469,11 +464,9 @@ func changeBucketOwner(ctx *cli.Context) error {
}

if resp.StatusCode >= 400 {
return fmt.Errorf("%s", body)
return parseApiError(body)
}

fmt.Println(string(body))

return nil
}

Expand Down Expand Up @@ -521,15 +514,26 @@ func listBuckets(ctx *cli.Context) error {
}

if resp.StatusCode >= 400 {
return fmt.Errorf("%s", body)
return parseApiError(body)
}

var buckets []s3response.Bucket
if err := json.Unmarshal(body, &buckets); err != nil {
var result s3response.ListBucketsResult
if err := xml.Unmarshal(body, &result); err != nil {
return err
}

printBuckets(buckets)
printBuckets(result.Buckets)

return nil
}

func parseApiError(body []byte) error {
var apiErr smithy.GenericAPIError
err := xml.Unmarshal(body, &apiErr)
if err != nil {
apiErr.Code = "InternalServerError"
apiErr.Message = err.Error()
}

return &apiErr
}
8 changes: 8 additions & 0 deletions metrics/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ var (
ActionPutBucketOwnershipControls = "s3_PutBucketOwnershipControls"
ActionGetBucketOwnershipControls = "s3_GetBucketOwnershipControls"
ActionDeleteBucketOwnershipControls = "s3_DeleteBucketOwnershipControls"

// Admin actions
ActionAdminCreateUser = "admin_CreateUser"
ActionAdminUpdateUser = "admin_UpdateUser"
ActionAdminDeleteUser = "admin_DeleteUser"
ActionAdminChangeBucketOwner = "admin_ChangeBucketOwner"
ActionAdminListUsers = "admin_ListUsers"
ActionAdminListBuckets = "admin_ListBuckets"
)

func init() {
Expand Down
3 changes: 3 additions & 0 deletions s3api/admin-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ func NewAdminServer(app *fiber.App, be backend.Backend, root middlewares.RootUse
app.Use(middlewares.VerifyV4Signature(root, iam, l, nil, region, false))
app.Use(middlewares.VerifyMD5Body(l))

// Admin role checker
app.Use(middlewares.IsAdmin(l))

server.router.Init(app, be, iam, l)

return server
Expand Down
Loading

0 comments on commit c6359a7

Please sign in to comment.