Skip to content

Commit

Permalink
Merge pull request #3496 from jamsman94/feature/globalRole
Browse files Browse the repository at this point in the history
add gloabl role configs
  • Loading branch information
jamsman94 authored Apr 24, 2024
2 parents 70591eb + b34fb01 commit 5d88df7
Show file tree
Hide file tree
Showing 25 changed files with 954 additions and 39 deletions.
5 changes: 4 additions & 1 deletion pkg/microservice/aslan/core/service/handler/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func GetServiceTemplate(c *gin.Context) {
ctx.UnAuthorized = true
return
}

if production {
if !ctx.Resources.ProjectAuthInfo[projectName].IsProjectAdmin &&
!ctx.Resources.ProjectAuthInfo[projectName].ProductionService.View {
Expand All @@ -167,7 +168,9 @@ func GetServiceTemplate(c *gin.Context) {
}
} else {
if !ctx.Resources.ProjectAuthInfo[projectName].IsProjectAdmin &&
!ctx.Resources.ProjectAuthInfo[projectName].Service.View {
!ctx.Resources.ProjectAuthInfo[projectName].Service.View &&
// special case for vm project
!ctx.Resources.ProjectAuthInfo[projectName].Env.View {
ctx.UnAuthorized = true
return
}
Expand Down
167 changes: 147 additions & 20 deletions pkg/microservice/user/core/handler/permission/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ import (
"github.com/koderover/zadig/v2/pkg/tool/log"
)

func checkLicense(actions []string) error {
licenseStatus, err := plutusvendor.New().CheckZadigXLicenseStatus()
if err != nil {
return fmt.Errorf("failed to validate zadig license status, error: %s", err)
}
if !((licenseStatus.Type == plutusvendor.ZadigSystemTypeProfessional ||
licenseStatus.Type == plutusvendor.ZadigSystemTypeEnterprise) &&
licenseStatus.Status == plutusvendor.ZadigXLicenseStatusNormal) {
actionSet := sets.NewString(actions...)
if actionSet.Has(permission.VerbCreateReleasePlan) || actionSet.Has(permission.VerbDeleteReleasePlan) ||
actionSet.Has(permission.VerbEditReleasePlan) || actionSet.Has(permission.VerbGetReleasePlan) ||
actionSet.Has(permission.VerbEditDataCenterInsightConfig) ||
actionSet.Has(permission.VerbGetProductionService) || actionSet.Has(permission.VerbGetProductionService) ||
actionSet.Has(permission.VerbGetProductionService) || actionSet.Has(permission.VerbGetProductionService) ||
actionSet.Has(permission.VerbGetProductionEnv) || actionSet.Has(permission.VerbCreateProductionEnv) ||
actionSet.Has(permission.VerbConfigProductionEnv) || actionSet.Has(permission.VerbEditProductionEnv) ||
actionSet.Has(permission.VerbDeleteProductionEnv) || actionSet.Has(permission.VerbDebugProductionEnvPod) ||
actionSet.Has(permission.VerbGetDelivery) || actionSet.Has(permission.VerbCreateDelivery) || actionSet.Has(permission.VerbDeleteDelivery) {
return e.ErrLicenseInvalid.AddDesc("")
}
}
return nil
}

func OpenAPICreateRole(c *gin.Context) {
ctx := internalhandler.NewContext(c)
ctx.UserName = ctx.UserName + "(openAPI)"
Expand All @@ -48,7 +72,15 @@ func CreateRole(c *gin.Context) {
CreateRoleImpl(c, ctx)
}

func CreateRoleImpl(c *gin.Context, ctx *internalhandler.Context) {
func CreateRoleTemplate(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()

if err != nil {
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}

data, err := c.GetRawData()
if err != nil {
Expand All @@ -64,6 +96,38 @@ func CreateRoleImpl(c *gin.Context, ctx *internalhandler.Context) {
return
}

internalhandler.InsertDetailedOperationLog(c, ctx.UserName, "*", setting.OperationSceneProject, "创建", "全局角色", "角色名称:"+args.Name, string(data), ctx.Logger, args.Name)

// authorization checks
if !ctx.Resources.IsSystemAdmin {
ctx.UnAuthorized = true
return
}

err = checkLicense(args.Actions)
if err != nil {
ctx.Err = err
return
}

ctx.Err = permission.CreateRoleTemplate(args, ctx.Logger)
}

func CreateRoleImpl(c *gin.Context, ctx *internalhandler.Context) {
data, err := c.GetRawData()
if err != nil {
log.Errorf("CreateRole c.GetRawData() err : %v", err)
ctx.Err = e.ErrInvalidParam.AddErr(err)
return
}
c.Request.Body = io.NopCloser(bytes.NewBuffer(data))

args := &permission.CreateRoleReq{}
if err := c.ShouldBindJSON(args); err != nil {
ctx.Err = err
return
}

err = userhandler.GenerateUserAuthInfo(ctx)
if err != nil {
ctx.UnAuthorized = true
Expand Down Expand Up @@ -94,28 +158,11 @@ func CreateRoleImpl(c *gin.Context, ctx *internalhandler.Context) {
}
}

licenseStatus, err := plutusvendor.New().CheckZadigXLicenseStatus()
err = checkLicense(args.Actions)
if err != nil {
ctx.Err = fmt.Errorf("failed to validate zadig license status, error: %s", err)
ctx.Err = err
return
}
if !((licenseStatus.Type == plutusvendor.ZadigSystemTypeProfessional ||
licenseStatus.Type == plutusvendor.ZadigSystemTypeEnterprise) &&
licenseStatus.Status == plutusvendor.ZadigXLicenseStatusNormal) {
actionSet := sets.NewString(args.Actions...)
if actionSet.Has(permission.VerbCreateReleasePlan) || actionSet.Has(permission.VerbDeleteReleasePlan) ||
actionSet.Has(permission.VerbEditReleasePlan) || actionSet.Has(permission.VerbGetReleasePlan) ||
actionSet.Has(permission.VerbEditDataCenterInsightConfig) ||
actionSet.Has(permission.VerbGetProductionService) || actionSet.Has(permission.VerbGetProductionService) ||
actionSet.Has(permission.VerbGetProductionService) || actionSet.Has(permission.VerbGetProductionService) ||
actionSet.Has(permission.VerbGetProductionEnv) || actionSet.Has(permission.VerbCreateProductionEnv) ||
actionSet.Has(permission.VerbConfigProductionEnv) || actionSet.Has(permission.VerbEditProductionEnv) ||
actionSet.Has(permission.VerbDeleteProductionEnv) || actionSet.Has(permission.VerbDebugProductionEnvPod) ||
actionSet.Has(permission.VerbGetDelivery) || actionSet.Has(permission.VerbCreateDelivery) || actionSet.Has(permission.VerbDeleteDelivery) {
ctx.Err = e.ErrLicenseInvalid.AddDesc("")
return
}
}

ctx.Err = permission.CreateRole(projectName, args, ctx.Logger)
}
Expand Down Expand Up @@ -209,6 +256,50 @@ func UpdateRoleImpl(c *gin.Context, ctx *internalhandler.Context) {
ctx.Err = permission.UpdateRole(projectName, args, ctx.Logger)
}

func UpdateRoleTemplate(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
if err != nil {
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}

defer func() { internalhandler.JSONResponse(c, ctx) }()

data, err := c.GetRawData()
if err != nil {
log.Errorf("UpdateRole c.GetRawData() err : %v", err)
ctx.Err = e.ErrInvalidParam.AddErr(err)
return
}
c.Request.Body = io.NopCloser(bytes.NewBuffer(data))

args := &permission.CreateRoleReq{}
if err := c.ShouldBindJSON(args); err != nil {
ctx.Err = err
return
}

name := c.Param("name")
args.Name = name

internalhandler.InsertDetailedOperationLog(c, ctx.UserName, "*", setting.OperationSceneProject, "更新", "全局角色", "角色名称:"+args.Name, string(data), ctx.Logger, args.Name)

// authorization checks
if !ctx.Resources.IsSystemAdmin {
ctx.UnAuthorized = true
return
}

err = checkLicense(args.Actions)
if err != nil {
ctx.Err = err
return
}

ctx.Err = permission.UpdateRoleTemplate(args, ctx.Logger)
}

func OpenAPIListRoles(c *gin.Context) {
ctx := internalhandler.NewContext(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
Expand Down Expand Up @@ -268,6 +359,13 @@ func ListRoles(c *gin.Context) {
}
}

func ListRoleTemplates(c *gin.Context) {
ctx := internalhandler.NewContext(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()

ctx.Resp, ctx.Err = permission.ListRoleTemplates(ctx.Logger)
}

func OpenAPIGetRole(c *gin.Context) {
ctx := internalhandler.NewContext(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
Expand Down Expand Up @@ -318,6 +416,13 @@ func GetRole(c *gin.Context) {
ctx.Resp, ctx.Err = permission.GetRole(projectName, c.Param("name"), ctx.Logger)
}

func GetRoleTemplate(c *gin.Context) {
ctx := internalhandler.NewContext(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()

ctx.Resp, ctx.Err = permission.GetRoleTemplate(c.Param("name"), ctx.Logger)
}

func OpenAPIDeleteRole(c *gin.Context) {
ctx := internalhandler.NewContext(c)
ctx.UserName = ctx.UserName + "(openAPI)"
Expand All @@ -326,6 +431,28 @@ func OpenAPIDeleteRole(c *gin.Context) {
DeleteRoleImpl(c, ctx)
}

func DeleteRoleTemplate(c *gin.Context) {
ctx, err := internalhandler.NewContextWithAuthorization(c)
if err != nil {
ctx.Err = fmt.Errorf("authorization Info Generation failed: err %s", err)
ctx.UnAuthorized = true
return
}

defer func() { internalhandler.JSONResponse(c, ctx) }()

// authorization checks
if !ctx.Resources.IsSystemAdmin {
ctx.UnAuthorized = true
return
}

name := c.Param("name")
internalhandler.InsertDetailedOperationLog(c, ctx.UserName, "*", setting.OperationSceneProject, "删除", "角色", "角色名称:"+name, "", ctx.Logger, name)

ctx.Err = permission.DeleteRoleTemplate(c.Param("name"), ctx.Logger)
}

func DeleteRole(c *gin.Context) {
ctx := internalhandler.NewContext(c)
defer func() { internalhandler.JSONResponse(c, ctx) }()
Expand Down
9 changes: 9 additions & 0 deletions pkg/microservice/user/core/handler/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ func (*Router) Inject(router *gin.RouterGroup) {
roles.DELETE("/:name", permission.DeleteRole)
}

roleTemplates := policy.Group("/role-templates")
{
roleTemplates.POST("", permission.CreateRoleTemplate)
roleTemplates.PUT("/:name", permission.UpdateRoleTemplate)
roleTemplates.GET("", permission.ListRoleTemplates)
roleTemplates.GET("/:name", permission.GetRoleTemplate)
roleTemplates.DELETE("/:name", permission.DeleteRoleTemplate)
}

roleBindings := policy.Group("/role-bindings")
{
roleBindings.GET("", permission.ListRoleBindings)
Expand Down
3 changes: 2 additions & 1 deletion pkg/microservice/user/core/init/action_initialization.sql
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,5 @@ VALUES
("查看交付物追踪", "delivery_get", "ArtifactManagement", 2),
("查看数据概览", "data_over", "DataCenter", 2),
("查看效能洞察", "efficiency_over", "DataCenter", 2),
("配置效能洞察", "edit_dashboard_config", "DataCenter", 2) ON DUPLICATE KEY UPDATE id=id;
("配置效能洞察", "edit_dashboard_config", "DataCenter", 2) ON DUPLICATE KEY UPDATE id=id;

28 changes: 28 additions & 0 deletions pkg/microservice/user/core/init/dm_mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ CREATE TABLE IF NOT EXISTS role (

CREATE UNIQUE INDEX IF NOT EXISTS namespaced_role ON role(namespace, name);

CREATE TABLE IF NOT EXISTS role_template (
id bigint NOT NULL AUTO_INCREMENT,
name varchar(32) NOT NULL COMMENT '角色名称',
description varchar(64) NOT NULL COMMENT '描述',
type tinyint NOT NULL COMMENT '类型',
PRIMARY KEY (id)
) ;

CREATE UNIQUE INDEX IF NOT EXISTS name_role_template ON role_template(name);

CREATE TABLE IF NOT EXISTS role_action_binding (
id bigint NOT NULL AUTO_INCREMENT,
action_id bigint NOT NULL COMMENT '用户组ID',
Expand All @@ -79,6 +89,15 @@ CREATE TABLE IF NOT EXISTS role_action_binding (
FOREIGN KEY (role_id) REFERENCES role(id) ON DELETE CASCADE
) ;

CREATE TABLE IF NOT EXISTS role_template_action_binding (
id bigint NOT NULL AUTO_INCREMENT,
action_id bigint NOT NULL COMMENT '用户组ID',
role_template_id bigint NOT NULL COMMENT '全局角色ID',
PRIMARY KEY (id),
FOREIGN KEY (action_id) REFERENCES action(id) ON DELETE CASCADE,
FOREIGN KEY (role_template_id) REFERENCES role_template(id) ON DELETE CASCADE
) ;

CREATE TABLE IF NOT EXISTS role_binding (
id bigint NOT NULL AUTO_INCREMENT,
uid varchar(64) NOT NULL COMMENT '用户ID',
Expand All @@ -95,4 +114,13 @@ CREATE TABLE IF NOT EXISTS group_role_binding (
PRIMARY KEY (id),
FOREIGN KEY (group_id) REFERENCES user_group(group_id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES role(id) ON DELETE CASCADE
) ;

CREATE TABLE IF NOT EXISTS role_template_binding (
id bigint NOT NULL AUTO_INCREMENT,
role_id bigint NOT NULL COMMENT '角色ID',
role_template_id bigint NOT NULL COMMENT '全局角色ID',
PRIMARY KEY (id),
FOREIGN KEY (role_id) REFERENCES role(id) ON DELETE CASCADE,
FOREIGN KEY (role_template_id) REFERENCES role_template(id) ON DELETE CASCADE
) ;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INSERT INTO `role_template` (name, description, type)
VALUES
('project-admin', '拥有执行项目中任何操作的权限', 1),
('read-only', '拥有指定项目中所有资源的读权限', 1),
('read-project-only', '拥有指定项目本身的读权限,无权限查看和操作项目内资源', 1);
26 changes: 26 additions & 0 deletions pkg/microservice/user/core/init/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ CREATE TABLE IF NOT EXISTS `role` (
UNIQUE KEY `namespaced_role` (`namespace`, `name`)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Compact;

CREATE TABLE IF NOT EXISTS `role_template` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '角色名称',
`description` varchar(64) NOT NULL COMMENT '描述',
`type` tinyint NOT NULL COMMENT '类型',
PRIMARY KEY (`id`),
UNIQUE KEY `name_role_template` (`name`)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '全局角色' ROW_FORMAT = Compact;

CREATE TABLE IF NOT EXISTS `role_action_binding` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`action_id` bigint(20) NOT NULL COMMENT '用户组ID',
Expand All @@ -76,6 +85,15 @@ CREATE TABLE IF NOT EXISTS `role_action_binding` (
FOREIGN KEY (`role_id`) REFERENCES role(`id`) ON DELETE CASCADE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色/权限项绑定信息' ROW_FORMAT = Compact;

CREATE TABLE IF NOT EXISTS `role_template_action_binding` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`action_id` bigint(20) NOT NULL COMMENT '用户组ID',
`role_template_id` bigint(20) NOT NULL COMMENT '全局角色ID',
PRIMARY KEY (`id`),
FOREIGN KEY (`action_id`) REFERENCES action(`id`) ON DELETE CASCADE,
FOREIGN KEY (`role_template_id`) REFERENCES role_template(`id`) ON DELETE CASCADE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '全局角色/权限项绑定信息' ROW_FORMAT = Compact;

CREATE TABLE IF NOT EXISTS `role_binding` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uid` varchar(64) NOT NULL COMMENT '用户ID',
Expand All @@ -94,3 +112,11 @@ CREATE TABLE IF NOT EXISTS `group_role_binding` (
FOREIGN KEY (`role_id`) REFERENCES role(`id`) ON DELETE CASCADE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色组/角色绑定信息' ROW_FORMAT = Compact;

CREATE TABLE IF NOT EXISTS `role_template_binding` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
`role_template_id` bigint(20) NOT NULL COMMENT '全局角色ID',
PRIMARY KEY (`id`),
FOREIGN KEY (`role_id`) REFERENCES role(`id`) ON DELETE CASCADE,
FOREIGN KEY (`role_template_id`) REFERENCES role_template(`id`) ON DELETE CASCADE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '全局角色/角色绑定信息' ROW_FORMAT = Compact;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INSERT INTO `role_template` (name, description, type) VALUES
("project-admin", "拥有执行项目中任何操作的权限", 1),
("read-only", "拥有指定项目中所有资源的读权限", 1),
("read-project-only", "拥有指定项目本身的读权限,无权限查看和操作项目内资源", 1)
on duplicate key update id=id;
15 changes: 15 additions & 0 deletions pkg/microservice/user/core/repository/models/role_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package models

type RoleTemplate struct {
ID uint `gorm:"primarykey" json:"id"`
Name string `gorm:"column:name" json:"name"`
Description string `gorm:"column:description" json:"description"`
Type int `gorm:"column:type" json:"type"`

RoleTemplateActionBindings []RoleTemplateActionBinding `gorm:"foreignKey:RoleTemplateID;constraint:OnDelete:CASCADE;" json:"-"`
RoleTemplateBindings []RoleTemplateBinding `gorm:"foreignKey:RoleTemplateID;constraint:OnDelete:CASCADE;" json:"-"`
}

func (RoleTemplate) TableName() string {
return "role_template"
}
Loading

0 comments on commit 5d88df7

Please sign in to comment.