mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-28 21:37:31 +02:00
Remove "GetMyProjects" and "GetProjectRoles" in the interface "security.Context"
Fixes #11125, remove "GetMyProjects" and "GetProjectRoles" in the interface "security.Context" Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
83f46869d5
commit
0a372a85eb
@ -399,22 +399,6 @@ func TestGetProjectById(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserProjectRoles(t *testing.T) {
|
||||
r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID, common.UserMember)
|
||||
if err != nil {
|
||||
t.Errorf("Error happened in GetUserProjectRole: %v, userID: %+v, project Id: %d", err, currentUser.UserID, currentProject.ProjectID)
|
||||
}
|
||||
|
||||
// Get the size of current user project role.
|
||||
if len(r) != 1 {
|
||||
t.Errorf("The user, id: %d, should only have one role in project, id: %d, but actual: %d", currentUser.UserID, currentProject.ProjectID, len(r))
|
||||
}
|
||||
|
||||
if r[0].Name != "projectAdmin" {
|
||||
t.Errorf("the expected rolename is: projectAdmin, actual: %s", r[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTotalOfProjects(t *testing.T) {
|
||||
total, err := GetTotalOfProjects(nil)
|
||||
if err != nil {
|
||||
@ -439,23 +423,6 @@ func TestGetProjects(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRoleByID(t *testing.T) {
|
||||
r, err := GetRoleByID(models.PROJECTADMIN)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to call GetRoleByID: %v", err)
|
||||
}
|
||||
if r == nil || r.Name != "projectAdmin" || r.RoleCode != "MDRWS" {
|
||||
t.Errorf("Role does not match for role id: %d, actual: %+v", models.PROJECTADMIN, r)
|
||||
}
|
||||
r, err = GetRoleByID(9999)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to call GetRoleByID: %v", err)
|
||||
}
|
||||
if r != nil {
|
||||
t.Errorf("Role should nil for non-exist id 9999, actual: %+v", r)
|
||||
}
|
||||
}
|
||||
|
||||
// isAdminRole returns whether the user is admin.
|
||||
func isAdminRole(userIDOrUsername interface{}) (bool, error) {
|
||||
u := models.User{}
|
||||
|
@ -394,57 +394,6 @@ func TestGetTotalGroupProjects(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestGetRolesByLDAPGroup(t *testing.T) {
|
||||
|
||||
userGroupList, err := QueryUserGroup(models.UserGroup{LdapGroupDN: "cn=harbor_users,ou=sample,ou=vmware,dc=harbor,dc=com", GroupType: 1})
|
||||
if err != nil || len(userGroupList) < 1 {
|
||||
t.Errorf("failed to query user group, err %v", err)
|
||||
}
|
||||
|
||||
userGroups := []models.UserGroup{
|
||||
{GroupName: "test_http_group", GroupType: common.HTTPGroupType},
|
||||
{GroupName: "test_myhttp_group", GroupType: common.HTTPGroupType},
|
||||
}
|
||||
|
||||
gl2, err2 := PopulateGroup(userGroups)
|
||||
if err2 != nil || len(gl2) != 2 {
|
||||
t.Errorf("failed to query http user group, err %v", err)
|
||||
}
|
||||
project, err := dao.GetProjectByName("member_test_01")
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred when Get project by name: %v", err)
|
||||
}
|
||||
privateProject, err := dao.GetProjectByName("group_project_private")
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred when Get project by name: %v", err)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
projectID int64
|
||||
groupIDs []int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantSize int
|
||||
wantErr bool
|
||||
}{
|
||||
{"Check normal", args{projectID: project.ProjectID, groupIDs: []int{userGroupList[0].ID, gl2[0], gl2[1]}}, 2, false},
|
||||
{"Check non exist", args{projectID: privateProject.ProjectID, groupIDs: []int{9999}}, 0, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := dao.GetRolesByGroupID(tt.args.projectID, tt.args.groupIDs)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("TestGetRolesByLDAPGroup() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if len(got) != tt.wantSize {
|
||||
t.Errorf("TestGetRolesByLDAPGroup() = %v, want %v", len(got), tt.wantSize)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncGroupByGroupKey(t *testing.T) {
|
||||
type args []models.UserGroup
|
||||
|
@ -39,7 +39,7 @@ func AddProject(project models.Project) (int64, error) {
|
||||
pmID, err := addProjectMember(models.Member{
|
||||
ProjectID: projectID,
|
||||
EntityID: project.OwnerID,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
EntityType: common.UserMember,
|
||||
})
|
||||
if err != nil {
|
||||
@ -294,25 +294,3 @@ func DeleteProject(id int64) error {
|
||||
_, err = GetOrmer().Raw(sql, name, id).Exec()
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRolesByGroupID - Get Project roles of the
|
||||
// specified group is a member of current project
|
||||
func GetRolesByGroupID(projectID int64, groupIDs []int) ([]int, error) {
|
||||
var roles []int
|
||||
if len(groupIDs) == 0 {
|
||||
return roles, nil
|
||||
}
|
||||
groupIDCondition := JoinNumberConditions(groupIDs)
|
||||
o := GetOrmer()
|
||||
sql := fmt.Sprintf(
|
||||
`select distinct pm.role from project_member pm
|
||||
left join user_group ug on pm.entity_type = 'g' and pm.entity_id = ug.id
|
||||
where ug.id in ( %s ) and pm.project_id = ?`,
|
||||
groupIDCondition)
|
||||
log.Debugf("sql for GetRolesByGroupID(project ID: %d, group ids: %v):%v", projectID, groupIDs, sql)
|
||||
if _, err := o.Raw(sql, projectID).QueryRows(&roles); err != nil {
|
||||
log.Warningf("Error in GetRolesByGroupID, error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return roles, nil
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ package project
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
@ -169,3 +168,30 @@ func SearchMemberByName(projectID int64, entityName string) ([]*models.Member, e
|
||||
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
||||
return members, err
|
||||
}
|
||||
|
||||
// ListRoles lists the roles of user for the specific project
|
||||
func ListRoles(user *models.User, projectID int64) ([]int, error) {
|
||||
if user == nil {
|
||||
return nil, nil
|
||||
}
|
||||
var params []interface{}
|
||||
sql := `
|
||||
select role
|
||||
from project_member
|
||||
where entity_type = 'u' and entity_id = ? and project_id = ? `
|
||||
params = append(params, user.UserID, projectID)
|
||||
if len(user.GroupIDs) > 0 {
|
||||
sql += fmt.Sprintf(`union
|
||||
select role
|
||||
from project_member
|
||||
where entity_type = 'g' and entity_id in ( %s ) and project_id = ? `, dao.ParamPlaceholderForIn(len(user.GroupIDs)))
|
||||
params = append(params, user.GroupIDs)
|
||||
params = append(params, projectID)
|
||||
}
|
||||
roles := []int{}
|
||||
_, err := dao.GetOrmer().Raw(sql, params).QueryRows(&roles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roles, nil
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ package project
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/dao/group"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -89,7 +92,7 @@ func TestDeleteProjectMemberByID(t *testing.T) {
|
||||
ProjectID: currentProject.ProjectID,
|
||||
EntityID: 1,
|
||||
EntityType: common.UserMember,
|
||||
Role: models.DEVELOPER,
|
||||
Role: common.RoleDeveloper,
|
||||
}
|
||||
|
||||
pmid, err := AddProjectMember(addMember)
|
||||
@ -129,7 +132,7 @@ func TestAddProjectMember(t *testing.T) {
|
||||
ProjectID: currentProject.ProjectID,
|
||||
EntityID: 1,
|
||||
EntityType: common.UserMember,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
}
|
||||
|
||||
log.Debugf("Current project id %v", currentProject.ProjectID)
|
||||
@ -159,7 +162,7 @@ func TestAddProjectMember(t *testing.T) {
|
||||
ProjectID: -1,
|
||||
EntityID: 1,
|
||||
EntityType: common.UserMember,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Should failed with negative projectID")
|
||||
@ -168,7 +171,7 @@ func TestAddProjectMember(t *testing.T) {
|
||||
ProjectID: 1,
|
||||
EntityID: -1,
|
||||
EntityType: common.UserMember,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Should failed with negative entityID")
|
||||
@ -191,7 +194,7 @@ func TestUpdateProjectMemberRole(t *testing.T) {
|
||||
ProjectID: currentProject.ProjectID,
|
||||
EntityID: int(userID),
|
||||
EntityType: common.UserMember,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
}
|
||||
|
||||
pmid, err := AddProjectMember(member)
|
||||
@ -199,7 +202,7 @@ func TestUpdateProjectMemberRole(t *testing.T) {
|
||||
t.Errorf("Error occurred in UpdateProjectMember: %v", err)
|
||||
}
|
||||
|
||||
UpdateProjectMemberRole(pmid, models.DEVELOPER)
|
||||
UpdateProjectMemberRole(pmid, common.RoleDeveloper)
|
||||
|
||||
queryMember := models.Member{
|
||||
ProjectID: currentProject.ProjectID,
|
||||
@ -215,7 +218,7 @@ func TestUpdateProjectMemberRole(t *testing.T) {
|
||||
t.Errorf("Error occurred in Failed, size: %d, condition:%+v", len(memberList), queryMember)
|
||||
}
|
||||
memberItem := memberList[0]
|
||||
if memberItem.Role != models.DEVELOPER || memberItem.Entityname != user.Username {
|
||||
if memberItem.Role != common.RoleDeveloper || memberItem.Entityname != user.Username {
|
||||
t.Errorf("member doesn't match!")
|
||||
}
|
||||
|
||||
@ -325,6 +328,55 @@ func TestGetTotalOfProjectMembers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRoles(t *testing.T) {
|
||||
// nil user
|
||||
roles, err := ListRoles(nil, 1)
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, roles, 0)
|
||||
|
||||
user, err := dao.GetUser(models.User{Username: "member_test_01"})
|
||||
require.Nil(t, err)
|
||||
project, err := dao.GetProjectByName("member_test_01")
|
||||
require.Nil(t, err)
|
||||
|
||||
// user with empty groups
|
||||
roles, err = ListRoles(user, project.ProjectID)
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, roles, 1)
|
||||
|
||||
// user with a group whose ID doesn't exist
|
||||
user.GroupIDs = []int{9999}
|
||||
roles, err = ListRoles(user, project.ProjectID)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, roles, 1)
|
||||
assert.Equal(t, common.RoleProjectAdmin, roles[0])
|
||||
|
||||
// user with a valid group
|
||||
groupID, err := group.AddUserGroup(models.UserGroup{
|
||||
GroupName: "group_for_list_role",
|
||||
GroupType: 1,
|
||||
LdapGroupDN: "CN=list_role_users,OU=sample,OU=vmware,DC=harbor,DC=com",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer group.DeleteUserGroup(groupID)
|
||||
|
||||
memberID, err := AddProjectMember(models.Member{
|
||||
ProjectID: project.ProjectID,
|
||||
Role: common.RoleDeveloper,
|
||||
EntityID: groupID,
|
||||
EntityType: "g",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer DeleteProjectMemberByID(memberID)
|
||||
|
||||
user.GroupIDs = []int{groupID}
|
||||
roles, err = ListRoles(user, project.ProjectID)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, roles, 2)
|
||||
assert.Equal(t, common.RoleProjectAdmin, roles[0])
|
||||
assert.Equal(t, common.RoleDeveloper, roles[1])
|
||||
}
|
||||
|
||||
func PrepareGroupTest() {
|
||||
initSqls := []string{
|
||||
`insert into user_group (group_name, group_type, ldap_group_dn) values ('harbor_group_01', 1, 'cn=harbor_user,dc=example,dc=com')`,
|
||||
|
@ -1,61 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
)
|
||||
|
||||
// GetUserProjectRoles returns roles that the user has according to the project.
|
||||
func GetUserProjectRoles(userID int, projectID int64, entityType string) ([]models.Role, error) {
|
||||
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select *
|
||||
from role
|
||||
where role_id =
|
||||
(
|
||||
select role
|
||||
from project_member
|
||||
where project_id = ? and entity_id = ? and entity_type = 'u'
|
||||
)`
|
||||
|
||||
var roleList []models.Role
|
||||
_, err := o.Raw(sql, projectID, userID).QueryRows(&roleList)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleList, nil
|
||||
}
|
||||
|
||||
// GetRoleByID ...
|
||||
func GetRoleByID(id int) (*models.Role, error) {
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select *
|
||||
from role
|
||||
where role_id = ?`
|
||||
|
||||
var role models.Role
|
||||
if err := o.Raw(sql, id).QueryRow(&role); err != nil {
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &role, nil
|
||||
}
|
@ -14,20 +14,10 @@
|
||||
|
||||
package models
|
||||
|
||||
const (
|
||||
// PROJECTADMIN project administrator
|
||||
PROJECTADMIN = 1
|
||||
// DEVELOPER developer
|
||||
DEVELOPER = 2
|
||||
// GUEST guest
|
||||
GUEST = 3
|
||||
)
|
||||
|
||||
// Role holds the details of a role.
|
||||
type Role struct {
|
||||
RoleID int `orm:"pk;auto;column(role_id)" json:"role_id"`
|
||||
RoleCode string `orm:"column(role_code)" json:"role_code"`
|
||||
Name string `orm:"column(name)" json:"role_name"`
|
||||
|
||||
RoleMask int `orm:"column(role_mask)" json:"role_mask"`
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
pro "github.com/goharbor/harbor/src/common/dao/project"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/security"
|
||||
"github.com/goharbor/harbor/src/core/promgr"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
@ -24,8 +26,8 @@ import (
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
)
|
||||
|
||||
// NewProjectRBACEvaluator returns permission evaluator for project
|
||||
func NewProjectRBACEvaluator(ctx security.Context, pm promgr.ProjectManager) evaluator.Evaluator {
|
||||
// NewProjectUserEvaluator returns permission evaluator for project
|
||||
func NewProjectUserEvaluator(user *models.User, pm promgr.ProjectManager) evaluator.Evaluator {
|
||||
return namespace.New(ProjectNamespaceKind, func(ns types.Namespace) evaluator.Evaluator {
|
||||
project, err := pm.Get(ns.Identity())
|
||||
if err != nil || project == nil {
|
||||
@ -35,9 +37,13 @@ func NewProjectRBACEvaluator(ctx security.Context, pm promgr.ProjectManager) eva
|
||||
return nil
|
||||
}
|
||||
|
||||
if ctx.IsAuthenticated() {
|
||||
roles := ctx.GetProjectRoles(project.ProjectID)
|
||||
return rbac.New(NewProjectRBACUser(project, ctx.GetUsername(), roles...))
|
||||
if user != nil {
|
||||
roles, err := pro.ListRoles(user, project.ProjectID)
|
||||
if err != nil {
|
||||
log.Errorf("failed to list roles: %v", err)
|
||||
return nil
|
||||
}
|
||||
return rbac.New(NewProjectRBACUser(project, user.Username, roles...))
|
||||
} else if project.IsPublic() {
|
||||
// anonymous access and the project is public
|
||||
return rbac.New(NewProjectRBACUser(project, "anonymous"))
|
||||
|
@ -15,15 +15,17 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/dao/project"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
promgr "github.com/goharbor/harbor/src/core/promgr/mocks"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
"github.com/goharbor/harbor/src/testing/common/security"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -72,10 +74,10 @@ func makeResource(subresource ...types.Resource) types.Resource {
|
||||
|
||||
func TestAnonymousAccess(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
evaluator1 := NewProjectRBACEvaluator(anonymousSecurity, publicProjectManager)
|
||||
evaluator1 := NewProjectUserEvaluator(nil, publicProjectManager)
|
||||
assert.True(evaluator1.HasPermission(makeResource(ResourceRepository), ActionPull))
|
||||
|
||||
evaluator2 := NewProjectRBACEvaluator(anonymousSecurity, privateProjectManager)
|
||||
evaluator2 := NewProjectUserEvaluator(nil, privateProjectManager)
|
||||
assert.False(evaluator2.HasPermission(makeResource(ResourceRepository), ActionPull))
|
||||
|
||||
evaluator3 := NewProjectRobotEvaluator(anonymousSecurity, publicProjectManager, func(ns types.Namespace) types.RBACUser { return nil })
|
||||
@ -87,15 +89,41 @@ func TestAnonymousAccess(t *testing.T) {
|
||||
|
||||
func TestProjectRoleAccess(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
evaluator1 := NewProjectRBACEvaluator(projectAdminSecurity, publicProjectManager)
|
||||
assert.True(evaluator1.HasPermission(makeResource(ResourceRepository), ActionPush))
|
||||
dao.PrepareTestForPostgresSQL()
|
||||
|
||||
evaluator2 := NewProjectRBACEvaluator(guestSecurity, publicProjectManager)
|
||||
assert.False(evaluator2.HasPermission(makeResource(ResourceRepository), ActionPush))
|
||||
projectID, err := dao.AddProject(models.Project{
|
||||
OwnerID: 1,
|
||||
Name: "project_for_test_evaluator",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer dao.DeleteProject(projectID)
|
||||
|
||||
pm := makeMockProjectManager(projectID, true)
|
||||
|
||||
memberID, err := project.AddProjectMember(models.Member{
|
||||
ProjectID: projectID,
|
||||
Role: common.RoleProjectAdmin,
|
||||
EntityID: 1,
|
||||
EntityType: "u",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer project.DeleteProjectMemberByID(memberID)
|
||||
evaluator1 := NewProjectUserEvaluator(&models.User{
|
||||
UserID: 1,
|
||||
Username: "admin",
|
||||
}, pm)
|
||||
assert.True(evaluator1.HasPermission(NewProjectNamespace(projectID).Resource(ResourceRepository), ActionPush))
|
||||
|
||||
project.UpdateProjectMemberRole(memberID, common.RoleGuest)
|
||||
evaluator2 := NewProjectUserEvaluator(&models.User{
|
||||
UserID: 1,
|
||||
Username: "admin",
|
||||
}, pm)
|
||||
assert.False(evaluator2.HasPermission(NewProjectNamespace(projectID).Resource(ResourceRepository), ActionPush))
|
||||
}
|
||||
|
||||
func BenchmarkProjectRBACEvaluator(b *testing.B) {
|
||||
evaluator := NewProjectRBACEvaluator(projectAdminSecurity, publicProjectManager)
|
||||
evaluator := NewProjectUserEvaluator(nil, publicProjectManager)
|
||||
resource := NewProjectNamespace(projectID).Resource(ResourceRepository)
|
||||
|
||||
b.ResetTimer()
|
||||
@ -105,7 +133,7 @@ func BenchmarkProjectRBACEvaluator(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkProjectRBACEvaluatorParallel(b *testing.B) {
|
||||
evaluator := NewProjectRBACEvaluator(projectAdminSecurity, publicProjectManager)
|
||||
evaluator := NewProjectUserEvaluator(nil, publicProjectManager)
|
||||
resource := NewProjectNamespace(projectID).Resource(ResourceRepository)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
|
@ -17,7 +17,6 @@ package security
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
)
|
||||
|
||||
@ -33,10 +32,6 @@ type Context interface {
|
||||
IsSysAdmin() bool
|
||||
// IsSolutionUser returns whether the user is solution user
|
||||
IsSolutionUser() bool
|
||||
// Get current user's all project
|
||||
GetMyProjects() ([]*models.Project, error)
|
||||
// Get user's role in provided project
|
||||
GetProjectRoles(projectIDOrName interface{}) []int
|
||||
// Can returns whether the user can do action on resource
|
||||
Can(action types.Action, resource types.Resource) bool
|
||||
}
|
||||
|
@ -17,12 +17,9 @@ package local
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/core/promgr"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/evaluator"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/evaluator/admin"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
@ -89,109 +86,10 @@ func (s *SecurityContext) Can(action types.Action, resource types.Resource) bool
|
||||
if s.IsSysAdmin() {
|
||||
evaluators = evaluators.Add(admin.New(s.GetUsername()))
|
||||
}
|
||||
evaluators = evaluators.Add(rbac.NewProjectRBACEvaluator(s, s.pm))
|
||||
evaluators = evaluators.Add(rbac.NewProjectUserEvaluator(s.User(), s.pm))
|
||||
|
||||
s.evaluator = evaluators
|
||||
})
|
||||
|
||||
return s.evaluator != nil && s.evaluator.HasPermission(resource, action)
|
||||
}
|
||||
|
||||
// GetProjectRoles ...
|
||||
func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
||||
if !s.IsAuthenticated() || projectIDOrName == nil {
|
||||
return []int{}
|
||||
}
|
||||
|
||||
roles := []int{}
|
||||
user, err := dao.GetUser(models.User{
|
||||
Username: s.GetUsername(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("failed to get user %s: %v", s.GetUsername(), err)
|
||||
return roles
|
||||
}
|
||||
if user == nil {
|
||||
log.Debugf("user %s not found", s.GetUsername())
|
||||
return roles
|
||||
}
|
||||
project, err := s.pm.Get(projectIDOrName)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get project %v: %v", projectIDOrName, err)
|
||||
return roles
|
||||
}
|
||||
if project == nil {
|
||||
log.Errorf("project %v not found", projectIDOrName)
|
||||
return roles
|
||||
}
|
||||
roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID, common.UserMember)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get roles of user %d to project %d: %v", user.UserID, project.ProjectID, err)
|
||||
return roles
|
||||
}
|
||||
for _, role := range roleList {
|
||||
switch role.RoleCode {
|
||||
case "MDRWS":
|
||||
roles = append(roles, common.RoleProjectAdmin)
|
||||
case "DRWS":
|
||||
roles = append(roles, common.RoleMaster)
|
||||
case "RWS":
|
||||
roles = append(roles, common.RoleDeveloper)
|
||||
case "RS":
|
||||
roles = append(roles, common.RoleGuest)
|
||||
case "LRS":
|
||||
roles = append(roles, common.RoleLimitedGuest)
|
||||
}
|
||||
}
|
||||
return mergeRoles(roles, s.GetRolesByGroup(projectIDOrName))
|
||||
}
|
||||
|
||||
func mergeRoles(rolesA, rolesB []int) []int {
|
||||
type void struct{}
|
||||
var roles []int
|
||||
var placeHolder void
|
||||
roleSet := make(map[int]void)
|
||||
for _, r := range rolesA {
|
||||
roleSet[r] = placeHolder
|
||||
}
|
||||
for _, r := range rolesB {
|
||||
roleSet[r] = placeHolder
|
||||
}
|
||||
for r := range roleSet {
|
||||
roles = append(roles, r)
|
||||
}
|
||||
return roles
|
||||
}
|
||||
|
||||
// GetRolesByGroup - Get the group role of current user to the project
|
||||
func (s *SecurityContext) GetRolesByGroup(projectIDOrName interface{}) []int {
|
||||
var roles []int
|
||||
user := s.user
|
||||
project, err := s.pm.Get(projectIDOrName)
|
||||
// No user, group or project info
|
||||
if err != nil || project == nil || user == nil || len(user.GroupIDs) == 0 {
|
||||
return roles
|
||||
}
|
||||
// Get role by Group ID
|
||||
roles, err = dao.GetRolesByGroupID(project.ProjectID, user.GroupIDs)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return roles
|
||||
}
|
||||
|
||||
// GetMyProjects ...
|
||||
func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
||||
result, err := s.pm.List(
|
||||
&models.ProjectQueryParam{
|
||||
Member: &models.MemberQuery{
|
||||
Name: s.GetUsername(),
|
||||
GroupIDs: s.user.GroupIDs,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result.Projects, nil
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/core/promgr/pmsdriver/local"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -272,43 +271,6 @@ func TestHasPushPullPermWithGroup(t *testing.T) {
|
||||
assert.True(t, ctx.Can(rbac.ActionPull, resource))
|
||||
}
|
||||
|
||||
func TestGetMyProjects(t *testing.T) {
|
||||
ctx := NewSecurityContext(guestUser, pm)
|
||||
projects, err := ctx.GetMyProjects()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 1, len(projects))
|
||||
assert.Equal(t, private.ProjectID, projects[0].ProjectID)
|
||||
}
|
||||
|
||||
func TestGetProjectRoles(t *testing.T) {
|
||||
// unauthenticated
|
||||
ctx := NewSecurityContext(nil, pm)
|
||||
roles := ctx.GetProjectRoles(private.Name)
|
||||
assert.Equal(t, 0, len(roles))
|
||||
|
||||
// authenticated, project name of ID is nil
|
||||
ctx = NewSecurityContext(guestUser, pm)
|
||||
roles = ctx.GetProjectRoles(nil)
|
||||
assert.Equal(t, 0, len(roles))
|
||||
|
||||
// authenticated, has read perm
|
||||
ctx = NewSecurityContext(guestUser, pm)
|
||||
roles = ctx.GetProjectRoles(private.Name)
|
||||
assert.Equal(t, 1, len(roles))
|
||||
assert.Equal(t, common.RoleGuest, roles[0])
|
||||
|
||||
// authenticated, has write perm
|
||||
ctx = NewSecurityContext(developerUser, pm)
|
||||
roles = ctx.GetProjectRoles(private.Name)
|
||||
assert.Equal(t, 1, len(roles))
|
||||
assert.Equal(t, common.RoleDeveloper, roles[0])
|
||||
|
||||
// authenticated, has all perms
|
||||
ctx = NewSecurityContext(projectAdminUser, pm)
|
||||
roles = ctx.GetProjectRoles(private.Name)
|
||||
assert.Equal(t, 1, len(roles))
|
||||
assert.Equal(t, common.RoleProjectAdmin, roles[0])
|
||||
}
|
||||
func PrepareGroupTest() {
|
||||
initSqls := []string{
|
||||
`insert into user_group (group_name, group_type, ldap_group_dn) values ('harbor_group_01', 1, 'cn=harbor_user,dc=example,dc=com')`,
|
||||
@ -329,106 +291,3 @@ func PrepareGroupTest() {
|
||||
}
|
||||
dao.PrepareTestData(clearSqls, initSqls)
|
||||
}
|
||||
|
||||
func TestSecurityContext_GetRolesByGroup(t *testing.T) {
|
||||
PrepareGroupTest()
|
||||
project, err := dao.GetProjectByName("group_project")
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred when GetProjectByName: %v", err)
|
||||
}
|
||||
developer, err := dao.GetUser(models.User{Username: "sample01"})
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred when GetUser: %v", err)
|
||||
}
|
||||
userGroups, err := group.QueryUserGroup(models.UserGroup{GroupType: common.LDAPGroupType, LdapGroupDN: "cn=harbor_user,dc=example,dc=com"})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to query user group %v", err)
|
||||
}
|
||||
if len(userGroups) < 1 {
|
||||
t.Errorf("Failed to retrieve user group")
|
||||
}
|
||||
|
||||
developer.GroupIDs = []int{userGroups[0].ID}
|
||||
type fields struct {
|
||||
user *models.User
|
||||
pm promgr.ProjectManager
|
||||
}
|
||||
type args struct {
|
||||
projectIDOrName interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want []int
|
||||
}{
|
||||
{"Developer", fields{user: developer, pm: pm}, args{project.ProjectID}, []int{2}},
|
||||
{"Guest", fields{user: guestUser, pm: pm}, args{project.ProjectID}, []int{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &SecurityContext{
|
||||
user: tt.fields.user,
|
||||
pm: tt.fields.pm,
|
||||
}
|
||||
if got := s.GetRolesByGroup(tt.args.projectIDOrName); !dao.ArrayEqual(got, tt.want) {
|
||||
t.Errorf("SecurityContext.GetRolesByGroup() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecurityContext_GetMyProjects(t *testing.T) {
|
||||
type fields struct {
|
||||
user *models.User
|
||||
pm promgr.ProjectManager
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantSize int
|
||||
wantErr bool
|
||||
}{
|
||||
{"Admin", fields{user: projectAdminUser, pm: pm}, 1, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &SecurityContext{
|
||||
user: tt.fields.user,
|
||||
pm: tt.fields.pm,
|
||||
}
|
||||
got, err := s.GetMyProjects()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("SecurityContext.GetMyProjects() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if len(got) != tt.wantSize {
|
||||
t.Errorf("SecurityContext.GetMyProjects() = %v, want %v", len(got), tt.wantSize)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_mergeRoles(t *testing.T) {
|
||||
type args struct {
|
||||
rolesA []int
|
||||
rolesB []int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []int
|
||||
}{
|
||||
{"normal", args{[]int{3, 4}, []int{1, 2, 3, 4}}, []int{1, 2, 3, 4}},
|
||||
{"empty", args{[]int{}, []int{}}, []int{}},
|
||||
{"left empty", args{[]int{}, []int{1, 2, 3, 4}}, []int{1, 2, 3, 4}},
|
||||
{"right empty", args{[]int{1, 2, 3, 4}, []int{}}, []int{1, 2, 3, 4}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := mergeRoles(tt.args.rolesA, tt.args.rolesB); !test.CheckSetsEqual(got, tt.want) {
|
||||
t.Errorf("mergeRoles() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ package robot
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/core/promgr"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/evaluator"
|
||||
@ -72,16 +71,6 @@ func (s *SecurityContext) IsSolutionUser() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetMyProjects no implementation
|
||||
func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetProjectRoles no implementation
|
||||
func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Can returns whether the robot can do action on resource
|
||||
func (s *SecurityContext) Can(action types.Action, resource types.Resource) bool {
|
||||
s.once.Do(func() {
|
||||
|
@ -29,7 +29,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
"github.com/goharbor/harbor/src/pkg/robot/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -152,16 +151,3 @@ func TestHasPushPullPerm(t *testing.T) {
|
||||
resource := rbac.NewProjectNamespace(private.ProjectID).Resource(rbac.ResourceRepository)
|
||||
assert.True(t, ctx.Can(rbac.ActionPush, resource) && ctx.Can(rbac.ActionPull, resource))
|
||||
}
|
||||
|
||||
func TestGetMyProjects(t *testing.T) {
|
||||
ctx := NewSecurityContext(nil, nil, nil)
|
||||
projects, err := ctx.GetMyProjects()
|
||||
require.Nil(t, err)
|
||||
assert.Nil(t, projects)
|
||||
}
|
||||
|
||||
func TestGetProjectRoles(t *testing.T) {
|
||||
ctx := NewSecurityContext(nil, nil, nil)
|
||||
roles := ctx.GetProjectRoles("test")
|
||||
assert.Nil(t, roles)
|
||||
}
|
||||
|
@ -15,10 +15,6 @@
|
||||
package secret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/secret"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
@ -85,19 +81,3 @@ func (s *SecurityContext) Can(action types.Action, resource types.Resource) bool
|
||||
}
|
||||
return s.store.GetUsername(s.secret) == secret.JobserviceUser || s.store.GetUsername(s.secret) == secret.CoreUser
|
||||
}
|
||||
|
||||
// GetMyProjects ...
|
||||
func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
||||
return nil, fmt.Errorf("GetMyProjects is unsupported")
|
||||
}
|
||||
|
||||
// GetProjectRoles return guest role if has read permission, otherwise return nil
|
||||
func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
||||
roles := []int{}
|
||||
if s.store != nil &&
|
||||
(s.store.GetUsername(s.secret) == secret.JobserviceUser ||
|
||||
s.store.GetUsername(s.secret) == secret.CoreUser) {
|
||||
roles = append(roles, common.RoleGuest)
|
||||
}
|
||||
return roles
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ package secret
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/secret"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -154,34 +153,3 @@ func TestHasPushPullPerm(t *testing.T) {
|
||||
resource = rbac.Resource("/project/1/repository")
|
||||
assert.False(t, context.Can(rbac.ActionPush, resource) && context.Can(rbac.ActionPull, resource))
|
||||
}
|
||||
|
||||
func TestGetMyProjects(t *testing.T) {
|
||||
context := NewSecurityContext("secret",
|
||||
secret.NewStore(map[string]string{
|
||||
"secret": "username",
|
||||
}))
|
||||
|
||||
_, err := context.GetMyProjects()
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestGetProjectRoles(t *testing.T) {
|
||||
// invalid secret
|
||||
context := NewSecurityContext("invalid_secret",
|
||||
secret.NewStore(map[string]string{
|
||||
"jobservice_secret": secret.JobserviceUser,
|
||||
}))
|
||||
|
||||
roles := context.GetProjectRoles("any_project")
|
||||
assert.Equal(t, 0, len(roles))
|
||||
|
||||
// valid secret
|
||||
context = NewSecurityContext("jobservice_secret",
|
||||
secret.NewStore(map[string]string{
|
||||
"jobservice_secret": secret.JobserviceUser,
|
||||
}))
|
||||
|
||||
roles = context.GetProjectRoles("any_project")
|
||||
assert.Equal(t, 1, len(roles))
|
||||
assert.Equal(t, common.RoleGuest, roles[0])
|
||||
}
|
||||
|
@ -212,6 +212,10 @@ func (f *fakedProjectMgr) GetPublic() ([]*models.Project, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakedProjectMgr) GetAuthorized(user *models.User) ([]*models.Project, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if the project manager uses a metadata manager, return it, otherwise return nil
|
||||
func (f *fakedProjectMgr) GetMetadataManager() metamgr.ProjectMetadataManager {
|
||||
return nil
|
||||
|
@ -252,7 +252,7 @@ func prepare() error {
|
||||
|
||||
if projAdminPMID, err = project.AddProjectMember(models.Member{
|
||||
ProjectID: 1,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
EntityID: int(projAdminID),
|
||||
EntityType: common.UserMember,
|
||||
}); err != nil {
|
||||
@ -271,7 +271,7 @@ func prepare() error {
|
||||
|
||||
if projAdminRobotPMID, err = project.AddProjectMember(models.Member{
|
||||
ProjectID: 1,
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
EntityID: int(projAdminRobotID),
|
||||
EntityType: common.UserMember,
|
||||
}); err != nil {
|
||||
@ -290,7 +290,7 @@ func prepare() error {
|
||||
|
||||
if projDeveloperPMID, err = project.AddProjectMember(models.Member{
|
||||
ProjectID: 1,
|
||||
Role: models.DEVELOPER,
|
||||
Role: common.RoleDeveloper,
|
||||
EntityID: int(projDeveloperID),
|
||||
EntityType: common.UserMember,
|
||||
}); err != nil {
|
||||
@ -309,7 +309,7 @@ func prepare() error {
|
||||
|
||||
if projGuestPMID, err = project.AddProjectMember(models.Member{
|
||||
ProjectID: 1,
|
||||
Role: models.GUEST,
|
||||
Role: common.RoleGuest,
|
||||
EntityID: int(projGuestID),
|
||||
EntityType: common.UserMember,
|
||||
}); err != nil {
|
||||
|
@ -258,6 +258,10 @@ func (mpm *mockProjectManager) GetPublic() ([]*models.Project, error) {
|
||||
return nil, errors.New("Not implemented")
|
||||
}
|
||||
|
||||
func (mpm *mockProjectManager) GetAuthorized(user *models.User) ([]*models.Project, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if the project manager uses a metadata manager, return it, otherwise return nil
|
||||
func (mpm *mockProjectManager) GetMetadataManager() metamgr.ProjectMetadataManager {
|
||||
return nil
|
||||
|
@ -24,10 +24,11 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/dao/project"
|
||||
pro "github.com/goharbor/harbor/src/common/dao/project"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/quota"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/security/local"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
errutil "github.com/goharbor/harbor/src/common/utils/error"
|
||||
"github.com/goharbor/harbor/src/controller/event/metadata"
|
||||
@ -402,14 +403,16 @@ func (p *ProjectAPI) List() {
|
||||
return
|
||||
}
|
||||
projects = append(projects, pros...)
|
||||
mps, err := p.SecurityCtx.GetMyProjects()
|
||||
if sc, ok := p.SecurityCtx.(*local.SecurityContext); ok {
|
||||
mps, err := p.ProjectMgr.GetAuthorized(sc.User())
|
||||
if err != nil {
|
||||
p.SendInternalServerError(fmt.Errorf("failed to list projects: %v", err))
|
||||
p.SendInternalServerError(fmt.Errorf("failed to list authorized projects: %v", err))
|
||||
return
|
||||
}
|
||||
projects = append(projects, mps...)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Query projects by user group
|
||||
|
||||
if projects != nil {
|
||||
@ -443,8 +446,11 @@ func (p *ProjectAPI) populateProperties(project *models.Project) error {
|
||||
project.SetMetadata(models.ProMetaSeverity, strings.ToLower(vuln.ParseSeverityVersion3(severity).String()))
|
||||
}
|
||||
|
||||
if p.SecurityCtx.IsAuthenticated() {
|
||||
roles := p.SecurityCtx.GetProjectRoles(project.ProjectID)
|
||||
if sc, ok := p.SecurityCtx.(*local.SecurityContext); ok {
|
||||
roles, err := pro.ListRoles(sc.User(), project.ProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project.RoleList = roles
|
||||
project.Role = highestRole(roles)
|
||||
}
|
||||
@ -614,7 +620,7 @@ func getProjectMemberSummary(projectID int64, summary *models.ProjectSummary) {
|
||||
go func(role int, count *int64) {
|
||||
defer wg.Done()
|
||||
|
||||
total, err := project.GetTotalOfProjectMembers(projectID, role)
|
||||
total, err := pro.GetTotalOfProjectMembers(projectID, role)
|
||||
if err != nil {
|
||||
log.Debugf("failed to get total of project members of role %d", role)
|
||||
return
|
||||
|
@ -16,6 +16,8 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
pro "github.com/goharbor/harbor/src/common/dao/project"
|
||||
"github.com/goharbor/harbor/src/common/security/local"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
@ -47,7 +49,6 @@ type searchResult struct {
|
||||
// Get ...
|
||||
func (s *SearchAPI) Get() {
|
||||
keyword := s.GetString("q")
|
||||
isAuthenticated := s.SecurityCtx.IsAuthenticated()
|
||||
isSysAdmin := s.SecurityCtx.IsSysAdmin()
|
||||
|
||||
var projects []*models.Project
|
||||
@ -66,11 +67,11 @@ func (s *SearchAPI) Get() {
|
||||
s.ParseAndHandleError("failed to get projects", err)
|
||||
return
|
||||
}
|
||||
if isAuthenticated {
|
||||
mys, err := s.SecurityCtx.GetMyProjects()
|
||||
if sc, ok := s.SecurityCtx.(*local.SecurityContext); ok {
|
||||
mys, err := s.ProjectMgr.GetAuthorized(sc.User())
|
||||
if err != nil {
|
||||
s.SendInternalServerError(fmt.Errorf(
|
||||
"failed to get projects: %v", err))
|
||||
"failed to get authorized projects: %v", err))
|
||||
return
|
||||
}
|
||||
exist := map[int64]bool{}
|
||||
@ -95,8 +96,12 @@ func (s *SearchAPI) Get() {
|
||||
continue
|
||||
}
|
||||
|
||||
if isAuthenticated {
|
||||
roles := s.SecurityCtx.GetProjectRoles(p.ProjectID)
|
||||
if sc, ok := s.SecurityCtx.(*local.SecurityContext); ok {
|
||||
roles, err := pro.ListRoles(sc.User(), p.ProjectID)
|
||||
if err != nil {
|
||||
s.SendInternalServerError(fmt.Errorf("failed to list roles: %v", err))
|
||||
return
|
||||
}
|
||||
p.Role = highestRole(roles)
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ func TestSearch(t *testing.T) {
|
||||
ProjectID: projectID1,
|
||||
EntityID: int(nonSysAdminID),
|
||||
EntityType: common.UserMember,
|
||||
Role: models.GUEST,
|
||||
Role: common.RoleGuest,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer member.DeleteProjectMemberByID(memberID1)
|
||||
@ -81,7 +81,7 @@ func TestSearch(t *testing.T) {
|
||||
ProjectID: projectID2,
|
||||
EntityID: int(nonSysAdminID),
|
||||
EntityType: common.UserMember,
|
||||
Role: models.GUEST,
|
||||
Role: common.RoleGuest,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer member.DeleteProjectMemberByID(memberID2)
|
||||
|
@ -17,6 +17,7 @@ package api
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/security/local"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
@ -101,9 +102,9 @@ func (s *StatisticAPI) Get() {
|
||||
statistic[TRC] = n
|
||||
statistic[PriRC] = n - statistic[PubRC]
|
||||
} else {
|
||||
// including the public ones
|
||||
myProjects, err := s.SecurityCtx.GetMyProjects()
|
||||
privProjectIDs := make([]int64, 0)
|
||||
if sc, ok := s.SecurityCtx.(*local.SecurityContext); ok {
|
||||
myProjects, err := s.ProjectMgr.GetAuthorized(sc.User())
|
||||
if err != nil {
|
||||
s.ParseAndHandleError(fmt.Sprintf(
|
||||
"failed to get projects of user %s", s.username), err)
|
||||
@ -114,6 +115,7 @@ func (s *StatisticAPI) Get() {
|
||||
privProjectIDs = append(privProjectIDs, p.ProjectID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statistic[PriPC] = int64(len(privProjectIDs))
|
||||
if statistic[PriPC] == 0 {
|
||||
|
@ -368,7 +368,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) {
|
||||
MemberUser: models.User{
|
||||
Username: "mike",
|
||||
},
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
}
|
||||
pmid, err := api.AddProjectMember(currentProject.ProjectID, member)
|
||||
if err != nil {
|
||||
@ -387,7 +387,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) {
|
||||
MemberUser: models.User{
|
||||
Username: "mike",
|
||||
},
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
}
|
||||
pmid, err = api.AddProjectMember(currentProject.ProjectID, member2)
|
||||
if err != nil {
|
||||
@ -409,7 +409,7 @@ func TestAddProjectMemberWithLdapGroup(t *testing.T) {
|
||||
MemberGroup: models.UserGroup{
|
||||
ID: groupIds[0],
|
||||
},
|
||||
Role: models.PROJECTADMIN,
|
||||
Role: common.RoleProjectAdmin,
|
||||
}
|
||||
pmid, err := api.AddProjectMember(currentProject.ProjectID, member)
|
||||
if err != nil {
|
||||
|
@ -93,6 +93,29 @@ func (_m *ProjectManager) Get(projectIDOrName interface{}) (*models.Project, err
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetAuthorized provides a mock function with given fields: user
|
||||
func (_m *ProjectManager) GetAuthorized(user *models.User) ([]*models.Project, error) {
|
||||
ret := _m.Called(user)
|
||||
|
||||
var r0 []*models.Project
|
||||
if rf, ok := ret.Get(0).(func(*models.User) []*models.Project); ok {
|
||||
r0 = rf(user)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*models.Project)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*models.User) error); ok {
|
||||
r1 = rf(user)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetMetadataManager provides a mock function with given fields:
|
||||
func (_m *ProjectManager) GetMetadataManager() metamgr.ProjectMetadataManager {
|
||||
ret := _m.Called()
|
||||
|
@ -37,6 +37,8 @@ type ProjectManager interface {
|
||||
Exists(projectIDOrName interface{}) (bool, error)
|
||||
// get all public project
|
||||
GetPublic() ([]*models.Project, error)
|
||||
// get all projects that the user is authorized
|
||||
GetAuthorized(user *models.User) ([]*models.Project, error)
|
||||
// if the project manager uses a metadata manager, return it, otherwise return nil
|
||||
GetMetadataManager() metamgr.ProjectMetadataManager
|
||||
}
|
||||
@ -253,6 +255,23 @@ func (d *defaultProjectManager) GetPublic() ([]*models.Project, error) {
|
||||
return result.Projects, nil
|
||||
}
|
||||
|
||||
func (d *defaultProjectManager) GetAuthorized(user *models.User) ([]*models.Project, error) {
|
||||
if user == nil {
|
||||
return nil, nil
|
||||
}
|
||||
result, err := d.List(
|
||||
&models.ProjectQueryParam{
|
||||
Member: &models.MemberQuery{
|
||||
Name: user.Username,
|
||||
GroupIDs: user.GroupIDs,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Projects, nil
|
||||
}
|
||||
|
||||
func (d *defaultProjectManager) GetMetadataManager() metamgr.ProjectMetadataManager {
|
||||
return d.metaMgr
|
||||
}
|
||||
|
@ -120,6 +120,16 @@ func TestGetPublic(t *testing.T) {
|
||||
assert.True(t, projects[0].IsPublic())
|
||||
}
|
||||
|
||||
func TestGetAuthorized(t *testing.T) {
|
||||
projects, err := proMgr.GetAuthorized(nil)
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, projects, 0)
|
||||
|
||||
projects, err = proMgr.GetAuthorized(&models.User{UserID: 1})
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, projects, 1)
|
||||
}
|
||||
|
||||
func TestGetMetadataManager(t *testing.T) {
|
||||
metaMgr := proMgr.GetMetadataManager()
|
||||
assert.Nil(t, metaMgr)
|
||||
|
@ -66,8 +66,10 @@ func QuerySetter(ctx context.Context, model interface{}, query *q.Query, ignored
|
||||
|
||||
// or list
|
||||
ol, ok := v.(*q.OrList)
|
||||
if ok && len(ol.Values) > 0 {
|
||||
if ok {
|
||||
if len(ol.Values) > 0 {
|
||||
qs = qs.Filter(k+"__in", ol.Values...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,10 @@ func (mockPM) GetPublic() ([]*models.Project, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mockPM) GetAuthorized(user *models.User) ([]*models.Project, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (mockPM) GetMetadataManager() metamgr.ProjectMetadataManager {
|
||||
panic("implement me")
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"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/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/audit"
|
||||
@ -39,18 +41,23 @@ func (a *auditlogAPI) ListAuditLogs(ctx context.Context, params auditlog.ListAud
|
||||
}
|
||||
|
||||
if !secCtx.IsSysAdmin() {
|
||||
// ToDo remove the dependency on GetMyProjects()
|
||||
projects, err := secCtx.GetMyProjects()
|
||||
ol := &q.OrList{}
|
||||
if sc, ok := secCtx.(*local.SecurityContext); ok {
|
||||
projects, err := config.GlobalProjectMgr.GetAuthorized(sc.User())
|
||||
if err != nil {
|
||||
return a.SendError(ctx, fmt.Errorf(
|
||||
"failed to get projects of user %s: %v", secCtx.GetUsername(), err))
|
||||
}
|
||||
ol := &q.OrList{}
|
||||
for _, project := range projects {
|
||||
if a.HasProjectPermission(ctx, project.ProjectID, rbac.ActionList, rbac.ResourceLog) {
|
||||
ol.Values = append(ol.Values, project.ProjectID)
|
||||
}
|
||||
}
|
||||
}
|
||||
// make sure no project will be selected with the query
|
||||
if len(ol.Values) == 0 {
|
||||
ol.Values = append(ol.Values, -1)
|
||||
}
|
||||
query.Keywords["ProjectID"] = ol
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user