Skip to content

Commit

Permalink
fix issue 19928 (#20409)
Browse files Browse the repository at this point in the history
* fix issue 19928

it needs to consider the user who is in any group that has been granted with the project admin role.

Signed-off-by: wang yan <[email protected]>
  • Loading branch information
wy65701436 committed May 15, 2024
1 parent 232f9ba commit 2977fec
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 36 deletions.
3 changes: 0 additions & 3 deletions src/common/rbac/project/rbac_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,7 @@ var (
{Resource: rbac.ResourceMember, Action: rbac.ActionRead},
{Resource: rbac.ResourceMember, Action: rbac.ActionList},

{Resource: rbac.ResourceMetadata, Action: rbac.ActionCreate},
{Resource: rbac.ResourceMetadata, Action: rbac.ActionRead},
{Resource: rbac.ResourceMetadata, Action: rbac.ActionUpdate},
{Resource: rbac.ResourceMetadata, Action: rbac.ActionDelete},

{Resource: rbac.ResourceLog, Action: rbac.ActionList},

Expand Down
7 changes: 4 additions & 3 deletions src/controller/member/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"

"github.com/goharbor/harbor/src/common"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/core/auth"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/q"
Expand All @@ -45,7 +46,7 @@ type Controller interface {
// 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)
IsProjectAdmin(ctx context.Context, member commonmodels.User) (bool, error)
}

// Request - Project Member Request
Expand Down Expand Up @@ -261,8 +262,8 @@ 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)
func (c *controller) IsProjectAdmin(ctx context.Context, member commonmodels.User) (bool, error) {
members, err := c.projectMgr.ListAdminRolesOfUser(ctx, member)
if err != nil {
return false, err
}
Expand Down
2 changes: 1 addition & 1 deletion src/controller/member/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (suite *MemberControllerTestSuite) TestAddProjectMemberWithUserGroup() {

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)
ok, err := suite.controller.IsProjectAdmin(context.Background(), comModels.User{UserID: 1})
suite.NoError(err)
suite.True(ok)
}
Expand Down
5 changes: 3 additions & 2 deletions src/pkg/cached/project/redis/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"time"

commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/lib/config"
"github.com/goharbor/harbor/src/lib/log"
Expand Down Expand Up @@ -75,8 +76,8 @@ 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) ListAdminRolesOfUser(ctx context.Context, user commonmodels.User) ([]models.Member, error) {
return m.delegator.ListAdminRolesOfUser(ctx, user)
}

func (m *Manager) Delete(ctx context.Context, id int64) error {
Expand Down
33 changes: 27 additions & 6 deletions src/pkg/project/dao/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"time"

"github.com/goharbor/harbor/src/common"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/lib"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/lib/q"
Expand All @@ -43,7 +44,7 @@ type DAO interface {
// 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)
ListAdminRolesOfUser(ctx context.Context, user commonmodels.User) ([]models.Member, error)
}

// New returns an instance of the default DAO
Expand Down Expand Up @@ -202,19 +203,39 @@ 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) {
func (d *dao) ListAdminRolesOfUser(ctx context.Context, user commonmodels.User) ([]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)
var membersU []models.Member
sqlU := `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;`
_, err = o.Raw(sqlU, user.UserID).QueryRows(&membersU)
if err != nil {
return nil, err
}

var membersG []models.Member
if len(user.GroupIDs) > 0 {
var params []interface{}
params = append(params, user.GroupIDs)
sqlG := fmt.Sprintf(`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 in ( %s ) and b.entity_type = 'g' and b.role = 1;`, orm.ParamPlaceholderForIn(len(user.GroupIDs)))
_, err = o.Raw(sqlG, params).QueryRows(&membersG)
if err != nil {
return nil, err
}
}

var members []models.Member
if len(membersU) > 0 {
members = append(members, membersU...)
}
if len(membersG) > 0 {
members = append(members, membersG...)
}

return members, nil
}
37 changes: 37 additions & 0 deletions src/pkg/project/dao/dao_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/stretchr/testify/suite"

"github.com/goharbor/harbor/src/common"
commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/orm"
Expand Down Expand Up @@ -341,6 +342,42 @@ func (suite *DaoTestSuite) TestListByMember() {
}
}

func (suite *DaoTestSuite) TestListAdminRolesOfUser() {
{
// projectAdmin and user groups
suite.WithUser(func(userID int64, username string) {
project := &models.Project{
Name: utils.GenerateRandomString(),
OwnerID: int(userID),
}
projectID, err := suite.dao.Create(orm.Context(), project)
suite.Nil(err)

defer suite.dao.Delete(orm.Context(), projectID)

suite.WithUserGroup(func(groupID int64, groupName string) {

o, err := orm.FromContext(orm.Context())
if err != nil {
suite.Fail("got error %v", err)
}

var pid int64
suite.Nil(o.Raw("INSERT INTO project_member (project_id, entity_id, role, entity_type) values (?, ?, ?, ?) RETURNING id", projectID, groupID, common.RoleProjectAdmin, "g").QueryRow(&pid))
defer o.Raw("DELETE FROM project_member WHERE id = ?", pid)

userTest := commonmodels.User{
UserID: int(userID),
GroupIDs: []int{int(groupID)},
}
roles, err := suite.dao.ListAdminRolesOfUser(orm.Context(), userTest)
suite.Nil(err)
suite.Len(roles, 2)
})
})
}
}

func (suite *DaoTestSuite) TestListRoles() {
{
// only projectAdmin
Expand Down
7 changes: 4 additions & 3 deletions src/pkg/project/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"regexp"
"strings"

commonmodels "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/q"
Expand Down Expand Up @@ -47,7 +48,7 @@ type Manager interface {
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)
ListAdminRolesOfUser(ctx context.Context, user commonmodels.User) ([]models.Member, error)
}

// New returns a default implementation of Manager
Expand Down Expand Up @@ -124,6 +125,6 @@ func (m *manager) ListRoles(ctx context.Context, projectID int64, userID int, gr
}

// ListAdminRolesOfUser returns the roles of user for the all projects
func (m *manager) ListAdminRolesOfUser(ctx context.Context, userID int) ([]models.Member, error) {
return m.dao.ListAdminRolesOfUser(ctx, userID)
func (m *manager) ListAdminRolesOfUser(ctx context.Context, user commonmodels.User) ([]models.Member, error) {
return m.dao.ListAdminRolesOfUser(ctx, user)
}
16 changes: 8 additions & 8 deletions src/server/v2.0/handler/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/common/security"
"github.com/goharbor/harbor/src/common/security/local"
"github.com/goharbor/harbor/src/controller/member"
"github.com/goharbor/harbor/src/controller/user"
"github.com/goharbor/harbor/src/lib/errors"
Expand Down Expand Up @@ -57,15 +58,14 @@ func (p *permissionsAPI) GetPermissions(ctx context.Context, _ permissions.GetPe
if secCtx.IsSysAdmin() {
isSystemAdmin = true
} else {
user, err := p.uc.GetByName(ctx, secCtx.GetUsername())
if err != nil {
return p.SendError(ctx, err)
if sc, ok := secCtx.(*local.SecurityContext); ok {
user := sc.User()
var err error
isProjectAdmin, err = p.mc.IsProjectAdmin(ctx, *user)
if err != nil {
return p.SendError(ctx, err)
}
}
is, err := p.mc.IsProjectAdmin(ctx, user.UserID)
if err != nil {
return p.SendError(ctx, err)
}
isProjectAdmin = is
}
if !isSystemAdmin && !isProjectAdmin {
return p.SendError(ctx, errors.ForbiddenError(errors.New("only admins(system and project) can access permissions")))
Expand Down
23 changes: 13 additions & 10 deletions src/testing/pkg/project/manager.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2977fec

Please sign in to comment.