Skip to content

Commit 46378e9

Browse files
committed
feat: add permission control for business directory
Signed-off-by: YuTang Song <2313186065@qq.com>
1 parent 018f47e commit 46378e9

7 files changed

Lines changed: 227 additions & 5 deletions

File tree

pkg/cli/upgradeassistant/cmd/migrate/430.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,26 @@ import (
2525
"github.com/koderover/zadig/v2/pkg/microservice/user/core/repository"
2626
usermodels "github.com/koderover/zadig/v2/pkg/microservice/user/core/repository/models"
2727
"github.com/koderover/zadig/v2/pkg/microservice/user/core/repository/orm"
28+
permissionservice "github.com/koderover/zadig/v2/pkg/microservice/user/core/service/permission"
2829
"github.com/koderover/zadig/v2/pkg/setting"
2930
internalhandler "github.com/koderover/zadig/v2/pkg/shared/handler"
31+
pkgtypes "github.com/koderover/zadig/v2/pkg/types"
3032
)
3133

34+
type permissionActionSeed430 struct {
35+
Name string
36+
Action string
37+
Resource string
38+
Scope int
39+
}
40+
41+
var businessDirectoryActionSeeds430 = []permissionActionSeed430{
42+
{Name: "查看", Action: permissionservice.VerbGetBusinessDirectory, Resource: "BusinessDirectory", Scope: pkgtypes.DBSystemScope},
43+
{Name: "新建", Action: permissionservice.VerbCreateBusinessDirectory, Resource: "BusinessDirectory", Scope: pkgtypes.DBSystemScope},
44+
{Name: "编辑", Action: permissionservice.VerbEditBusinessDirectory, Resource: "BusinessDirectory", Scope: pkgtypes.DBSystemScope},
45+
{Name: "删除", Action: permissionservice.VerbDeleteBusinessDirectory, Resource: "BusinessDirectory", Scope: pkgtypes.DBSystemScope},
46+
}
47+
3248
func init() {
3349
upgradepath.RegisterHandler("4.2.1", "4.3.0", V421ToV430)
3450
upgradepath.RegisterHandler("4.3.0", "4.2.1", V430ToV421)
@@ -90,6 +106,16 @@ func migrateGlobalReadOnlyRole(_ *internalhandler.Context, migrationInfo *intern
90106
if err != nil {
91107
return err
92108
}
109+
// Ensure business-directory actions exist for upgraded instances.
110+
if err := ensureBusinessDirectoryActions430(); err != nil {
111+
return err
112+
}
113+
// Fallback backfill:
114+
// - if a role already has get_business_directory, append create/edit/delete
115+
// - otherwise append the full business-directory action set.
116+
if err := backfillBusinessDirectoryRolePermissions430(); err != nil {
117+
return err
118+
}
93119

94120
_ = internalmongodb.NewMigrationColl().UpdateMigrationStatus(migrationInfo.ID, map[string]interface{}{
95121
getMigrationFieldBsonTag(migrationInfo, &migrationInfo.Migration430GlobalReadOnlyRole): true,
@@ -98,6 +124,136 @@ func migrateGlobalReadOnlyRole(_ *internalhandler.Context, migrationInfo *intern
98124
return nil
99125
}
100126

127+
func ensureBusinessDirectoryActions430() error {
128+
tx := repository.DB.Begin()
129+
if tx.Error != nil {
130+
return fmt.Errorf("failed to begin tx for business directory action migration, err: %s", tx.Error)
131+
}
132+
133+
for _, seed := range businessDirectoryActionSeeds430 {
134+
action, err := orm.GetActionByVerb(seed.Action, tx)
135+
if err != nil {
136+
tx.Rollback()
137+
return fmt.Errorf("failed to query action %s, err: %s", seed.Action, err)
138+
}
139+
if action != nil && action.ID != 0 {
140+
continue
141+
}
142+
143+
action = &usermodels.Action{
144+
Name: seed.Name,
145+
Action: seed.Action,
146+
Resource: seed.Resource,
147+
Scope: seed.Scope,
148+
}
149+
if err := orm.CreateAction(action, tx); err != nil {
150+
tx.Rollback()
151+
return fmt.Errorf("failed to create action %s, err: %s", seed.Action, err)
152+
}
153+
}
154+
155+
if err := tx.Commit().Error; err != nil {
156+
return fmt.Errorf("failed to commit business directory action migration tx, err: %s", err)
157+
}
158+
return nil
159+
}
160+
161+
// backfillBusinessDirectoryRolePermissions430 provides a migration fallback for
162+
// historical system roles:
163+
// 1) If a role already has get_business_directory, only append write verbs.
164+
// 2) If a role does not have get_business_directory, append the full set.
165+
// global-read-only role is skipped to keep readonly semantics.
166+
func backfillBusinessDirectoryRolePermissions430() error {
167+
tx := repository.DB.Begin()
168+
if tx.Error != nil {
169+
return fmt.Errorf("failed to begin tx for business directory permission backfill, err: %s", tx.Error)
170+
}
171+
172+
actionIDMap := make(map[string]uint, len(businessDirectoryActionSeeds430))
173+
for _, seed := range businessDirectoryActionSeeds430 {
174+
action, err := orm.GetActionByVerb(seed.Action, tx)
175+
if err != nil {
176+
tx.Rollback()
177+
return fmt.Errorf("failed to query action %s for backfill, err: %s", seed.Action, err)
178+
}
179+
if action == nil || action.ID == 0 {
180+
tx.Rollback()
181+
return fmt.Errorf("action %s is missing while backfilling business directory permissions", seed.Action)
182+
}
183+
actionIDMap[seed.Action] = action.ID
184+
}
185+
186+
roles, err := orm.ListRoleByNamespace(permissionservice.GeneralNamespace, tx)
187+
if err != nil {
188+
tx.Rollback()
189+
return fmt.Errorf("failed to list system roles for business directory backfill, err: %s", err)
190+
}
191+
192+
for _, role := range roles {
193+
if role == nil || role.ID == 0 {
194+
continue
195+
}
196+
// Keep global-read-only role as readonly.
197+
if role.GlobalReadOnly {
198+
continue
199+
}
200+
201+
actions, err := orm.ListActionByRole(role.ID, tx)
202+
if err != nil {
203+
tx.Rollback()
204+
return fmt.Errorf("failed to list actions for role %d during business directory backfill, err: %s", role.ID, err)
205+
}
206+
207+
existingVerbs := map[string]struct{}{}
208+
for _, action := range actions {
209+
if action == nil {
210+
continue
211+
}
212+
existingVerbs[action.Action] = struct{}{}
213+
}
214+
215+
// Fallback strategy:
216+
// - has get_business_directory: only backfill create/edit/delete
217+
// - does not have get_business_directory: backfill get/create/edit/delete
218+
targetVerbs := []string{
219+
permissionservice.VerbGetBusinessDirectory,
220+
permissionservice.VerbCreateBusinessDirectory,
221+
permissionservice.VerbEditBusinessDirectory,
222+
permissionservice.VerbDeleteBusinessDirectory,
223+
}
224+
if _, hasGet := existingVerbs[permissionservice.VerbGetBusinessDirectory]; hasGet {
225+
targetVerbs = []string{
226+
permissionservice.VerbCreateBusinessDirectory,
227+
permissionservice.VerbEditBusinessDirectory,
228+
permissionservice.VerbDeleteBusinessDirectory,
229+
}
230+
}
231+
232+
missingActionIDs := make([]uint, 0)
233+
for _, verb := range targetVerbs {
234+
if _, ok := existingVerbs[verb]; ok {
235+
continue
236+
}
237+
if actionID, ok := actionIDMap[verb]; ok {
238+
missingActionIDs = append(missingActionIDs, actionID)
239+
}
240+
}
241+
242+
if len(missingActionIDs) == 0 {
243+
continue
244+
}
245+
if err := orm.BulkCreateRoleActionBindings(role.ID, missingActionIDs, tx); err != nil {
246+
tx.Rollback()
247+
return fmt.Errorf("failed to backfill business directory permissions for role %d, err: %s", role.ID, err)
248+
}
249+
}
250+
251+
if err := tx.Commit().Error; err != nil {
252+
return fmt.Errorf("failed to commit business directory permission backfill tx, err: %s", err)
253+
}
254+
return nil
255+
}
256+
101257
// backfill global read only role
102258
func backfillGlobalReadOnlyRole() error {
103259
tx := repository.DB.Begin()

pkg/microservice/aslan/core/application/handler/application.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ func CreateApplication(c *gin.Context) {
3939
ctx.UnAuthorized = true
4040
return
4141
}
42+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.Create {
43+
ctx.UnAuthorized = true
44+
return
45+
}
4246
args := new(commonmodels.Application)
4347
data, _ := c.GetRawData()
4448
c.Request.Body = io.NopCloser(bytes.NewBuffer(data))
@@ -58,6 +62,11 @@ func BulkCreateApplications(c *gin.Context) {
5862
return
5963
}
6064

65+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.Create {
66+
ctx.UnAuthorized = true
67+
return
68+
}
69+
6170
var args []*commonmodels.Application
6271
data, _ := c.GetRawData()
6372
c.Request.Body = io.NopCloser(bytes.NewBuffer(data))
@@ -74,8 +83,17 @@ func BulkCreateApplications(c *gin.Context) {
7483
}
7584

7685
func GetApplication(c *gin.Context) {
77-
ctx := internalhandler.NewContext(c)
86+
ctx, err := internalhandler.NewContextWithAuthorization(c)
7887
defer func() { internalhandler.JSONResponse(c, ctx) }()
88+
if err != nil {
89+
ctx.RespErr = fmt.Errorf("authorization Info Generation failed: err %s", err)
90+
ctx.UnAuthorized = true
91+
return
92+
}
93+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.View {
94+
ctx.UnAuthorized = true
95+
return
96+
}
7997
ctx.Resp, ctx.RespErr = service.GetApplication(c.Param("id"), ctx.Logger)
8098
}
8199

@@ -87,6 +105,10 @@ func UpdateApplication(c *gin.Context) {
87105
ctx.UnAuthorized = true
88106
return
89107
}
108+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.Edit {
109+
ctx.UnAuthorized = true
110+
return
111+
}
90112
args := new(commonmodels.Application)
91113
data, _ := c.GetRawData()
92114
if err := json.Unmarshal(data, args); err != nil {
@@ -104,12 +126,25 @@ func DeleteApplication(c *gin.Context) {
104126
ctx.UnAuthorized = true
105127
return
106128
}
129+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.Delete {
130+
ctx.UnAuthorized = true
131+
return
132+
}
107133
ctx.RespErr = service.DeleteApplication(c.Param("id"), ctx.Logger)
108134
}
109135

110136
func SearchApplications(c *gin.Context) {
111-
ctx := internalhandler.NewContext(c)
137+
ctx, err := internalhandler.NewContextWithAuthorization(c)
112138
defer func() { internalhandler.JSONResponse(c, ctx) }()
139+
if err != nil {
140+
ctx.RespErr = fmt.Errorf("authorization Info Generation failed: err %s", err)
141+
ctx.UnAuthorized = true
142+
return
143+
}
144+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.View {
145+
ctx.UnAuthorized = true
146+
return
147+
}
113148
var req service.SearchApplicationsRequest
114149
if err := c.ShouldBindJSON(&req); err != nil {
115150
ctx.RespErr = e.ErrInvalidParam.AddErr(err)
@@ -124,8 +159,17 @@ func SearchApplications(c *gin.Context) {
124159
}
125160

126161
func ListApplicationEnvs(c *gin.Context) {
127-
ctx := internalhandler.NewContext(c)
162+
ctx, err := internalhandler.NewContextWithAuthorization(c)
128163
defer func() { internalhandler.JSONResponse(c, ctx) }()
164+
if err != nil {
165+
ctx.RespErr = fmt.Errorf("authorization Info Generation failed: err %s", err)
166+
ctx.UnAuthorized = true
167+
return
168+
}
169+
if !ctx.Resources.IsSystemAdmin && !ctx.Resources.SystemActions.BusinessDirectory.View {
170+
ctx.UnAuthorized = true
171+
return
172+
}
129173
resp, err := service.ListApplicationEnvs(c.Param("id"), ctx.Logger)
130174
if err != nil {
131175
ctx.RespErr = err

pkg/microservice/user/core/init/action_initialization.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ VALUES
7171
("删除", "delete_release_plan", "ReleasePlan", 2),
7272
("配置", "edit_config_release_plan", "ReleasePlan", 2),
7373
("查看", "get_business_directory", "BusinessDirectory", 2),
74+
("新建", "create_business_directory", "BusinessDirectory", 2),
75+
("编辑", "edit_business_directory", "BusinessDirectory", 2),
76+
("删除", "delete_business_directory", "BusinessDirectory", 2),
7477
("查看", "get_cluster_management", "ClusterManagement", 2),
7578
("新建", "create_cluster_management", "ClusterManagement", 2),
7679
("编辑", "edit_cluster_management", "ClusterManagement", 2),

pkg/microservice/user/core/init/dm_action_initialization.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ VALUES
6868
('编辑', 'edit_release_plan', 'ReleasePlan', 2),
6969
('删除', 'delete_release_plan', 'ReleasePlan', 2),
7070
('查看', 'get_business_directory', 'BusinessDirectory', 2),
71+
('新建', 'create_business_directory', 'BusinessDirectory', 2),
72+
('编辑', 'edit_business_directory', 'BusinessDirectory', 2),
73+
('删除', 'delete_business_directory', 'BusinessDirectory', 2),
7174
('查看', 'get_cluster_management', 'ClusterManagement', 2),
7275
('新建', 'create_cluster_management', 'ClusterManagement', 2),
7376
('编辑', 'edit_cluster_management', 'ClusterManagement', 2),

pkg/microservice/user/core/service/permission/authz.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,12 @@ func modifySystemAction(systemActions *SystemActions, verb string) {
10571057
systemActions.ReleasePlan.EditConfig = true
10581058
case VerbGetBusinessDirectory:
10591059
systemActions.BusinessDirectory.View = true
1060+
case VerbCreateBusinessDirectory:
1061+
systemActions.BusinessDirectory.Create = true
1062+
case VerbEditBusinessDirectory:
1063+
systemActions.BusinessDirectory.Edit = true
1064+
case VerbDeleteBusinessDirectory:
1065+
systemActions.BusinessDirectory.Delete = true
10601066
case VerbGetClusterManagement:
10611067
systemActions.ClusterManagement.View = true
10621068
case VerbCreateClusterManagement:

pkg/microservice/user/core/service/permission/types.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,10 @@ const (
152152
VerbEditHelmRepoManagement = "edit_helmrepo_management"
153153
VerbDeleteHelmRepoManagement = "delete_helmrepo_management"
154154
// business directory
155-
VerbGetBusinessDirectory = "get_business_directory"
155+
VerbGetBusinessDirectory = "get_business_directory"
156+
VerbCreateBusinessDirectory = "create_business_directory"
157+
VerbEditBusinessDirectory = "edit_business_directory"
158+
VerbDeleteBusinessDirectory = "delete_business_directory"
156159
// dbinstance management
157160
VerbGetDBInstanceManagement = "get_dbinstance_management"
158161
VerbCreateDBInstanceManagement = "create_dbinstance_management"
@@ -345,7 +348,10 @@ type ReleasePlanActions struct {
345348
}
346349

347350
type BusinessDirectoryActions struct {
348-
View bool
351+
View bool
352+
Create bool
353+
Edit bool
354+
Delete bool
349355
}
350356

351357
type ClusterManagementActions struct {

pkg/shared/client/user/user_auth.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ type ReleasePlanActions struct {
178178

179179
type BusinessDirectoryActions struct {
180180
View bool
181+
// Edit business directory metadata/configuration.
182+
Edit bool
183+
Create bool
184+
Delete bool
181185
}
182186

183187
type ClusterManagementActions struct {

0 commit comments

Comments
 (0)