Skip to content

Commit e4fe61d

Browse files
authored
enable robot full access (#20754)
* have option to enable robot full access When the system admin enable this option, the robot can be assigned with robot/user/group/quota permissions. Signed-off-by: wang yan <[email protected]> * robot account permission enhancement Update codes according to the proposal of goharbor/community#249 Signed-off-by: wang yan <[email protected]> --------- Signed-off-by: wang yan <[email protected]>
1 parent d42c347 commit e4fe61d

19 files changed

+532
-69
lines changed

src/common/rbac/const.go

+85-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
package rbac
1616

17-
import "github.com/goharbor/harbor/src/pkg/permission/types"
17+
import (
18+
"github.com/goharbor/harbor/src/pkg/permission/types"
19+
)
1820

1921
// const action variables
2022
const (
@@ -81,9 +83,88 @@ const (
8183
ResourceSecurityHub = Resource("security-hub")
8284
)
8385

86+
type scope string
87+
88+
const (
89+
ScopeSystem = scope("System")
90+
ScopeProject = scope("Project")
91+
)
92+
93+
// RobotPermissionProvider defines the permission provider for robot account
94+
type RobotPermissionProvider interface {
95+
GetPermissions(s scope) []*types.Policy
96+
}
97+
98+
// GetPermissionProvider gives the robot permission provider
99+
func GetPermissionProvider() RobotPermissionProvider {
100+
// TODO will determine by the ui configuration
101+
return &NolimitProvider{}
102+
}
103+
104+
// BaseProvider ...
105+
type BaseProvider struct {
106+
}
107+
108+
// GetPermissions ...
109+
func (d *BaseProvider) GetPermissions(s scope) []*types.Policy {
110+
return PoliciesMap[s]
111+
}
112+
113+
// NolimitProvider ...
114+
type NolimitProvider struct {
115+
BaseProvider
116+
}
117+
118+
// GetPermissions ...
119+
func (n *NolimitProvider) GetPermissions(s scope) []*types.Policy {
120+
if s == ScopeSystem {
121+
return append(n.BaseProvider.GetPermissions(ScopeSystem),
122+
&types.Policy{Resource: ResourceRobot, Action: ActionCreate},
123+
&types.Policy{Resource: ResourceRobot, Action: ActionRead},
124+
&types.Policy{Resource: ResourceRobot, Action: ActionUpdate},
125+
&types.Policy{Resource: ResourceRobot, Action: ActionList},
126+
&types.Policy{Resource: ResourceRobot, Action: ActionDelete},
127+
128+
&types.Policy{Resource: ResourceUser, Action: ActionCreate},
129+
&types.Policy{Resource: ResourceUser, Action: ActionRead},
130+
&types.Policy{Resource: ResourceUser, Action: ActionUpdate},
131+
&types.Policy{Resource: ResourceUser, Action: ActionList},
132+
&types.Policy{Resource: ResourceUser, Action: ActionDelete},
133+
134+
&types.Policy{Resource: ResourceLdapUser, Action: ActionCreate},
135+
&types.Policy{Resource: ResourceLdapUser, Action: ActionList},
136+
137+
&types.Policy{Resource: ResourceExportCVE, Action: ActionCreate},
138+
&types.Policy{Resource: ResourceExportCVE, Action: ActionRead},
139+
140+
&types.Policy{Resource: ResourceQuota, Action: ActionUpdate},
141+
142+
&types.Policy{Resource: ResourceUserGroup, Action: ActionCreate},
143+
&types.Policy{Resource: ResourceUserGroup, Action: ActionRead},
144+
&types.Policy{Resource: ResourceUserGroup, Action: ActionUpdate},
145+
&types.Policy{Resource: ResourceUserGroup, Action: ActionList},
146+
&types.Policy{Resource: ResourceUserGroup, Action: ActionDelete})
147+
}
148+
if s == ScopeProject {
149+
return append(n.BaseProvider.GetPermissions(ScopeProject),
150+
&types.Policy{Resource: ResourceRobot, Action: ActionCreate},
151+
&types.Policy{Resource: ResourceRobot, Action: ActionRead},
152+
&types.Policy{Resource: ResourceRobot, Action: ActionUpdate},
153+
&types.Policy{Resource: ResourceRobot, Action: ActionList},
154+
&types.Policy{Resource: ResourceRobot, Action: ActionDelete},
155+
156+
&types.Policy{Resource: ResourceMember, Action: ActionCreate},
157+
&types.Policy{Resource: ResourceMember, Action: ActionRead},
158+
&types.Policy{Resource: ResourceMember, Action: ActionUpdate},
159+
&types.Policy{Resource: ResourceMember, Action: ActionList},
160+
&types.Policy{Resource: ResourceMember, Action: ActionDelete})
161+
}
162+
return []*types.Policy{}
163+
}
164+
84165
var (
85-
PoliciesMap = map[string][]*types.Policy{
86-
"System": {
166+
PoliciesMap = map[scope][]*types.Policy{
167+
ScopeSystem: {
87168
{Resource: ResourceAuditLog, Action: ActionList},
88169

89170
{Resource: ResourcePreatInstance, Action: ActionRead},
@@ -154,7 +235,7 @@ var (
154235
{Resource: ResourceQuota, Action: ActionRead},
155236
{Resource: ResourceQuota, Action: ActionList},
156237
},
157-
"Project": {
238+
ScopeProject: {
158239
{Resource: ResourceLog, Action: ActionList},
159240

160241
{Resource: ResourceProject, Action: ActionRead},

src/common/rbac/const_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package rbac
2+
3+
import (
4+
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
5+
6+
"github.com/stretchr/testify/assert"
7+
"testing"
8+
)
9+
10+
func TestBaseProvider(t *testing.T) {
11+
permissionProvider := &BaseProvider{}
12+
sysPermissions := permissionProvider.GetPermissions(ScopeSystem)
13+
14+
for _, per := range sysPermissions {
15+
if per.Action == ActionCreate && per.Resource == ResourceRobot {
16+
t.Fail()
17+
}
18+
}
19+
}
20+
21+
func TestNolimitProvider(t *testing.T) {
22+
permissionProvider := &BaseProvider{}
23+
sysPermissions := permissionProvider.GetPermissions(ScopeSystem)
24+
25+
for _, per := range sysPermissions {
26+
if per.Action == ActionCreate && per.Resource == ResourceRobot {
27+
t.Log("no limit provider has the permission of robot account creation")
28+
}
29+
}
30+
}
31+
32+
func TestGetPermissionProvider(t *testing.T) {
33+
defaultPro := GetPermissionProvider()
34+
_, ok := defaultPro.(*NolimitProvider)
35+
assert.True(t, ok)
36+
}

src/controller/robot/controller.go

+16-20
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ func (d *controller) Count(ctx context.Context, query *q.Query) (int64, error) {
9797

9898
// Create ...
9999
func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error) {
100-
if err := d.setProject(ctx, r); err != nil {
101-
return 0, "", err
102-
}
103-
104100
var expiresAt int64
105101
if r.Duration == -1 {
106102
expiresAt = -1
@@ -327,22 +323,6 @@ func (d *controller) populatePermissions(ctx context.Context, r *Robot) error {
327323
return nil
328324
}
329325

330-
// set the project info if it's a project level robot
331-
func (d *controller) setProject(ctx context.Context, r *Robot) error {
332-
if r == nil {
333-
return nil
334-
}
335-
if r.Level == LEVELPROJECT {
336-
pro, err := d.proMgr.Get(ctx, r.Permissions[0].Namespace)
337-
if err != nil {
338-
return err
339-
}
340-
r.ProjectName = pro.Name
341-
r.ProjectID = pro.ProjectID
342-
}
343-
return nil
344-
}
345-
346326
// convertScope converts the db scope into robot model
347327
// /system => Kind: system Namespace: /
348328
// /project/* => Kind: project Namespace: *
@@ -394,6 +374,22 @@ func (d *controller) toScope(ctx context.Context, p *Permission) (string, error)
394374
return "", errors.New(nil).WithMessage("unknown robot kind").WithCode(errors.BadRequestCode)
395375
}
396376

377+
// set the project info if it's a project level robot
378+
func SetProject(ctx context.Context, r *Robot) error {
379+
if r == nil {
380+
return nil
381+
}
382+
if r.Level == LEVELPROJECT {
383+
pro, err := project.New().Get(ctx, r.Permissions[0].Namespace)
384+
if err != nil {
385+
return err
386+
}
387+
r.ProjectName = pro.Name
388+
r.ProjectID = pro.ProjectID
389+
}
390+
return nil
391+
}
392+
397393
func CreateSec(salt ...string) (string, string, string, error) {
398394
var secret, pwd string
399395
options := []retry.Option{

src/controller/robot/model.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ const (
3939
// Robot ...
4040
type Robot struct {
4141
model.Robot
42-
ProjectName string
43-
Level string
44-
Editable bool `json:"editable"`
45-
Permissions []*Permission `json:"permissions"`
42+
ProjectName string
43+
ProjectNameOrID interface{}
44+
Level string
45+
Editable bool `json:"editable"`
46+
Permissions []*Permission `json:"permissions"`
4647
}
4748

4849
// IsSysLevel, true is a system level robot, others are project level.

src/controller/scan/base_controller.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,8 @@ func (bc *basicController) makeRobotAccount(ctx context.Context, projectID int64
867867
CreatorType: "local",
868868
CreatorRef: int64(0),
869869
},
870-
Level: robot.LEVELPROJECT,
870+
ProjectName: projectName,
871+
Level: robot.LEVELPROJECT,
871872
Permissions: []*robot.Permission{
872873
{
873874
Kind: "project",

src/controller/scan/base_controller_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ func (suite *ControllerTestSuite) SetupSuite() {
238238
CreatorType: "local",
239239
CreatorRef: int64(0),
240240
},
241-
Level: robot.LEVELPROJECT,
241+
ProjectName: "library",
242+
Level: robot.LEVELPROJECT,
242243
Permissions: []*robot.Permission{
243244
{
244245
Kind: "project",

src/portal/src/app/base/left-side-nav/system-robot-accounts/system-robot-util.ts

+5
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ export const ACTION_RESOURCE_I18N_MAP = {
7979
'notification-policy': 'ROBOT_ACCOUNT.NOTIFICATION_POLICY',
8080
quota: 'ROBOT_ACCOUNT.QUOTA',
8181
sbom: 'ROBOT_ACCOUNT.SBOM',
82+
robot: 'ROBOT_ACCOUNT.ROBOT',
83+
user: 'ROBOT_ACCOUNT.USER',
84+
'user-group': 'ROBOT_ACCOUNT.GROUP',
85+
'ldap-user': 'ROBOT_ACCOUNT.LDAPUSER',
86+
member: 'ROBOT_ACCOUNT.MEMBER',
8287
};
8388

8489
export function convertKey(key: string) {

src/portal/src/i18n/lang/de-de-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,12 @@
423423
"SELECT_PERMISSIONS": "Select Permissions",
424424
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
425425
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
426-
"SYSTEM_PERMISSIONS": "System Permissions"
426+
"SYSTEM_PERMISSIONS": "System Permissions",
427+
"ROBOT": "Robot Account",
428+
"USER": "User",
429+
"LDAPUSER": "LDAP User",
430+
"GROUP": "User Group",
431+
"MEMBER": "Project Member"
427432
},
428433
"WEBHOOK": {
429434
"EDIT_BUTTON": "EDIT",

src/portal/src/i18n/lang/en-us-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,12 @@
423423
"SELECT_PERMISSIONS": "Select Permissions",
424424
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
425425
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
426-
"SYSTEM_PERMISSIONS": "System Permissions"
426+
"SYSTEM_PERMISSIONS": "System Permissions",
427+
"ROBOT": "Robot Account",
428+
"USER": "User",
429+
"LDAPUSER": "LDAP User",
430+
"GROUP": "User Group",
431+
"MEMBER": "Project Member"
427432
},
428433
"WEBHOOK": {
429434
"EDIT_BUTTON": "EDIT",

src/portal/src/i18n/lang/es-es-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,12 @@
424424
"SELECT_PERMISSIONS": "Select Permissions",
425425
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
426426
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
427-
"SYSTEM_PERMISSIONS": "System Permissions"
427+
"SYSTEM_PERMISSIONS": "System Permissions",
428+
"ROBOT": "Robot Account",
429+
"USER": "User",
430+
"LDAPUSER": "LDAP User",
431+
"GROUP": "User Group",
432+
"MEMBER": "Project Member"
428433
},
429434
"WEBHOOK": {
430435
"EDIT_BUTTON": "EDIT",

src/portal/src/i18n/lang/fr-fr-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,12 @@
423423
"SELECT_PERMISSIONS": "Selectionner les permissions",
424424
"SELECT_SYSTEM_PERMISSIONS": "Selectionner les permissions système",
425425
"SELECT_PROJECT_PERMISSIONS": "Selectionner les permissions projet",
426-
"SYSTEM_PERMISSIONS": "Permissions système"
426+
"SYSTEM_PERMISSIONS": "Permissions système",
427+
"ROBOT": "Robot Account",
428+
"USER": "User",
429+
"LDAPUSER": "LDAP User",
430+
"GROUP": "User Group",
431+
"MEMBER": "Project Member"
427432
},
428433
"WEBHOOK": {
429434
"EDIT_BUTTON": "Éditer",

src/portal/src/i18n/lang/ko-kr-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,12 @@
420420
"SELECT_PERMISSIONS": "권한 선택",
421421
"SELECT_SYSTEM_PERMISSIONS": "시스템 권한 선택",
422422
"SELECT_PROJECT_PERMISSIONS": "프로젝트 권한 선택",
423-
"SYSTEM_PERMISSIONS": "시스템 권한"
423+
"SYSTEM_PERMISSIONS": "시스템 권한",
424+
"ROBOT": "Robot Account",
425+
"USER": "User",
426+
"LDAPUSER": "LDAP User",
427+
"GROUP": "User Group",
428+
"MEMBER": "Project Member"
424429
},
425430
"WEBHOOK": {
426431
"EDIT_BUTTON": "편집",

src/portal/src/i18n/lang/pt-br-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,12 @@
421421
"SELECT_PERMISSIONS": "Select Permissions",
422422
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
423423
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
424-
"SYSTEM_PERMISSIONS": "System Permissions"
424+
"SYSTEM_PERMISSIONS": "System Permissions",
425+
"ROBOT": "Robot Account",
426+
"USER": "User",
427+
"LDAPUSER": "LDAP User",
428+
"GROUP": "User Group",
429+
"MEMBER": "Project Member"
425430
},
426431
"GROUP": {
427432
"GROUP": "Grupo",

src/portal/src/i18n/lang/tr-tr-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,12 @@
423423
"SELECT_PERMISSIONS": "Select Permissions",
424424
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
425425
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
426-
"SYSTEM_PERMISSIONS": "System Permissions"
426+
"SYSTEM_PERMISSIONS": "System Permissions",
427+
"ROBOT": "Robot Account",
428+
"USER": "User",
429+
"LDAPUSER": "LDAP User",
430+
"GROUP": "User Group",
431+
"MEMBER": "Project Member"
427432
},
428433
"WEBHOOK": {
429434
"EDIT_BUTTON": "DÜZENLE",

src/portal/src/i18n/lang/zh-cn-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,12 @@
421421
"SELECT_PERMISSIONS": "选择权限",
422422
"SELECT_SYSTEM_PERMISSIONS": "选择系统权限",
423423
"SELECT_PROJECT_PERMISSIONS": "选择项目权限",
424-
"SYSTEM_PERMISSIONS": "系统权限"
424+
"SYSTEM_PERMISSIONS": "系统权限",
425+
"ROBOT": "机器人账户",
426+
"USER": "用户",
427+
"LDAPUSER": "LDAP 用户",
428+
"GROUP": "用户组",
429+
"MEMBER": "项目成员"
425430
},
426431
"WEBHOOK": {
427432
"EDIT_BUTTON": "编辑",

src/portal/src/i18n/lang/zh-tw-lang.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,12 @@
422422
"SELECT_PERMISSIONS": "Select Permissions",
423423
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
424424
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
425-
"SYSTEM_PERMISSIONS": "System Permissions"
425+
"SYSTEM_PERMISSIONS": "System Permissions",
426+
"ROBOT": "Robot Account",
427+
"USER": "User",
428+
"LDAPUSER": "LDAP User",
429+
"GROUP": "User Group",
430+
"MEMBER": "Project Member"
426431
},
427432
"WEBHOOK": {
428433
"EDIT_BUTTON": "編輯",

src/server/v2.0/handler/permissions.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,12 @@ func (p *permissionsAPI) GetPermissions(ctx context.Context, _ permissions.GetPe
7171
return p.SendError(ctx, errors.ForbiddenError(errors.New("only admins(system and project) can access permissions")))
7272
}
7373

74+
provider := rbac.GetPermissionProvider()
7475
sysPermissions := make([]*types.Policy, 0)
75-
proPermissions := rbac.PoliciesMap["Project"]
76+
proPermissions := provider.GetPermissions(rbac.ScopeProject)
7677
if isSystemAdmin {
7778
// project admin cannot see the system level permissions
78-
sysPermissions = rbac.PoliciesMap["System"]
79+
sysPermissions = provider.GetPermissions(rbac.ScopeSystem)
7980
}
8081

8182
return permissions.NewGetPermissionsOK().WithPayload(p.convertPermissions(sysPermissions, proPermissions))

0 commit comments

Comments
 (0)