727 lines
24 KiB
Go
727 lines
24 KiB
Go
package controllers
|
|
|
|
import (
|
|
"apiserver/common"
|
|
"apiserver/models"
|
|
"apiserver/services"
|
|
"apiserver/store"
|
|
logger "apiserver/utils"
|
|
utils "apiserver/utils"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type RoleController struct{}
|
|
|
|
func (rc *RoleController) GetRolesInfo(ctx *gin.Context) {
|
|
logger.Debug("Enter GetRolesInfo() function from ", zap.String("client_ip", ctx.ClientIP()))
|
|
|
|
var fields []string
|
|
filters := make([]utils.FilterCondition, 0)
|
|
sortOrders := make([]utils.SortOrder, 0)
|
|
uniqueFlag := false
|
|
|
|
// ---- check parameters ----
|
|
for param := range ctx.Request.URL.Query() {
|
|
if !utils.ContainsField(utils.SupportedQueryParams, param) &&
|
|
!utils.ContainsField(utils.TypeQueryParams, param) &&
|
|
!utils.ContainsField(utils.UniqueQueryParams, param) {
|
|
err := errors.New("invalid role info query parameters of : " + param)
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Get query parameters
|
|
typeStr := ctx.Query("type") // type=builtin/all
|
|
filterStr := ctx.Query("filter")
|
|
fieldsStr := ctx.Query("fields")
|
|
sortStr := ctx.Query("sort") // sort=role_name:asc
|
|
pagetokenStr := ctx.Query("page_token") // page_token=Aafjakjf0023A
|
|
limitStr := ctx.Query("limit") // eg: limit=100
|
|
uniqueStr := ctx.Query("unique")
|
|
|
|
logger.Debug("Role query values are:",
|
|
zap.String("typeStr", typeStr),
|
|
zap.String("fieldsStr", fieldsStr),
|
|
zap.String("filterStr", filterStr),
|
|
zap.String("sortStr", sortStr),
|
|
zap.String("limitStr", limitStr),
|
|
zap.String("pagetokenStr", pagetokenStr))
|
|
|
|
// ---- 1. check type ----
|
|
typeValue, err := utils.ParseType(typeStr, models.RolesAvailableTypes)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
logger.Debug("GetRolesInfo typeValue is ", zap.String("typeValue", typeValue))
|
|
|
|
var rqueryReply []utils.OrderMap
|
|
var pagetoken string
|
|
if typeValue != "builtin" {
|
|
|
|
// ---- 2. check limit value ----
|
|
limit, err := utils.ParseLimit(limitStr)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// ---- 3. check filter ----
|
|
if filterStr != "" {
|
|
filters = utils.ParseFilters(filterStr)
|
|
if filters == nil {
|
|
err := errors.New("filter " + filterStr + " has syntax error")
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
for _, filter := range filters {
|
|
if !utils.ContainsField(models.ROLE_SUPPORT_FILTERS, filter.Field) {
|
|
err := errors.New("unsupported filter: " + filter.Field)
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
} else {
|
|
filterStr = filter.Value
|
|
}
|
|
}
|
|
|
|
// check token
|
|
token := ctx.GetHeader("Authorization")
|
|
submitUser, err := GetUsernameFromToken(token)
|
|
if err != nil {
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// check rbac
|
|
permission, err := GetRequireResourcePermission(submitUser, "rbac:view")
|
|
|
|
logger.Debug("get role info for rbac:view permission:", zap.Any("permission", permission))
|
|
if permission.DomainType != models.DomainTypeAll {
|
|
// only query self roles list info
|
|
userSelfRoles := store.GetUserRoleNames(submitUser)
|
|
// if submit_user is not specified, use query request submission user
|
|
var findSelfRole bool = false
|
|
var reset_filterRole string
|
|
for _, filter := range filters {
|
|
if filter.Field == "role_name" {
|
|
filterRoles := strings.Split(filter.Value, ",")
|
|
for _, filterRole := range filterRoles {
|
|
filterRole = strings.TrimSpace(filterRole)
|
|
if !utils.ContainsField(models.BUILTIN_ROLE_NAMES, filterRole) {
|
|
if utils.ContainsField(userSelfRoles, filterRole) {
|
|
findSelfRole = true
|
|
reset_filterRole = filterRole + ","
|
|
}
|
|
} else {
|
|
findSelfRole = true
|
|
}
|
|
}
|
|
if !findSelfRole {
|
|
err := errors.New("no permission")
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
if filterStr == "" {
|
|
filters = append(filters, utils.FilterCondition{
|
|
Field: "role_name",
|
|
Operator: "in",
|
|
Value: strings.Join(userSelfRoles, ","),
|
|
})
|
|
} else {
|
|
filters = append(filters, utils.FilterCondition{
|
|
Field: "role_name",
|
|
Operator: "in",
|
|
Value: reset_filterRole,
|
|
})
|
|
}
|
|
}
|
|
logger.Debug("before call ConvertToNewFilter filters:", zap.Any("filters", filters))
|
|
var role models.RoleInfo
|
|
filtercds, err := utils.ConvertToNewFilter(filters, &role)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// ---- 4. check sort ----
|
|
if sortStr == "" {
|
|
logger.Debug("sort is not specified, set sort=role_name:asc as default")
|
|
sortStr = "role_name:asc"
|
|
}
|
|
sorts, err := utils.ParseSortParam(sortStr, models.ROLE_SUPPORT_SORT)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// ---- 5. handle fields ----
|
|
if fieldsStr != "" {
|
|
fields = utils.ParseFields(fieldsStr)
|
|
found := false
|
|
// verify the fields is in supported list
|
|
supportedFields := utils.GetSupportedFields(models.RoleFields{})
|
|
logger.Debug("role supportedFields: %v", zap.Any("supportedFields", supportedFields))
|
|
for _, field := range fields {
|
|
if !utils.ContainsField(supportedFields, field) {
|
|
err := errors.New("unsupported query field: " + field)
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
// if user not specify role_name in fields, add role_name as default field.
|
|
if field == "role_name" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
logger.Debug("user doesn't specify role name in query fields, add it.")
|
|
fields = append(fields, "role_name")
|
|
}
|
|
} else {
|
|
fields = models.ROLE_DEFAULT_COLUMN
|
|
}
|
|
|
|
// -- 6. check unique value --
|
|
uniqueFlag = utils.ParseUnique(uniqueStr)
|
|
if uniqueFlag {
|
|
if fieldsStr == "" || fieldsStr != "role_name" {
|
|
err := errors.New("when unique=true is specified, fields must be set to role_name")
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
limit = 0
|
|
}
|
|
// ---- 7. check paging ---
|
|
pagetokenStr = strings.TrimSpace(pagetokenStr)
|
|
if pagetokenStr != "" {
|
|
pagetokenStr, err = utils.ParsePageToken(pagetokenStr)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
found := false
|
|
for _, sortent := range sorts {
|
|
if sortent.Column == "role_name" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
sorts = append(sorts, utils.SortOrder{
|
|
Column: "role_name",
|
|
Ascending: true,
|
|
})
|
|
}
|
|
|
|
//check all sort column is in fields
|
|
err = utils.CheckAllMapKeyInList(sorts, fields)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
sortOrders = sorts
|
|
|
|
queryOpts, err := utils.BuildQueryOptions(filtercds, nil, sortOrders, limit, pagetokenStr)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.ERROR_CODE, common.ERROR_QUERY_RESINFO_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
rqueryReply, pagetoken, err = services.QueryData(services.TableRolePermission, queryOpts, fields)
|
|
if err != nil {
|
|
logger.Error("Failed to query role info.", zap.Error(err))
|
|
ReturnError(ctx, common.ERROR_CODE, common.ERROR_QUEUR_ROLEINFO_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
logger.Debug("the role info query reply:", zap.Any("rqueryReply", rqueryReply),
|
|
zap.String("pagetoken", pagetoken))
|
|
}
|
|
//convert to readable string.
|
|
var queryResult utils.QueryResult
|
|
if typeValue == "builtin" || typeValue == "all" {
|
|
filterStr = "all"
|
|
}
|
|
builtinResult := processBuiltinRoles(make(map[string]utils.OrderMap), fieldsStr, filterStr)
|
|
dbResult := processRoleData(rqueryReply, uniqueFlag, pagetoken)
|
|
if builtinResult.Count > 0 {
|
|
pagetoken = strings.TrimSpace(pagetoken)
|
|
if pagetoken != "" {
|
|
queryResult.Rows = dbResult.Rows
|
|
queryResult.Count = dbResult.Count
|
|
queryResult.Pagetoken = dbResult.Pagetoken
|
|
} else {
|
|
queryResult.Rows = append(builtinResult.Rows, dbResult.Rows...)
|
|
queryResult.Count = builtinResult.Count + dbResult.Count
|
|
queryResult.Pagetoken = dbResult.Pagetoken
|
|
}
|
|
} else {
|
|
queryResult.Rows = dbResult.Rows
|
|
queryResult.Count = dbResult.Count
|
|
queryResult.Pagetoken = dbResult.Pagetoken
|
|
}
|
|
ReturnSuccess(ctx, common.SUCCESS_CODE, common.SUCCESS_MSG, queryResult)
|
|
}
|
|
|
|
func processRoleData(rows []utils.OrderMap, unique bool, pageToken string) utils.QueryResult {
|
|
// Map to track seen role names for deduplication when field is specified
|
|
seenRoleNames := make(map[string]bool)
|
|
var processedRows []utils.OrderMap
|
|
|
|
for _, row := range rows {
|
|
roleName, _ := row.Data["role_name"].(string)
|
|
|
|
// Deduplicate role_name when field parameter is not empty
|
|
if unique {
|
|
if seenRoleNames[roleName] {
|
|
continue // Skip duplicate role names
|
|
}
|
|
seenRoleNames[roleName] = true
|
|
|
|
row1 := utils.OrderMap{
|
|
Fields: []string{"role_name"},
|
|
Data: map[string]interface{}{
|
|
"role_name": roleName,
|
|
},
|
|
}
|
|
row.Data = row1.Data
|
|
}
|
|
|
|
// Process JSONBR fields (keep existing logic)
|
|
for _, jsonbField := range models.JSONBRFields {
|
|
if v, exist := row.Data[jsonbField]; exist {
|
|
if strValue, ok := v.(string); ok {
|
|
if jsonbData, err := utils.ParseJSONB(strValue); err == nil {
|
|
row.Data[jsonbField] = jsonbData
|
|
} else {
|
|
logger.Error("Failed to parse role info JSONB field.", zap.Error(err))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
processedRows = append(processedRows, row)
|
|
}
|
|
|
|
return utils.QueryResult{
|
|
Rows: processedRows,
|
|
Count: len(processedRows),
|
|
Pagetoken: pageToken,
|
|
}
|
|
}
|
|
|
|
func processBuiltinRoles(rolePermissions map[string]utils.OrderMap, field string, filter string) utils.QueryResult {
|
|
var resultRows []utils.OrderMap
|
|
for _, roleName := range models.BUILTIN_ROLE_NAMES {
|
|
if filter == roleName || filter == "all" {
|
|
if field != "" {
|
|
row1 := utils.OrderMap{
|
|
Fields: []string{"role_name"},
|
|
Data: map[string]interface{}{
|
|
"role_name": roleName,
|
|
},
|
|
}
|
|
resultRows = append(resultRows, row1)
|
|
} else {
|
|
userPerm := GetBuiltinRolePermissions(roleName)
|
|
// For each permission, create a separate entry
|
|
for _, perm := range userPerm {
|
|
// For each domain, create a separate entry
|
|
for _, domain := range perm.Domain {
|
|
row := utils.OrderMap{
|
|
Fields: []string{"role_name", "action", "domain_type", "domain_values"},
|
|
Data: map[string]interface{}{
|
|
"role_name": roleName,
|
|
"action": perm.Action,
|
|
"domain_type": domain.Type,
|
|
"domain_values": domain.Values,
|
|
},
|
|
}
|
|
resultRows = append(resultRows, row)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return utils.QueryResult{
|
|
Rows: resultRows,
|
|
Count: len(resultRows),
|
|
}
|
|
}
|
|
|
|
func (rc RoleController) GetRoleByRolename(ctx *gin.Context) {
|
|
logger.Debug("Enter GetRoleByRolename() function from ", zap.String("client_ip", ctx.ClientIP()))
|
|
|
|
// ---- check parameters ----
|
|
for param := range ctx.Request.URL.Query() {
|
|
if !utils.ContainsField(utils.SupportedQueryParams, param) {
|
|
err := errors.New("invalid specific role info query parameters of : " + param)
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
}
|
|
roleNamesStr := ctx.Param("rolename")
|
|
fieldsStr := ctx.Query("fields")
|
|
|
|
logger.Debug("origin query string rolename, fieldsStr values are:",
|
|
zap.String("rolename", roleNamesStr),
|
|
zap.String("fields", fieldsStr))
|
|
|
|
//add role_name list as filter.
|
|
roleNames := strings.Split(roleNamesStr, ",")
|
|
mergeRqueryReply := make([]utils.OrderMap, 0)
|
|
builtinResult := make([]utils.OrderMap, 0)
|
|
var page_token = ""
|
|
for _, rolename := range roleNames {
|
|
rolename = strings.TrimSpace(rolename)
|
|
filters := make([]utils.FilterCondition, 0)
|
|
sortOrders := make([]utils.SortOrder, 0)
|
|
filters = append(filters, utils.FilterCondition{
|
|
Field: "role_name",
|
|
Operator: "eq",
|
|
Value: rolename,
|
|
})
|
|
|
|
//filtercds := make([]utils.Condition, len(filters))
|
|
for _, filter := range filters {
|
|
// check the filter is supported.
|
|
if !utils.ContainsField(models.ROLE_SUPPORT_FILTERS, filter.Field) {
|
|
err := errors.New("unsupported filter: " + filter.Field)
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
}
|
|
|
|
var role models.RoleInfo
|
|
var err error
|
|
filtercds, err := utils.ConvertToNewFilter(filters, &role)
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
var fields []string
|
|
if fieldsStr != "" {
|
|
fields = utils.ParseFields(fieldsStr)
|
|
|
|
found := false
|
|
// verify the fields is in supported list
|
|
supportedFields := utils.GetSupportedFields(models.RoleInfo{})
|
|
logger.Debug("role supportedFields: %v", zap.Any("supportedFields", supportedFields))
|
|
|
|
for _, field := range fields {
|
|
if !utils.ContainsField(supportedFields, field) {
|
|
err := errors.New("unsupported query field: " + field)
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.INVALID_PARAMS_CODE, common.INVALID_PARAMS_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// if user not specify role_name in fields, add role_name as default field.
|
|
if field == "role_name" {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
logger.Debug("user doesn't specify role_name in query fields, add it.")
|
|
fields = append(fields, "role_name")
|
|
}
|
|
} else { // default display columns
|
|
fields = models.ROLE_DEFAULT_COLUMN
|
|
}
|
|
|
|
// add a default order: sort=role_name:asc
|
|
sortOrders = append(sortOrders, utils.SortOrder{
|
|
Column: "role_name",
|
|
Ascending: true,
|
|
})
|
|
|
|
queryOpts, err := utils.BuildQueryOptions(filtercds, nil, sortOrders, utils.PER_PAGE_LIMIT, "")
|
|
if err != nil {
|
|
logger.Error(err.Error())
|
|
ReturnError(ctx, common.ERROR_CODE, common.ERROR_QUEUR_ROLEINFO_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
builtinQueryResult := processBuiltinRoles(make(map[string]utils.OrderMap), fieldsStr, rolename)
|
|
builtinResult = builtinQueryResult.Rows
|
|
|
|
rqueryReply, page_token, err := services.QueryData(services.TableRolePermission, queryOpts, fields)
|
|
if err != nil {
|
|
logger.Error("Failed to query the specific role info.", zap.Error(err))
|
|
ReturnError(ctx, common.ERROR_CODE, common.ERROR_QUEUR_ROLEINFO_MSG+": "+err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
logger.Debug("specific role query reply:", zap.Any("rqueryReply", rqueryReply), zap.String("pagetoken", page_token))
|
|
mergeRqueryReply = append(mergeRqueryReply, rqueryReply...)
|
|
} // end for rolename
|
|
logger.Debug("the specific role query reply:", zap.Any("rqueryReply", mergeRqueryReply))
|
|
uniqueFlag := false
|
|
queryResult := processRoleData(mergeRqueryReply, uniqueFlag, page_token)
|
|
if len(builtinResult) > 0 {
|
|
queryResult.Rows = append(builtinResult, queryResult.Rows...)
|
|
queryResult.Count = len(builtinResult) + queryResult.Count
|
|
}
|
|
ReturnSuccess(ctx, common.SUCCESS_CODE, common.SUCCESS_MSG, queryResult)
|
|
}
|
|
func (rc *RoleController) AddPermissionsForRole(ctx *gin.Context) {
|
|
logger.Debug("Enter AddPermissionsForRole() function from ", zap.String("client_ip", ctx.ClientIP()))
|
|
roleId := ctx.Param("roleid")
|
|
var req models.CreateRoleRequest
|
|
req.RoleName = roleId
|
|
if err := utils.BindJSONStrict(ctx, &req); err != nil {
|
|
logger.Error("Invalid request parameters", zap.Error(err))
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
err := preCheckRoleRequest(&req, false)
|
|
if err != nil {
|
|
logger.Error("Failed to create role request", zap.Error(err))
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
storePerms := make([]store.RolePermission, 0, len(req.RolePermissions))
|
|
for _, perm := range req.RolePermissions {
|
|
domainValuesJSON, _ := json.Marshal(perm.DomainValues)
|
|
storePerms = append(storePerms, store.RolePermission{
|
|
Action: perm.Permission,
|
|
DomainType: perm.DomainType,
|
|
DomainValues: perm.DomainValues,
|
|
})
|
|
_ = domainValuesJSON // no longer needed for store
|
|
}
|
|
store.AddPermissionsForRole(req.RoleName, storePerms)
|
|
|
|
response := models.RoleCreateResponse{
|
|
RoleName: req.RoleName,
|
|
Message: fmt.Sprintf("Role <%s> updated successfully", req.RoleName),
|
|
}
|
|
ReturnSuccess(ctx, common.SUCCESS_CODE, common.SUCCESS_MSG, response)
|
|
return
|
|
|
|
}
|
|
|
|
// detele a role and ensure no user is using it,
|
|
// can't delete built-in role, delete the role from role_permission table
|
|
func (rc *RoleController) DeleteRoleAndPermissions(ctx *gin.Context) {
|
|
logger.Debug("Enter DeleteRoleAndPermissions() function from ", zap.String("client_ip", ctx.ClientIP()))
|
|
req_rolename := ctx.Param("rolename")
|
|
req_rolename = strings.TrimSpace(req_rolename)
|
|
logger.Debug("DeleteRoleAndPermissions() function from ", zap.String("rolename", req_rolename))
|
|
|
|
if req_rolename == "" {
|
|
logger.Error("role name can't be empty", zap.String("req_rolename", req_rolename))
|
|
err := fmt.Errorf("role name can't be empty")
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
// step 1: role name whether exists
|
|
allRoleNames := store.GetAllRoleNames(false)
|
|
found := false
|
|
for _, roleName := range allRoleNames {
|
|
if roleName == req_rolename {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
logger.Error("The role name not found", zap.String("req_rolename", req_rolename))
|
|
err := fmt.Errorf("role name not found: %s", req_rolename)
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// step 2: built-in role
|
|
if utils.ContainsField(models.BUILTIN_ROLE_NAMES, req_rolename) {
|
|
logger.Error("built-in role name can't be deleted", zap.String("req_rolename", req_rolename))
|
|
err := fmt.Errorf("built-in role name <%s> can't be deleted", req_rolename)
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// step 3: check whether there is a user configured with rolename
|
|
allUsers := store.GetUsersUnderRoleName(req_rolename)
|
|
if len(allUsers) > 0 {
|
|
logger.Error("the role is still under using by the user", zap.String("req_rolename", req_rolename))
|
|
err := fmt.Errorf("the role is still under using by the user")
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// step 4: delete the role
|
|
store.Roles.Delete(req_rolename)
|
|
|
|
// step 6: return response
|
|
logger.Debug("Role deleted successfully", zap.String("rolename", req_rolename))
|
|
Msg := fmt.Sprintf("role of <%s> deleted successfully", req_rolename)
|
|
ReturnSuccess(ctx, common.SUCCESS_CODE, common.SUCCESS_MSG, Msg)
|
|
return
|
|
}
|
|
func (rc *RoleController) CreateRole(ctx *gin.Context) {
|
|
logger.Debug("Enter CreateRole() function from ", zap.String("client_ip", ctx.ClientIP()))
|
|
|
|
var req models.CreateRoleRequest
|
|
|
|
if err := utils.BindJSONStrict(ctx, &req); err != nil {
|
|
logger.Error("Invalid request parameters", zap.Error(err))
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
// precheck the request parameter
|
|
err := preCheckRoleRequest(&req, true)
|
|
if err != nil {
|
|
logger.Error("Failed to create role request", zap.Error(err))
|
|
ReturnError(ctx, common.ERROR_CODE, err.Error(), nil)
|
|
return
|
|
}
|
|
|
|
storePerms := make([]store.RolePermission, 0, len(req.RolePermissions))
|
|
for _, perm := range req.RolePermissions {
|
|
domainValuesJSON, _ := json.Marshal(perm.DomainValues)
|
|
storePerms = append(storePerms, store.RolePermission{
|
|
Action: perm.Permission,
|
|
DomainType: perm.DomainType,
|
|
DomainValues: perm.DomainValues,
|
|
})
|
|
_ = domainValuesJSON // no longer needed for store
|
|
}
|
|
store.AddRoleNames(req.RoleName)
|
|
store.AddPermissionsForRole(req.RoleName, storePerms)
|
|
|
|
response := models.RoleCreateResponse{
|
|
RoleName: req.RoleName,
|
|
Message: fmt.Sprintf("Role <%s> created successfully", req.RoleName),
|
|
}
|
|
|
|
ReturnSuccess(ctx, common.CREATED, common.SUCCESS_MSG, response)
|
|
return
|
|
}
|
|
|
|
func preCheckRole(role_name string) error {
|
|
|
|
return nil
|
|
}
|
|
func preCheckRoleRequest(req *models.CreateRoleRequest, newFlag bool) error {
|
|
logger.Debug("Enter preCheckRoleRequest")
|
|
if req.RoleName != "" {
|
|
if newFlag {
|
|
allRoleNames := store.GetAllRoleNames(true)
|
|
//validate queue_name whether exists
|
|
for _, roleName := range allRoleNames {
|
|
if roleName == req.RoleName {
|
|
logger.Error("The role name has been existed", zap.String("role_name", req.RoleName))
|
|
return fmt.Errorf("duplicated role name: %s", req.RoleName)
|
|
}
|
|
}
|
|
} else {
|
|
allRoleNames := store.GetAllRoleNames(false)
|
|
found := false
|
|
for _, roleName := range allRoleNames {
|
|
if roleName == req.RoleName {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
logger.Error("The role name not found", zap.String("role_name", req.RoleName))
|
|
return fmt.Errorf("role name not found: %s", req.RoleName)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(req.RolePermissions) == 0 {
|
|
logger.Error("Role permissions cannot be empty")
|
|
return fmt.Errorf("role permissions cannot be empty")
|
|
}
|
|
for _, perm := range req.RolePermissions {
|
|
logger.Debug("Checking permission", zap.String("permission", perm.Permission))
|
|
if !utils.ContainsField(GetAllPermissions(), perm.Permission) {
|
|
logger.Error("Unsupported permission", zap.String("permission", perm.Permission))
|
|
return fmt.Errorf("unsupported permission: %s", perm.Permission)
|
|
}
|
|
if !newFlag { // add a new permission
|
|
dbExistPerms := store.GetRoleAllPermissions(req.RoleName)
|
|
if utils.ContainsField(dbExistPerms, perm.Permission) {
|
|
logger.Error("The permission has been existed", zap.String("permission", perm.Permission))
|
|
return fmt.Errorf("duplicated permission: %s", perm.Permission)
|
|
}
|
|
}
|
|
if perm.DomainType == "" {
|
|
logger.Error("Domain type cannot be empty")
|
|
return fmt.Errorf("domain type cannot be empty")
|
|
} else {
|
|
parts := strings.Split(perm.Permission, ":")
|
|
objectPart := parts[0] //permission first section
|
|
allowedDomainTypes := models.SupportedDomainTypes[objectPart]
|
|
domainType := strings.ToLower(perm.DomainType)
|
|
if !utils.ContainsField(allowedDomainTypes, domainType) {
|
|
logger.Error("Unsupported domain type for permission object",
|
|
zap.String("object_type", objectPart), zap.String("domain_type", domainType))
|
|
return fmt.Errorf("unsupported domain type for permission object %s: %s, and allowed types are %v", objectPart, domainType, allowedDomainTypes)
|
|
}
|
|
if domainType == models.DomainTypeAll ||
|
|
domainType == models.DomainTypeSelf ||
|
|
domainType == models.DomainTypeSelfHG ||
|
|
domainType == models.DomainTypeSelfUG {
|
|
if len(perm.DomainValues) > 0 {
|
|
logger.Error("Domain values should be empty for 'all' or 'self' domain type",
|
|
zap.String("domain_type", domainType))
|
|
return fmt.Errorf("domain values should be empty for 'all' or 'self' domain type: %s", domainType)
|
|
}
|
|
}
|
|
if domainType == models.DomainTypeUserGroup ||
|
|
domainType == models.DomainTypeHostGroup ||
|
|
domainType == models.DomainTypeQueue {
|
|
if len(perm.DomainValues) == 0 {
|
|
logger.Error("Domain values should not be empty for 'usergroups', 'hostgroups' or 'queues' domain type",
|
|
zap.String("domain_type", domainType))
|
|
return fmt.Errorf("domain values should not be empty for 'usergroups', 'hostgroups' or 'queues' domain type: %s", domainType)
|
|
}
|
|
}
|
|
switch domainType {
|
|
case models.DomainTypeQueue:
|
|
if !store.IsQueueExist(perm.DomainValues) {
|
|
logger.Error("Queue does not exist for specified values", zap.Any("queue_name", perm.DomainValues))
|
|
return fmt.Errorf("queue does not exist for specified values: %v", perm.DomainValues)
|
|
}
|
|
} //end of switch
|
|
|
|
}
|
|
}
|
|
return nil
|
|
}
|