Skip to content

Commit

Permalink
add permission api
Browse files Browse the repository at this point in the history
The permission api targets to return the full set of permissons for robot to use.
And only system and project admin have the access

Signed-off-by: wang yan <[email protected]>
  • Loading branch information
wy65701436 committed Nov 6, 2023
1 parent ec0ef17 commit 3fbe34a
Show file tree
Hide file tree
Showing 10 changed files with 387 additions and 15 deletions.
39 changes: 38 additions & 1 deletion api/v2.0/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6140,7 +6140,31 @@ paths:
'401':
$ref: '#/responses/401'
'500':
$ref: '#/responses/500'
$ref: '#/responses/500'

/permissions:
get:
summary: Get system or project level permissions info.
operationId: getPermissions
description: |
This endpoint is for retrieving resource and action info that only provides for admin user(system admin and project admin).
tags:
- permissions
parameters:
- $ref: '#/parameters/requestId'
responses:
'200':
description: Get permissions successfully.
schema:
$ref: '#/definitions/Permissions'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'

parameters:
query:
Expand Down Expand Up @@ -9397,6 +9421,19 @@ definitions:
action:
type: string
description: The permission action
Permissions:
type: object
properties:
system:
type: array
description: The system level permissions
items:
$ref: '#/definitions/Permission'
project:
type: array
description: The project level permissions
items:
$ref: '#/definitions/Permission'
OIDCCliSecretReq:
type: object
properties:
Expand Down
149 changes: 149 additions & 0 deletions src/common/rbac/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package rbac

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

// const action variables
const (
ActionAll = Action("*") // action match any other actions
Expand Down Expand Up @@ -77,3 +79,150 @@ const (
ResourceJobServiceMonitor = Resource("jobservice-monitor")
ResourceSecurityHub = Resource("security-hub")
)

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

{Resource: ResourcePreatPolicy, Action: ActionRead},
{Resource: ResourcePreatPolicy, Action: ActionCreate},
{Resource: ResourcePreatPolicy, Action: ActionDelete},
{Resource: ResourcePreatPolicy, Action: ActionList},
{Resource: ResourcePreatPolicy, Action: ActionUpdate},

{Resource: ResourceProject, Action: ActionList},
{Resource: ResourceProject, Action: ActionCreate},

{Resource: ResourceReplicationPolicy, Action: ActionRead},
{Resource: ResourceReplicationPolicy, Action: ActionCreate},
{Resource: ResourceReplicationPolicy, Action: ActionDelete},
{Resource: ResourceReplicationPolicy, Action: ActionList},
{Resource: ResourceReplicationPolicy, Action: ActionUpdate},

{Resource: ResourceReplication, Action: ActionRead},
{Resource: ResourceReplication, Action: ActionCreate},
{Resource: ResourceReplication, Action: ActionDelete},
{Resource: ResourceReplication, Action: ActionList},
{Resource: ResourceReplication, Action: ActionUpdate},

{Resource: ResourceReplicationAdapter, Action: ActionList},

{Resource: ResourceRegistry, Action: ActionRead},
{Resource: ResourceRegistry, Action: ActionCreate},
{Resource: ResourceRegistry, Action: ActionDelete},
{Resource: ResourceRegistry, Action: ActionList},
{Resource: ResourceRegistry, Action: ActionUpdate},

{Resource: ResourceScanAll, Action: ActionRead},
{Resource: ResourceScanAll, Action: ActionUpdate},
{Resource: ResourceScanAll, Action: ActionStop},
{Resource: ResourceScanAll, Action: ActionCreate},

{Resource: ResourceSystemVolumes, Action: ActionRead},

{Resource: ResourceGarbageCollection, Action: ActionRead},
{Resource: ResourceGarbageCollection, Action: ActionCreate},
{Resource: ResourceGarbageCollection, Action: ActionDelete},
{Resource: ResourceGarbageCollection, Action: ActionList},
{Resource: ResourceGarbageCollection, Action: ActionUpdate},
{Resource: ResourceGarbageCollection, Action: ActionStop},

{Resource: ResourcePurgeAuditLog, Action: ActionRead},
{Resource: ResourcePurgeAuditLog, Action: ActionCreate},
{Resource: ResourcePurgeAuditLog, Action: ActionDelete},
{Resource: ResourcePurgeAuditLog, Action: ActionList},
{Resource: ResourcePurgeAuditLog, Action: ActionUpdate},
{Resource: ResourcePurgeAuditLog, Action: ActionStop},

{Resource: ResourceJobServiceMonitor, Action: ActionList},
{Resource: ResourceJobServiceMonitor, Action: ActionStop},

{Resource: ResourceTagRetention, Action: ActionRead},
{Resource: ResourceTagRetention, Action: ActionCreate},
{Resource: ResourceTagRetention, Action: ActionDelete},
{Resource: ResourceTagRetention, Action: ActionList},
{Resource: ResourceTagRetention, Action: ActionUpdate},

{Resource: ResourceScanner, Action: ActionRead},
{Resource: ResourceScanner, Action: ActionCreate},
{Resource: ResourceScanner, Action: ActionDelete},
{Resource: ResourceScanner, Action: ActionList},
{Resource: ResourceScanner, Action: ActionUpdate},

{Resource: ResourceLabel, Action: ActionRead},
{Resource: ResourceLabel, Action: ActionCreate},
{Resource: ResourceLabel, Action: ActionDelete},
{Resource: ResourceLabel, Action: ActionList},
{Resource: ResourceLabel, Action: ActionUpdate},

{Resource: ResourceExportCVE, Action: ActionRead},
{Resource: ResourceExportCVE, Action: ActionCreate},

{Resource: ResourceSecurityHub, Action: ActionRead},
{Resource: ResourceSecurityHub, Action: ActionList},

{Resource: ResourceCatalog, Action: ActionRead},
},
"Project": {
{Resource: ResourceLog, Action: ActionList},

{Resource: ResourceProject, Action: ActionRead},
{Resource: ResourceProject, Action: ActionDelete},
{Resource: ResourceProject, Action: ActionUpdate},

{Resource: ResourceMetadata, Action: ActionRead},
{Resource: ResourceMetadata, Action: ActionCreate},
{Resource: ResourceMetadata, Action: ActionDelete},
{Resource: ResourceMetadata, Action: ActionList},
{Resource: ResourceMetadata, Action: ActionUpdate},

{Resource: ResourceRepository, Action: ActionRead},
{Resource: ResourceRepository, Action: ActionCreate},
{Resource: ResourceRepository, Action: ActionList},
{Resource: ResourceRepository, Action: ActionUpdate},

{Resource: ResourceArtifact, Action: ActionRead},
{Resource: ResourceArtifact, Action: ActionCreate},
{Resource: ResourceArtifact, Action: ActionList},
{Resource: ResourceArtifact, Action: ActionDelete},

{Resource: ResourceScan, Action: ActionCreate},
{Resource: ResourceScan, Action: ActionRead},
{Resource: ResourceScan, Action: ActionStop},

{Resource: ResourceTag, Action: ActionCreate},
{Resource: ResourceTag, Action: ActionList},
{Resource: ResourceTag, Action: ActionDelete},

{Resource: ResourceAccessory, Action: ActionList},

{Resource: ResourceArtifactAddition, Action: ActionCreate},

{Resource: ResourceArtifactLabel, Action: ActionCreate},
{Resource: ResourceArtifactLabel, Action: ActionDelete},

{Resource: ResourceScanner, Action: ActionCreate},
{Resource: ResourceScanner, Action: ActionRead},

{Resource: ResourcePreatPolicy, Action: ActionRead},
{Resource: ResourcePreatPolicy, Action: ActionCreate},
{Resource: ResourcePreatPolicy, Action: ActionDelete},
{Resource: ResourcePreatPolicy, Action: ActionList},
{Resource: ResourcePreatPolicy, Action: ActionUpdate},

{Resource: ResourceImmutableTag, Action: ActionCreate},
{Resource: ResourceImmutableTag, Action: ActionDelete},
{Resource: ResourceImmutableTag, Action: ActionList},
{Resource: ResourceImmutableTag, Action: ActionUpdate},

{Resource: ResourceNotificationPolicy, Action: ActionRead},
{Resource: ResourceNotificationPolicy, Action: ActionCreate},
{Resource: ResourceNotificationPolicy, Action: ActionDelete},
{Resource: ResourceNotificationPolicy, Action: ActionList},
{Resource: ResourceNotificationPolicy, Action: ActionUpdate},

{Resource: ResourceRegistry, Action: ActionPush},
},
}
)
15 changes: 13 additions & 2 deletions src/controller/member/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,20 @@ import (

// Controller defines the operation related to project member
type Controller interface {
// Get get the project member with ID
// Get gets the project member with ID
Get(ctx context.Context, projectNameOrID interface{}, memberID int) (*models.Member, error)
// Create add project member to project
Create(ctx context.Context, projectNameOrID interface{}, req Request) (int, error)
// Delete member from project
Delete(ctx context.Context, projectNameOrID interface{}, memberID int) error
// List list all project members with condition
// List lists all project members with condition
List(ctx context.Context, projectNameOrID interface{}, entityName string, query *q.Query) ([]*models.Member, error)
// UpdateRole update the project member role
UpdateRole(ctx context.Context, projectNameOrID interface{}, memberID int, role int) error
// Count get the total amount of project members
Count(ctx context.Context, projectNameOrID interface{}, query *q.Query) (int, error)
// IsProjectAdmin judges if the user is a project admin of any project
IsProjectAdmin(ctx context.Context, memberID int) (bool, error)
}

// Request - Project Member Request
Expand Down Expand Up @@ -258,3 +260,12 @@ func (c *controller) Delete(ctx context.Context, projectNameOrID interface{}, me
}
return c.mgr.Delete(ctx, p.ProjectID, memberID)
}

func (c *controller) IsProjectAdmin(ctx context.Context, memberID int) (bool, error) {
members, err := c.projectMgr.ListAdminRolesOfUser(ctx, memberID)
if err != nil {
return false, err
}

return len(members) > 0, nil
}
8 changes: 8 additions & 0 deletions src/controller/member/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package member

import (
"context"
"fmt"
"testing"

Expand Down Expand Up @@ -95,6 +96,13 @@ func (suite *MemberControllerTestSuite) TestAddProjectMemberWithUserGroup() {
suite.NoError(err)
}

func (suite *MemberControllerTestSuite) TestIsProjectAdmin() {
mock.OnAnything(suite.projectMgr, "ListAdminRolesOfUser").Return([]models.Member{models.Member{ID: 2, ProjectID: 2}}, nil)
ok, err := suite.controller.IsProjectAdmin(context.Background(), 2)
suite.NoError(err)
suite.True(ok)
}

func TestMemberControllerTestSuite(t *testing.T) {
suite.Run(t, &MemberControllerTestSuite{})
}
4 changes: 4 additions & 0 deletions src/pkg/cached/project/redis/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ func (m *Manager) ListRoles(ctx context.Context, projectID int64, userID int, gr
return m.delegator.ListRoles(ctx, projectID, userID, groupIDs...)
}

func (m *Manager) ListAdminRolesOfUser(ctx context.Context, userID int) ([]models.Member, error) {
return m.delegator.ListAdminRolesOfUser(ctx, userID)
}

func (m *Manager) Delete(ctx context.Context, id int64) error {
p, err := m.Get(ctx, id)
if err != nil {
Expand Down
35 changes: 27 additions & 8 deletions src/pkg/project/dao/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@ import (

// DAO is the data access object interface for project
type DAO interface {
// Create create a project instance
// Create creates a project instance
Create(ctx context.Context, project *models.Project) (int64, error)
// Count returns the total count of projects according to the query
Count(ctx context.Context, query *q.Query) (total int64, err error)
// Delete delete the project instance by id
// Delete deletes the project instance by id
Delete(ctx context.Context, id int64) error
// Get get project instance by id
// Get gets project instance by id
Get(ctx context.Context, id int64) (*models.Project, error)
// GetByName get project instance by name
GetByName(ctx context.Context, name string) (*models.Project, error)
// List list projects
// List lists projects
List(ctx context.Context, query *q.Query) ([]*models.Project, error)
// Lists the roles of user for the specific project
// ListRoles the roles of user for the specific project
ListRoles(ctx context.Context, projectID int64, userID int, groupIDs ...int) ([]int, error)
// ListAdminRolesOfUser returns the roles of user for the all projects
ListAdminRolesOfUser(ctx context.Context, userID int) ([]models.Member, error)
}

// New returns an instance of the default DAO
Expand All @@ -51,7 +53,7 @@ func New() DAO {

type dao struct{}

// Create create a project instance
// Create creates a project instance
func (d *dao) Create(ctx context.Context, project *models.Project) (int64, error) {
var projectID int64

Expand Down Expand Up @@ -105,7 +107,7 @@ func (d *dao) Count(ctx context.Context, query *q.Query) (total int64, err error
return qs.Count()
}

// Delete delete the project instance by id
// Delete deletes the project instance by id
func (d *dao) Delete(ctx context.Context, id int64) error {
project, err := d.Get(ctx, id)
if err != nil {
Expand All @@ -124,7 +126,7 @@ func (d *dao) Delete(ctx context.Context, id int64) error {
return err
}

// Get get project instance by id
// Get gets project instance by id
func (d *dao) Get(ctx context.Context, id int64) (*models.Project, error) {
o, err := orm.FromContext(ctx)
if err != nil {
Expand Down Expand Up @@ -199,3 +201,20 @@ func (d *dao) ListRoles(ctx context.Context, projectID int64, userID int, groupI

return roles, nil
}

func (d *dao) ListAdminRolesOfUser(ctx context.Context, userID int) ([]models.Member, error) {
o, err := orm.FromContext(ctx)
if err != nil {
return nil, err
}

sql := `select b.* from project as a left join project_member as b on a.project_id = b.project_id where a.deleted = 'f' and b.entity_id = ? and b.entity_type = 'u' and b.role = 1;`

var members []models.Member
_, err = o.Raw(sql, userID).QueryRows(&members)
if err != nil {
return nil, err
}

return members, nil
}
Loading

0 comments on commit 3fbe34a

Please sign in to comment.