Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions cmd/client/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,16 @@ const (

API_SETTINGS = "/api/settings"
API_SETTINGS_SYSTEM = "/api/settings/system"

API_USER_LIST = "/api/user"
API_USER_DELETE = "/api/user"
API_USER_PROFILE = "/api/user/profile"

API_POLICY_LIST = "/api/policy"
API_POLICY_DELETE = "/api/policy"

API_SERVICE_ACCOUNT_LIST = "/api/serviceaccount"
API_SERVICE_ACCOUNT_CREATE = "/api/serviceaccount/create"
API_SERVICE_ACCOUNT_UPDATE = "/api/serviceaccount/update"
API_SERVICE_ACCOUNT_DELETE = "/api/serviceaccount"
)
29 changes: 28 additions & 1 deletion cmd/client/api/delete.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package api

import "net/http"
import (
"fmt"
"net/http"
)

func (c *Client) DeleteGateway(items ...string) error {
_, err := c.executeJson(API_GATEWAY_DELETE, http.MethodDelete, nil, nil, items, http.StatusOK)
Expand Down Expand Up @@ -66,3 +69,27 @@ func (c *Client) DeleteBackup(items ...string) error {
_, err := c.executeJson(API_BACKUP_DELETE, http.MethodDelete, nil, nil, items, http.StatusOK)
return err
}

func (c *Client) DeleteUser(items ...string) error {
profile, err := c.GetProfile()
if err != nil {
return err
}
for _, id := range items {
if id == profile.ID {
return fmt.Errorf("cannot delete the current user %s", profile.Username)
}
}
_, err = c.executeJson(API_USER_DELETE, http.MethodDelete, nil, nil, items, http.StatusOK)
return err
}

func (c *Client) DeletePolicy(items ...string) error {
_, err := c.executeJson(API_POLICY_DELETE, http.MethodDelete, nil, nil, items, http.StatusOK)
return err
}

func (c *Client) DeleteServiceAccount(items ...string) error {
_, err := c.executeJson(API_SERVICE_ACCOUNT_DELETE, http.MethodDelete, nil, nil, items, http.StatusOK)
return err
}
12 changes: 12 additions & 0 deletions cmd/client/api/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,15 @@ func (c *Client) ListForwardPayload(queryParams map[string]interface{}) (*storag
func (c *Client) ListBackup(queryParams map[string]interface{}) (*storageTY.Result, error) {
return c.listResource(API_BACKUP_LIST, queryParams)
}

func (c *Client) ListUser(queryParams map[string]interface{}) (*storageTY.Result, error) {
return c.listResource(API_USER_LIST, queryParams)
}

func (c *Client) ListPolicy(queryParams map[string]interface{}) (*storageTY.Result, error) {
return c.listResource(API_POLICY_LIST, queryParams)
}

func (c *Client) ListServiceAccount(queryParams map[string]interface{}) (*storageTY.Result, error) {
return c.listResource(API_SERVICE_ACCOUNT_LIST, queryParams)
}
8 changes: 4 additions & 4 deletions cmd/client/api/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (

func (c *Client) Login(username, password, token, expiresIn string) (*handlerTY.JwtTokenResponse, error) {
req := &handlerTY.UserLogin{
Username: username,
Password: password,
SvcToken: token,
ExpiresIn: expiresIn,
Username: username,
Password: password,
ServiceAccountToken: token,
ExpiresIn: expiresIn,
}
res, err := c.executeJson(API_LOGIN, http.MethodPost, nil, nil, req, http.StatusOK)
if err != nil {
Expand Down
47 changes: 28 additions & 19 deletions cmd/client/api/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,18 +217,29 @@ func (c *Client) getByID(api, id string, dest interface{}) (bool, error) {
}

func (c *Client) findResource(api string, filters []storageTY.Filter, dest interface{}) (bool, error) {
items, err := c.findResources(api, filters, 1)
if err != nil || len(items) == 0 {
return false, err
}
if err := utils.MapToStruct(utils.TagNameJSON, items[0], dest); err != nil {
return false, err
}
return true, nil
}

func (c *Client) findResources(api string, filters []storageTY.Filter, limit uint64) ([]map[string]interface{}, error) {
if len(filters) == 0 {
return false, nil
return nil, nil
}
queryParams, err := listQueryParams(filters, 1)
queryParams, err := listQueryParams(filters, limit)
if err != nil {
return false, err
return nil, err
}
result, err := c.listResource(api, queryParams)
if err != nil {
return false, err
return nil, err
}
return decodeFirst(result, dest)
return decodeItems(result)
}

func listQueryParams(filters []storageTY.Filter, limit uint64) (map[string]interface{}, error) {
Expand All @@ -243,25 +254,23 @@ func listQueryParams(filters []storageTY.Filter, limit uint64) (map[string]inter
}, nil
}

func decodeFirst(result *storageTY.Result, dest interface{}) (bool, error) {
func decodeItems(result *storageTY.Result) ([]map[string]interface{}, error) {
if result == nil || result.Data == nil {
return false, nil
}
items, ok := result.Data.([]interface{})
if !ok {
return false, fmt.Errorf("invalid response type:%T", result.Data)
}
if len(items) == 0 {
return false, nil
return nil, nil
}
data, ok := items[0].(map[string]interface{})
raw, ok := result.Data.([]interface{})
if !ok {
return false, fmt.Errorf("invalid item type:%T", items[0])
return nil, fmt.Errorf("invalid response type:%T", result.Data)
}
if err := utils.MapToStruct(utils.TagNameJSON, data, dest); err != nil {
return false, err
items := make([]map[string]interface{}, 0, len(raw))
for _, item := range raw {
data, ok := item.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("invalid item type:%T", item)
}
items = append(items, data)
}
return true, nil
return items, nil
}

func idFilters(id string) []storageTY.Filter {
Expand Down
131 changes: 131 additions & 0 deletions cmd/client/api/service_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package api

import (
"fmt"
"net/http"
"strings"

"github.com/mycontroller-org/server/v2/pkg/json"
"github.com/mycontroller-org/server/v2/pkg/types"
svcAccountTY "github.com/mycontroller-org/server/v2/pkg/types/service_account"
"github.com/mycontroller-org/server/v2/pkg/utils"
storageTY "github.com/mycontroller-org/server/v2/plugin/database/storage/types"
)

func (c *Client) CreateServiceAccount(account *svcAccountTY.ServiceAccount) (*svcAccountTY.CreateAccountResponse, error) {
res, err := c.executeJson(API_SERVICE_ACCOUNT_CREATE, http.MethodPost, nil, nil, account, http.StatusOK)
if err != nil {
return nil, err
}
created := &svcAccountTY.CreateAccountResponse{}
if err := json.Unmarshal(res.Body, created); err != nil {
return nil, err
}
return created, nil
}

func (c *Client) UpdateServiceAccount(account *svcAccountTY.ServiceAccount) error {
_, err := c.executeJson(API_SERVICE_ACCOUNT_UPDATE, http.MethodPost, nil, nil, account, http.StatusOK)
return err
}

func (c *Client) FindServiceAccount(id, name, userRef string) (*svcAccountTY.ServiceAccount, error) {
if id != "" {
item := &svcAccountTY.ServiceAccount{}
found, err := c.findResource(API_SERVICE_ACCOUNT_LIST, idFilters(id), item)
if err != nil {
return nil, err
}
if found {
if userRef != "" && !serviceAccountMatchesUser(item, c.resolveUserRef(userRef), userRef) {
return nil, nil
}
return item, nil
}
}
if name == "" {
return nil, nil
}
items, err := c.FindServiceAccounts(name, userRef)
if err != nil {
return nil, err
}
switch len(items) {
case 0:
return nil, nil
case 1:
return &items[0], nil
default:
users := make([]string, 0, len(items))
for _, item := range items {
label := item.Username
if label == "" {
label = item.UserID
}
users = append(users, label)
}
return nil, fmt.Errorf("multiple service accounts named %s (users: %s); specify --user", name, strings.Join(users, ", "))
}
}

func (c *Client) FindServiceAccounts(name, userRef string) ([]svcAccountTY.ServiceAccount, error) {
filters := []storageTY.Filter{equalFilter(types.KeyName, name)}
if userID := c.resolveUserRef(userRef); userID != "" {
filters = append(filters, equalFilter(types.KeyUserID, userID))
}
raw, err := c.findResources(API_SERVICE_ACCOUNT_LIST, filters, 1000)
if err != nil {
return nil, err
}
items := make([]svcAccountTY.ServiceAccount, 0, len(raw))
for _, data := range raw {
item := svcAccountTY.ServiceAccount{}
if err := utils.MapToStruct(utils.TagNameJSON, data, &item); err != nil {
return nil, err
}
items = append(items, item)
}
return items, nil
}

func serviceAccountMatchesUser(item *svcAccountTY.ServiceAccount, userID, userRef string) bool {
if item == nil {
return false
}
if userID != "" && (item.UserID == userID || strings.EqualFold(item.Username, userRef)) {
return true
}
return strings.EqualFold(item.Username, userRef) || item.UserID == userRef
}

func (c *Client) resolveUserRef(userRef string) string {
userRef = strings.TrimSpace(userRef)
if userRef == "" {
return ""
}
user, err := c.FindUser(userRef, userRef)
if err != nil || user == nil {
return userRef
}
return user.ID
}

func (c *Client) ResolveServiceAccountIDs(selectors []string, userRef string) ([]string, error) {
ids := make([]string, 0, len(selectors))
missing := make([]string, 0)
for _, selector := range selectors {
item, err := c.FindServiceAccount(selector, selector, userRef)
if err != nil {
return ids, err
}
if item == nil {
missing = append(missing, selector)
continue
}
ids = append(ids, item.ID)
}
if len(missing) > 0 {
return ids, fmt.Errorf("service-account(s) not present: %s", strings.Join(missing, ", "))
}
return ids, nil
}
Loading