diff --git a/manager/backend/services/footstone/presentation/permission_controller.go b/manager/backend/services/footstone/presentation/permission_controller.go index dbf1406706c19ed2659794a2cc59778adc509ea7..4653b1bb0b4ca8a7ee66aeda1e216dd7ffeac17b 100644 --- a/manager/backend/services/footstone/presentation/permission_controller.go +++ b/manager/backend/services/footstone/presentation/permission_controller.go @@ -134,7 +134,7 @@ func (p *PermissionController) ListMenus(_ context.Context, _ *ftpb.ListMenusReq // 开源版无细粒度 RBAC,但须校验调用方为有效已认证用户: // - user 为空或缺少角色 → 拒绝(防止绕过认证的越权访问) // - global 超级管理员 → 放通所有路径 -// - 普通已认证用户 → 放通(开源版默认所有已认证用户可访问) +// - 普通已认证用户 → 仅允许访问自身角色覆盖的 module_id func (p *PermissionController) HasPermission(_ context.Context, req *ftpb.HasPermissionRequest) (*ftpb.HasPermissionResponse, error) { if req == nil || req.User == nil { return &ftpb.HasPermissionResponse{Ok: false}, nil @@ -142,5 +142,18 @@ func (p *PermissionController) HasPermission(_ context.Context, req *ftpb.HasPer if len(req.User.Roles) == 0 { return &ftpb.HasPermissionResponse{Ok: false}, nil } - return &ftpb.HasPermissionResponse{Ok: true}, nil + for _, role := range req.User.Roles { + if role.GetRoleId() == "global" { + return &ftpb.HasPermissionResponse{Ok: true}, nil + } + } + if req.ModuleId == "" { + return &ftpb.HasPermissionResponse{Ok: false}, nil + } + for _, role := range req.User.Roles { + if role.GetModuleId() == req.ModuleId { + return &ftpb.HasPermissionResponse{Ok: true}, nil + } + } + return &ftpb.HasPermissionResponse{Ok: false}, nil } diff --git a/manager/backend/services/footstone/presentation/permission_controller_test.go b/manager/backend/services/footstone/presentation/permission_controller_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2475ebc5d109252aba4e0b192ed84fb22ef8d8c8 --- /dev/null +++ b/manager/backend/services/footstone/presentation/permission_controller_test.go @@ -0,0 +1,67 @@ +package presentation + +import ( + "context" + "testing" + + ftpb "gitee.com/OpenCloudOS/ocmanager/manager/backend/protocol/footstone" +) + +func TestHasPermissionRejectsModuleIDOutsideUserRoles(t *testing.T) { + controller := &PermissionController{} + resp, err := controller.HasPermission(context.Background(), &ftpb.HasPermissionRequest{ + User: &ftpb.UserInfo{ + Roles: []*ftpb.ModuleRole{{ModuleId: "1", RoleId: "operator"}}, + }, + ModuleId: "2", + }) + if err != nil { + t.Fatalf("HasPermission: %v", err) + } + if resp.GetOk() { + t.Fatal("HasPermission allowed module_id outside user roles") + } +} + +func TestHasPermissionAllowsOwnedModuleIDAndSuperAdmin(t *testing.T) { + controller := &PermissionController{} + + resp, err := controller.HasPermission(context.Background(), &ftpb.HasPermissionRequest{ + User: &ftpb.UserInfo{ + Roles: []*ftpb.ModuleRole{{ModuleId: "1", RoleId: "operator"}}, + }, + ModuleId: "1", + }) + if err != nil { + t.Fatalf("HasPermission owned module: %v", err) + } + if !resp.GetOk() { + t.Fatal("HasPermission rejected owned module_id") + } + + resp, err = controller.HasPermission(context.Background(), &ftpb.HasPermissionRequest{ + User: &ftpb.UserInfo{ + Roles: []*ftpb.ModuleRole{{ModuleId: "global", RoleId: "global"}}, + }, + ModuleId: "2", + }) + if err != nil { + t.Fatalf("HasPermission super admin: %v", err) + } + if !resp.GetOk() { + t.Fatal("HasPermission rejected super admin") + } +} + +func TestHasPermissionRejectsEmptyModuleIDForRegularUser(t *testing.T) { + controller := &PermissionController{} + resp, err := controller.HasPermission(context.Background(), &ftpb.HasPermissionRequest{ + User: &ftpb.UserInfo{Roles: []*ftpb.ModuleRole{{ModuleId: "1", RoleId: "operator"}}}, + }) + if err != nil { + t.Fatalf("HasPermission: %v", err) + } + if resp.GetOk() { + t.Fatal("HasPermission allowed an empty module_id for a regular user") + } +}