Skip to content

Commit

Permalink
enable robot full access (#20754)
Browse files Browse the repository at this point in the history
* 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 <wangyan@vmware.com>

* robot account permission enhancement

Update codes according to the proposal of goharbor/community#249

Signed-off-by: wang yan <wangyan@vmware.com>

---------

Signed-off-by: wang yan <wangyan@vmware.com>
  • Loading branch information
wy65701436 authored Sep 26, 2024
1 parent d42c347 commit e4fe61d
Show file tree
Hide file tree
Showing 19 changed files with 532 additions and 69 deletions.
89 changes: 85 additions & 4 deletions src/common/rbac/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

package rbac

import "github.com/goharbor/harbor/src/pkg/permission/types"
import (
"github.com/goharbor/harbor/src/pkg/permission/types"
)

// const action variables
const (
Expand Down Expand Up @@ -81,9 +83,88 @@ const (
ResourceSecurityHub = Resource("security-hub")
)

type scope string

const (
ScopeSystem = scope("System")
ScopeProject = scope("Project")
)

// RobotPermissionProvider defines the permission provider for robot account
type RobotPermissionProvider interface {
GetPermissions(s scope) []*types.Policy
}

// GetPermissionProvider gives the robot permission provider
func GetPermissionProvider() RobotPermissionProvider {
// TODO will determine by the ui configuration
return &NolimitProvider{}
}

// BaseProvider ...
type BaseProvider struct {
}

// GetPermissions ...
func (d *BaseProvider) GetPermissions(s scope) []*types.Policy {
return PoliciesMap[s]
}

// NolimitProvider ...
type NolimitProvider struct {
BaseProvider
}

// GetPermissions ...
func (n *NolimitProvider) GetPermissions(s scope) []*types.Policy {
if s == ScopeSystem {
return append(n.BaseProvider.GetPermissions(ScopeSystem),
&types.Policy{Resource: ResourceRobot, Action: ActionCreate},
&types.Policy{Resource: ResourceRobot, Action: ActionRead},
&types.Policy{Resource: ResourceRobot, Action: ActionUpdate},
&types.Policy{Resource: ResourceRobot, Action: ActionList},
&types.Policy{Resource: ResourceRobot, Action: ActionDelete},

&types.Policy{Resource: ResourceUser, Action: ActionCreate},
&types.Policy{Resource: ResourceUser, Action: ActionRead},
&types.Policy{Resource: ResourceUser, Action: ActionUpdate},
&types.Policy{Resource: ResourceUser, Action: ActionList},
&types.Policy{Resource: ResourceUser, Action: ActionDelete},

&types.Policy{Resource: ResourceLdapUser, Action: ActionCreate},
&types.Policy{Resource: ResourceLdapUser, Action: ActionList},

&types.Policy{Resource: ResourceExportCVE, Action: ActionCreate},
&types.Policy{Resource: ResourceExportCVE, Action: ActionRead},

&types.Policy{Resource: ResourceQuota, Action: ActionUpdate},

&types.Policy{Resource: ResourceUserGroup, Action: ActionCreate},
&types.Policy{Resource: ResourceUserGroup, Action: ActionRead},
&types.Policy{Resource: ResourceUserGroup, Action: ActionUpdate},
&types.Policy{Resource: ResourceUserGroup, Action: ActionList},
&types.Policy{Resource: ResourceUserGroup, Action: ActionDelete})
}
if s == ScopeProject {
return append(n.BaseProvider.GetPermissions(ScopeProject),
&types.Policy{Resource: ResourceRobot, Action: ActionCreate},
&types.Policy{Resource: ResourceRobot, Action: ActionRead},
&types.Policy{Resource: ResourceRobot, Action: ActionUpdate},
&types.Policy{Resource: ResourceRobot, Action: ActionList},
&types.Policy{Resource: ResourceRobot, Action: ActionDelete},

&types.Policy{Resource: ResourceMember, Action: ActionCreate},
&types.Policy{Resource: ResourceMember, Action: ActionRead},
&types.Policy{Resource: ResourceMember, Action: ActionUpdate},
&types.Policy{Resource: ResourceMember, Action: ActionList},
&types.Policy{Resource: ResourceMember, Action: ActionDelete})
}
return []*types.Policy{}
}

var (
PoliciesMap = map[string][]*types.Policy{
"System": {
PoliciesMap = map[scope][]*types.Policy{
ScopeSystem: {
{Resource: ResourceAuditLog, Action: ActionList},

{Resource: ResourcePreatInstance, Action: ActionRead},
Expand Down Expand Up @@ -154,7 +235,7 @@ var (
{Resource: ResourceQuota, Action: ActionRead},
{Resource: ResourceQuota, Action: ActionList},
},
"Project": {
ScopeProject: {
{Resource: ResourceLog, Action: ActionList},

{Resource: ResourceProject, Action: ActionRead},
Expand Down
36 changes: 36 additions & 0 deletions src/common/rbac/const_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package rbac

import (
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"

"github.com/stretchr/testify/assert"
"testing"
)

func TestBaseProvider(t *testing.T) {
permissionProvider := &BaseProvider{}
sysPermissions := permissionProvider.GetPermissions(ScopeSystem)

for _, per := range sysPermissions {
if per.Action == ActionCreate && per.Resource == ResourceRobot {
t.Fail()
}
}
}

func TestNolimitProvider(t *testing.T) {
permissionProvider := &BaseProvider{}
sysPermissions := permissionProvider.GetPermissions(ScopeSystem)

for _, per := range sysPermissions {
if per.Action == ActionCreate && per.Resource == ResourceRobot {
t.Log("no limit provider has the permission of robot account creation")
}
}
}

func TestGetPermissionProvider(t *testing.T) {
defaultPro := GetPermissionProvider()
_, ok := defaultPro.(*NolimitProvider)
assert.True(t, ok)
}
36 changes: 16 additions & 20 deletions src/controller/robot/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ func (d *controller) Count(ctx context.Context, query *q.Query) (int64, error) {

// Create ...
func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error) {
if err := d.setProject(ctx, r); err != nil {
return 0, "", err
}

var expiresAt int64
if r.Duration == -1 {
expiresAt = -1
Expand Down Expand Up @@ -327,22 +323,6 @@ func (d *controller) populatePermissions(ctx context.Context, r *Robot) error {
return nil
}

// set the project info if it's a project level robot
func (d *controller) setProject(ctx context.Context, r *Robot) error {
if r == nil {
return nil
}
if r.Level == LEVELPROJECT {
pro, err := d.proMgr.Get(ctx, r.Permissions[0].Namespace)
if err != nil {
return err
}
r.ProjectName = pro.Name
r.ProjectID = pro.ProjectID
}
return nil
}

// convertScope converts the db scope into robot model
// /system => Kind: system Namespace: /
// /project/* => Kind: project Namespace: *
Expand Down Expand Up @@ -394,6 +374,22 @@ func (d *controller) toScope(ctx context.Context, p *Permission) (string, error)
return "", errors.New(nil).WithMessage("unknown robot kind").WithCode(errors.BadRequestCode)
}

// set the project info if it's a project level robot
func SetProject(ctx context.Context, r *Robot) error {
if r == nil {
return nil
}
if r.Level == LEVELPROJECT {
pro, err := project.New().Get(ctx, r.Permissions[0].Namespace)
if err != nil {
return err
}
r.ProjectName = pro.Name
r.ProjectID = pro.ProjectID
}
return nil
}

func CreateSec(salt ...string) (string, string, string, error) {
var secret, pwd string
options := []retry.Option{
Expand Down
9 changes: 5 additions & 4 deletions src/controller/robot/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ const (
// Robot ...
type Robot struct {
model.Robot
ProjectName string
Level string
Editable bool `json:"editable"`
Permissions []*Permission `json:"permissions"`
ProjectName string
ProjectNameOrID interface{}
Level string
Editable bool `json:"editable"`
Permissions []*Permission `json:"permissions"`
}

// IsSysLevel, true is a system level robot, others are project level.
Expand Down
3 changes: 2 additions & 1 deletion src/controller/scan/base_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,8 @@ func (bc *basicController) makeRobotAccount(ctx context.Context, projectID int64
CreatorType: "local",
CreatorRef: int64(0),
},
Level: robot.LEVELPROJECT,
ProjectName: projectName,
Level: robot.LEVELPROJECT,
Permissions: []*robot.Permission{
{
Kind: "project",
Expand Down
3 changes: 2 additions & 1 deletion src/controller/scan/base_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ func (suite *ControllerTestSuite) SetupSuite() {
CreatorType: "local",
CreatorRef: int64(0),
},
Level: robot.LEVELPROJECT,
ProjectName: "library",
Level: robot.LEVELPROJECT,
Permissions: []*robot.Permission{
{
Kind: "project",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ export const ACTION_RESOURCE_I18N_MAP = {
'notification-policy': 'ROBOT_ACCOUNT.NOTIFICATION_POLICY',
quota: 'ROBOT_ACCOUNT.QUOTA',
sbom: 'ROBOT_ACCOUNT.SBOM',
robot: 'ROBOT_ACCOUNT.ROBOT',
user: 'ROBOT_ACCOUNT.USER',
'user-group': 'ROBOT_ACCOUNT.GROUP',
'ldap-user': 'ROBOT_ACCOUNT.LDAPUSER',
member: 'ROBOT_ACCOUNT.MEMBER',
};

export function convertKey(key: string) {
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/de-de-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,12 @@
"SELECT_PERMISSIONS": "Select Permissions",
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
"SYSTEM_PERMISSIONS": "System Permissions"
"SYSTEM_PERMISSIONS": "System Permissions",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "EDIT",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/en-us-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,12 @@
"SELECT_PERMISSIONS": "Select Permissions",
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
"SYSTEM_PERMISSIONS": "System Permissions"
"SYSTEM_PERMISSIONS": "System Permissions",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "EDIT",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/es-es-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,12 @@
"SELECT_PERMISSIONS": "Select Permissions",
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
"SYSTEM_PERMISSIONS": "System Permissions"
"SYSTEM_PERMISSIONS": "System Permissions",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "EDIT",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/fr-fr-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,12 @@
"SELECT_PERMISSIONS": "Selectionner les permissions",
"SELECT_SYSTEM_PERMISSIONS": "Selectionner les permissions système",
"SELECT_PROJECT_PERMISSIONS": "Selectionner les permissions projet",
"SYSTEM_PERMISSIONS": "Permissions système"
"SYSTEM_PERMISSIONS": "Permissions système",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "Éditer",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/ko-kr-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,12 @@
"SELECT_PERMISSIONS": "권한 선택",
"SELECT_SYSTEM_PERMISSIONS": "시스템 권한 선택",
"SELECT_PROJECT_PERMISSIONS": "프로젝트 권한 선택",
"SYSTEM_PERMISSIONS": "시스템 권한"
"SYSTEM_PERMISSIONS": "시스템 권한",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "편집",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/pt-br-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,12 @@
"SELECT_PERMISSIONS": "Select Permissions",
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
"SYSTEM_PERMISSIONS": "System Permissions"
"SYSTEM_PERMISSIONS": "System Permissions",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"GROUP": {
"GROUP": "Grupo",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/tr-tr-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,12 @@
"SELECT_PERMISSIONS": "Select Permissions",
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
"SYSTEM_PERMISSIONS": "System Permissions"
"SYSTEM_PERMISSIONS": "System Permissions",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "DÜZENLE",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/zh-cn-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,12 @@
"SELECT_PERMISSIONS": "选择权限",
"SELECT_SYSTEM_PERMISSIONS": "选择系统权限",
"SELECT_PROJECT_PERMISSIONS": "选择项目权限",
"SYSTEM_PERMISSIONS": "系统权限"
"SYSTEM_PERMISSIONS": "系统权限",
"ROBOT": "机器人账户",
"USER": "用户",
"LDAPUSER": "LDAP 用户",
"GROUP": "用户组",
"MEMBER": "项目成员"
},
"WEBHOOK": {
"EDIT_BUTTON": "编辑",
Expand Down
7 changes: 6 additions & 1 deletion src/portal/src/i18n/lang/zh-tw-lang.json
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,12 @@
"SELECT_PERMISSIONS": "Select Permissions",
"SELECT_SYSTEM_PERMISSIONS": "Select System Permissions",
"SELECT_PROJECT_PERMISSIONS": "Select Project Permissions",
"SYSTEM_PERMISSIONS": "System Permissions"
"SYSTEM_PERMISSIONS": "System Permissions",
"ROBOT": "Robot Account",
"USER": "User",
"LDAPUSER": "LDAP User",
"GROUP": "User Group",
"MEMBER": "Project Member"
},
"WEBHOOK": {
"EDIT_BUTTON": "編輯",
Expand Down
5 changes: 3 additions & 2 deletions src/server/v2.0/handler/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ func (p *permissionsAPI) GetPermissions(ctx context.Context, _ permissions.GetPe
return p.SendError(ctx, errors.ForbiddenError(errors.New("only admins(system and project) can access permissions")))
}

provider := rbac.GetPermissionProvider()
sysPermissions := make([]*types.Policy, 0)
proPermissions := rbac.PoliciesMap["Project"]
proPermissions := provider.GetPermissions(rbac.ScopeProject)
if isSystemAdmin {
// project admin cannot see the system level permissions
sysPermissions = rbac.PoliciesMap["System"]
sysPermissions = provider.GetPermissions(rbac.ScopeSystem)
}

return permissions.NewGetPermissionsOK().WithPayload(p.convertPermissions(sysPermissions, proPermissions))
Expand Down
Loading

0 comments on commit e4fe61d

Please sign in to comment.