mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-05 07:27:50 +01:00
Update security context for assign role to project group member
The project list will contain all public projects, user is a member of this project, or user is in the group which is a member of this projects. Change the behaviour of user roles, if the user is not a member of this project, then return the user's groups role of current project
This commit is contained in:
parent
413ae9a8cb
commit
b8a48d0326
@ -662,7 +662,7 @@ func TestGetTotalOfProjects(t *testing.T) {
|
|||||||
func TestGetProjects(t *testing.T) {
|
func TestGetProjects(t *testing.T) {
|
||||||
projects, err := GetProjects(nil)
|
projects, err := GetProjects(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred in GetAllProjects: %v", err)
|
t.Errorf("Error occurred in GetProjects: %v", err)
|
||||||
}
|
}
|
||||||
if len(projects) != 2 {
|
if len(projects) != 2 {
|
||||||
t.Errorf("Expected length of projects is 2, but actual: %d, the projects: %+v", len(projects), projects)
|
t.Errorf("Expected length of projects is 2, but actual: %d, the projects: %+v", len(projects), projects)
|
||||||
|
@ -15,8 +15,11 @@
|
|||||||
package group
|
package group
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/vmware/harbor/src/common"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
@ -133,3 +136,20 @@ func OnBoardUserGroup(g *models.UserGroup, keyAttribute string, combinedKeyAttri
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGroupDNQueryCondition get the part of IN ('XXX', 'XXX') condition
|
||||||
|
func GetGroupDNQueryCondition(userGroupList []*models.UserGroup) string {
|
||||||
|
result := make([]string, 0)
|
||||||
|
count := 0
|
||||||
|
for _, userGroup := range userGroupList {
|
||||||
|
if userGroup.GroupType == common.LdapGroupType {
|
||||||
|
result = append(result, "'"+userGroup.LdapGroupDN+"'")
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//No LDAP Group found
|
||||||
|
if count == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.Join(result, ",")
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/dao/project"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
)
|
)
|
||||||
@ -247,3 +248,178 @@ func TestOnBoardUserGroup(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetGroupDNQueryCondition(t *testing.T) {
|
||||||
|
userGroupList := []*models.UserGroup{
|
||||||
|
&models.UserGroup{
|
||||||
|
GroupName: "sample1",
|
||||||
|
GroupType: 1,
|
||||||
|
LdapGroupDN: "cn=sample1_users,ou=groups,dc=example,dc=com",
|
||||||
|
},
|
||||||
|
&models.UserGroup{
|
||||||
|
GroupName: "sample2",
|
||||||
|
GroupType: 1,
|
||||||
|
LdapGroupDN: "cn=sample2_users,ou=groups,dc=example,dc=com",
|
||||||
|
},
|
||||||
|
&models.UserGroup{
|
||||||
|
GroupName: "sample3",
|
||||||
|
GroupType: 0,
|
||||||
|
LdapGroupDN: "cn=sample3_users,ou=groups,dc=example,dc=com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
groupQueryConditions := GetGroupDNQueryCondition(userGroupList)
|
||||||
|
expectedConditions := `'cn=sample1_users,ou=groups,dc=example,dc=com','cn=sample2_users,ou=groups,dc=example,dc=com'`
|
||||||
|
if groupQueryConditions != expectedConditions {
|
||||||
|
t.Errorf("Failed to GetGroupDNQueryCondition, expected %v, actual %v", expectedConditions, groupQueryConditions)
|
||||||
|
}
|
||||||
|
var userGroupList2 []*models.UserGroup
|
||||||
|
groupQueryCondition2 := GetGroupDNQueryCondition(userGroupList2)
|
||||||
|
if len(groupQueryCondition2) > 0 {
|
||||||
|
t.Errorf("Failed to GetGroupDNQueryCondition, expected %v, actual %v", "", groupQueryCondition2)
|
||||||
|
}
|
||||||
|
groupQueryCondition3 := GetGroupDNQueryCondition(nil)
|
||||||
|
if len(groupQueryCondition3) > 0 {
|
||||||
|
t.Errorf("Failed to GetGroupDNQueryCondition, expected %v, actual %v", "", groupQueryCondition3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestGetGroupProjects(t *testing.T) {
|
||||||
|
userID, err := dao.Register(models.User{
|
||||||
|
Username: "grouptestu09",
|
||||||
|
Email: "grouptest09@example.com",
|
||||||
|
Password: "Harbor123456",
|
||||||
|
})
|
||||||
|
defer dao.DeleteUser(int(userID))
|
||||||
|
projectID1, err := dao.AddProject(models.Project{
|
||||||
|
Name: "grouptest01",
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when AddProject: %v", err)
|
||||||
|
}
|
||||||
|
defer dao.DeleteProject(projectID1)
|
||||||
|
projectID2, err := dao.AddProject(models.Project{
|
||||||
|
Name: "grouptest02",
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when AddProject: %v", err)
|
||||||
|
}
|
||||||
|
defer dao.DeleteProject(projectID2)
|
||||||
|
groupID, err := AddUserGroup(models.UserGroup{
|
||||||
|
GroupName: "test_group_01",
|
||||||
|
GroupType: 1,
|
||||||
|
LdapGroupDN: "cn=harbor_users,ou=groups,dc=example,dc=com",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when AddUserGroup: %v", err)
|
||||||
|
}
|
||||||
|
defer DeleteUserGroup(groupID)
|
||||||
|
pmid, err := project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: projectID1,
|
||||||
|
EntityID: groupID,
|
||||||
|
EntityType: "g",
|
||||||
|
})
|
||||||
|
defer project.DeleteProjectMemberByID(pmid)
|
||||||
|
type args struct {
|
||||||
|
groupDNCondition string
|
||||||
|
query *models.ProjectQueryParam
|
||||||
|
}
|
||||||
|
member := &models.MemberQuery{
|
||||||
|
Name: "grouptestu09",
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantSize int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"Query with group DN",
|
||||||
|
args{"'cn=harbor_users,ou=groups,dc=example,dc=com'",
|
||||||
|
&models.ProjectQueryParam{
|
||||||
|
Member: member,
|
||||||
|
}},
|
||||||
|
1, false},
|
||||||
|
{"Query without group DN",
|
||||||
|
args{"",
|
||||||
|
&models.ProjectQueryParam{}},
|
||||||
|
1, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := dao.GetGroupProjects(tt.args.groupDNCondition, tt.args.query)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetGroupProjects() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(got) < tt.wantSize {
|
||||||
|
t.Errorf("GetGroupProjects() size: %v, want %v", len(got), tt.wantSize)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTotalGroupProjects(t *testing.T) {
|
||||||
|
projectID1, err := dao.AddProject(models.Project{
|
||||||
|
Name: "grouptest01",
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when AddProject: %v", err)
|
||||||
|
}
|
||||||
|
defer dao.DeleteProject(projectID1)
|
||||||
|
projectID2, err := dao.AddProject(models.Project{
|
||||||
|
Name: "grouptest02",
|
||||||
|
OwnerID: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when AddProject: %v", err)
|
||||||
|
}
|
||||||
|
defer dao.DeleteProject(projectID2)
|
||||||
|
groupID, err := AddUserGroup(models.UserGroup{
|
||||||
|
GroupName: "test_group_01",
|
||||||
|
GroupType: 1,
|
||||||
|
LdapGroupDN: "cn=harbor_users,ou=groups,dc=example,dc=com",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when AddUserGroup: %v", err)
|
||||||
|
}
|
||||||
|
defer DeleteUserGroup(groupID)
|
||||||
|
pmid, err := project.AddProjectMember(models.Member{
|
||||||
|
ProjectID: projectID1,
|
||||||
|
EntityID: groupID,
|
||||||
|
EntityType: "g",
|
||||||
|
})
|
||||||
|
defer project.DeleteProjectMemberByID(pmid)
|
||||||
|
type args struct {
|
||||||
|
groupDNCondition string
|
||||||
|
query *models.ProjectQueryParam
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantSize int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"Query with group DN",
|
||||||
|
args{"'cn=harbor_users,ou=groups,dc=example,dc=com'",
|
||||||
|
&models.ProjectQueryParam{}},
|
||||||
|
1, false},
|
||||||
|
{"Query without group DN",
|
||||||
|
args{"",
|
||||||
|
&models.ProjectQueryParam{}},
|
||||||
|
1, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := dao.GetTotalGroupProjects(tt.args.groupDNCondition, tt.args.query)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetGroupProjects() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got < tt.wantSize {
|
||||||
|
t.Errorf("GetGroupProjects() size: %v, want %v", got, tt.wantSize)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -135,42 +135,85 @@ func GetTotalOfProjects(query *models.ProjectQueryParam) (int64, error) {
|
|||||||
|
|
||||||
// GetProjects returns a project list according to the query conditions
|
// GetProjects returns a project list according to the query conditions
|
||||||
func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
func GetProjects(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||||
sql, params := projectQueryConditions(query)
|
sqlStr, queryParam := projectQueryConditions(query)
|
||||||
if query == nil {
|
sqlStr = `select distinct p.project_id, p.name, p.owner_id,
|
||||||
sql += ` order by p.name`
|
p.creation_time, p.update_time ` + sqlStr + ` order by p.name`
|
||||||
}
|
sqlStr, queryParam = CreatePagination(query, sqlStr, queryParam)
|
||||||
|
|
||||||
|
log.Debugf("sql:=%+v, param= %+v", sqlStr, queryParam)
|
||||||
|
var projects []*models.Project
|
||||||
|
_, err := GetOrmer().Raw(sqlStr, queryParam).QueryRows(&projects)
|
||||||
|
|
||||||
|
return projects, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupProjects - Get user's all projects, including user is the user member of this project
|
||||||
|
// and the user is in the group which is a group member of this project.
|
||||||
|
func GetGroupProjects(groupDNCondition string, query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||||
|
sql, params := projectQueryConditions(query)
|
||||||
sql = `select distinct p.project_id, p.name, p.owner_id,
|
sql = `select distinct p.project_id, p.name, p.owner_id,
|
||||||
p.creation_time, p.update_time ` + sql
|
p.creation_time, p.update_time ` + sql
|
||||||
|
if len(groupDNCondition) > 0 {
|
||||||
|
sql = fmt.Sprintf(
|
||||||
|
`%s union select distinct p.project_id, p.name, p.owner_id, p.creation_time, p.update_time
|
||||||
|
from project p
|
||||||
|
left join project_member pm on p.project_id = pm.project_id
|
||||||
|
left join user_group ug on ug.id = pm.entity_id and pm.entity_type = 'g' and ug.group_type = 1
|
||||||
|
where ug.ldap_group_dn in ( %s ) order by name`,
|
||||||
|
sql, groupDNCondition)
|
||||||
|
}
|
||||||
|
sqlStr, queryParams := CreatePagination(query, sql, params)
|
||||||
|
log.Debugf("query sql:%v", sql)
|
||||||
var projects []*models.Project
|
var projects []*models.Project
|
||||||
_, err := GetOrmer().Raw(sql, params).QueryRows(&projects)
|
_, err := GetOrmer().Raw(sqlStr, queryParams).QueryRows(&projects)
|
||||||
return projects, err
|
return projects, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTotalGroupProjects - Get the total count of projects, including user is the member of this project and the
|
||||||
|
// user is in the group, which is the group member of this project.
|
||||||
|
func GetTotalGroupProjects(groupDNCondition string, query *models.ProjectQueryParam) (int, error) {
|
||||||
|
var sql string
|
||||||
|
sqlCondition, params := projectQueryConditions(query)
|
||||||
|
if len(groupDNCondition) == 0 {
|
||||||
|
sql = `select count(1) ` + sqlCondition
|
||||||
|
} else {
|
||||||
|
sql = fmt.Sprintf(
|
||||||
|
`select count(1)
|
||||||
|
from ( select p.project_id %s union select p.project_id
|
||||||
|
from project p
|
||||||
|
left join project_member pm on p.project_id = pm.project_id
|
||||||
|
left join user_group ug on ug.id = pm.entity_id and pm.entity_type = 'g' and ug.group_type = 1
|
||||||
|
where ug.ldap_group_dn in ( %s )) t`,
|
||||||
|
sqlCondition, groupDNCondition)
|
||||||
|
}
|
||||||
|
log.Debugf("query sql:%v", sql)
|
||||||
|
var count int
|
||||||
|
if err := GetOrmer().Raw(sql, params).QueryRow(&count); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
func projectQueryConditions(query *models.ProjectQueryParam) (string, []interface{}) {
|
func projectQueryConditions(query *models.ProjectQueryParam) (string, []interface{}) {
|
||||||
params := []interface{}{}
|
params := []interface{}{}
|
||||||
|
|
||||||
sql := ` from project as p`
|
sql := ` from project as p`
|
||||||
|
|
||||||
if query == nil {
|
if query == nil {
|
||||||
sql += ` where p.deleted=false`
|
sql += ` where p.deleted=false`
|
||||||
return sql, params
|
return sql, params
|
||||||
}
|
}
|
||||||
|
|
||||||
// if query.ProjectIDs is not nil but has no element, the query will returns no rows
|
// if query.ProjectIDs is not nil but has no element, the query will returns no rows
|
||||||
if query.ProjectIDs != nil && len(query.ProjectIDs) == 0 {
|
if query.ProjectIDs != nil && len(query.ProjectIDs) == 0 {
|
||||||
sql += ` where 1 = 0`
|
sql += ` where 1 = 0`
|
||||||
return sql, params
|
return sql, params
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(query.Owner) != 0 {
|
if len(query.Owner) != 0 {
|
||||||
sql += ` join harbor_user u1
|
sql += ` join harbor_user u1
|
||||||
on p.owner_id = u1.user_id`
|
on p.owner_id = u1.user_id`
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.Member != nil && len(query.Member.Name) != 0 {
|
if query.Member != nil && len(query.Member.Name) != 0 {
|
||||||
sql += ` join project_member pm
|
sql += ` join project_member pm
|
||||||
on p.project_id = pm.project_id
|
on p.project_id = pm.project_id and pm.entity_type = 'u'
|
||||||
join harbor_user u2
|
join harbor_user u2
|
||||||
on pm.entity_id=u2.user_id`
|
on pm.entity_id=u2.user_id`
|
||||||
}
|
}
|
||||||
@ -205,15 +248,18 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac
|
|||||||
params = append(params, roleID)
|
params = append(params, roleID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(query.ProjectIDs) > 0 {
|
if len(query.ProjectIDs) > 0 {
|
||||||
sql += fmt.Sprintf(` and p.project_id in ( %s )`,
|
sql += fmt.Sprintf(` and p.project_id in ( %s )`,
|
||||||
paramPlaceholder(len(query.ProjectIDs)))
|
paramPlaceholder(len(query.ProjectIDs)))
|
||||||
params = append(params, query.ProjectIDs)
|
params = append(params, query.ProjectIDs)
|
||||||
}
|
}
|
||||||
|
return sql, params
|
||||||
|
}
|
||||||
|
|
||||||
if query.Pagination != nil && query.Pagination.Size > 0 {
|
// CreatePagination ...
|
||||||
sql += ` order by p.name limit ?`
|
func CreatePagination(query *models.ProjectQueryParam, sql string, params []interface{}) (string, []interface{}) {
|
||||||
|
if query != nil && query.Pagination != nil && query.Pagination.Size > 0 {
|
||||||
|
sql += ` limit ?`
|
||||||
params = append(params, query.Pagination.Size)
|
params = append(params, query.Pagination.Size)
|
||||||
|
|
||||||
if query.Pagination.Page > 0 {
|
if query.Pagination.Page > 0 {
|
||||||
@ -221,7 +267,6 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac
|
|||||||
params = append(params, (query.Pagination.Page-1)*query.Pagination.Size)
|
params = append(params, (query.Pagination.Page-1)*query.Pagination.Size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sql, params
|
return sql, params
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,12 +276,31 @@ func DeleteProject(id int64) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID)
|
name := fmt.Sprintf("%s#%d", project.Name, project.ProjectID)
|
||||||
|
|
||||||
sql := `update project
|
sql := `update project
|
||||||
set deleted = true, name = ?
|
set deleted = true, name = ?
|
||||||
where project_id = ?`
|
where project_id = ?`
|
||||||
_, err = GetOrmer().Raw(sql, name, id).Exec()
|
_, err = GetOrmer().Raw(sql, name, id).Exec()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRolesByLDAPGroup - Get Project roles of the
|
||||||
|
// specified group DN is a member of current project
|
||||||
|
func GetRolesByLDAPGroup(projectID int64, groupDNCondition string) ([]int, error) {
|
||||||
|
var roles []int
|
||||||
|
if len(groupDNCondition) == 0 {
|
||||||
|
return roles, nil
|
||||||
|
}
|
||||||
|
o := GetOrmer()
|
||||||
|
sql := fmt.Sprintf(
|
||||||
|
`select pm.role from project_member pm
|
||||||
|
left join user_group ug on pm.entity_type = 'g' and pm.entity_id = ug.id
|
||||||
|
where ug.ldap_group_dn in ( %s ) and pm.project_id = ? `,
|
||||||
|
groupDNCondition)
|
||||||
|
log.Debugf("sql:%v", sql)
|
||||||
|
if _, err := o.Raw(sql, projectID).QueryRows(&roles); err != nil {
|
||||||
|
log.Warningf("Error in GetRolesByLDAPGroup, error: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return roles, nil
|
||||||
|
}
|
||||||
|
@ -30,14 +30,14 @@ func GetProjectMember(queryMember models.Member) ([]*models.Member, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
o := dao.GetOrmer()
|
o := dao.GetOrmer()
|
||||||
sql := ` select a.* from ((select pm.id as id, pm.project_id as project_id, ug.id as entity_id, ug.group_name as entity_name, ug.creation_time, ug.update_time, r.name as rolename,
|
sql := ` select a.* from (select pm.id as id, pm.project_id as project_id, ug.id as entity_id, ug.group_name as entity_name, ug.creation_time, ug.update_time, r.name as rolename,
|
||||||
r.role_id as role, pm.entity_type as entity_type from user_group ug join project_member pm
|
r.role_id as role, pm.entity_type as entity_type from user_group ug join project_member pm
|
||||||
on pm.project_id = ? and ug.id = pm.entity_id join role r on pm.role = r.role_id where pm.entity_type = 'g')
|
on pm.project_id = ? and ug.id = pm.entity_id join role r on pm.role = r.role_id where pm.entity_type = 'g'
|
||||||
union
|
union
|
||||||
(select pm.id as id, pm.project_id as project_id, u.user_id as entity_id, u.username as entity_name, u.creation_time, u.update_time, r.name as rolename,
|
select pm.id as id, pm.project_id as project_id, u.user_id as entity_id, u.username as entity_name, u.creation_time, u.update_time, r.name as rolename,
|
||||||
r.role_id as role, pm.entity_type as entity_type from harbor_user u join project_member pm
|
r.role_id as role, pm.entity_type as entity_type from harbor_user u join project_member pm
|
||||||
on pm.project_id = ? and u.user_id = pm.entity_id
|
on pm.project_id = ? and u.user_id = pm.entity_id
|
||||||
join role r on pm.role = r.role_id where u.deleted = false and pm.entity_type = 'u')) as a where a.project_id = ? `
|
join role r on pm.role = r.role_id where u.deleted = false and pm.entity_type = 'u') as a where a.project_id = ? `
|
||||||
|
|
||||||
queryParam := make([]interface{}, 1)
|
queryParam := make([]interface{}, 1)
|
||||||
// used ProjectID already
|
// used ProjectID already
|
||||||
@ -63,7 +63,7 @@ func GetProjectMember(queryMember models.Member) ([]*models.Member, error) {
|
|||||||
sql += " and a.id = ? "
|
sql += " and a.id = ? "
|
||||||
queryParam = append(queryParam, queryMember.ID)
|
queryParam = append(queryParam, queryMember.ID)
|
||||||
}
|
}
|
||||||
sql += ` order by a.entity_name `
|
sql += ` order by entity_name `
|
||||||
members := []*models.Member{}
|
members := []*models.Member{}
|
||||||
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
||||||
|
|
||||||
@ -120,29 +120,44 @@ func DeleteProjectMemberByID(pmid int) error {
|
|||||||
// SearchMemberByName search members of the project by entity_name
|
// SearchMemberByName search members of the project by entity_name
|
||||||
func SearchMemberByName(projectID int64, entityName string) ([]*models.Member, error) {
|
func SearchMemberByName(projectID int64, entityName string) ([]*models.Member, error) {
|
||||||
o := dao.GetOrmer()
|
o := dao.GetOrmer()
|
||||||
sql := `(select pm.id, pm.project_id,
|
sql := `select pm.id, pm.project_id,
|
||||||
u.username as entity_name,
|
u.username as entity_name,
|
||||||
r.name as rolename,
|
r.name as rolename,
|
||||||
pm.role, pm.entity_id, pm.entity_type
|
pm.role, pm.entity_id, pm.entity_type
|
||||||
from project_member pm
|
from project_member pm
|
||||||
left join harbor_user u on pm.entity_id = u.user_id and pm.entity_type = 'u'
|
left join harbor_user u on pm.entity_id = u.user_id and pm.entity_type = 'u'
|
||||||
left join role r on pm.role = r.role_id
|
left join role r on pm.role = r.role_id
|
||||||
where u.deleted = false and pm.project_id = ? and u.username like ? order by entity_name )
|
where u.deleted = false and pm.project_id = ? and u.username like ?
|
||||||
union
|
union
|
||||||
(select pm.id, pm.project_id,
|
select pm.id, pm.project_id,
|
||||||
ug.group_name as entity_name,
|
ug.group_name as entity_name,
|
||||||
r.name as rolename,
|
r.name as rolename,
|
||||||
pm.role, pm.entity_id, pm.entity_type
|
pm.role, pm.entity_id, pm.entity_type
|
||||||
from project_member pm
|
from project_member pm
|
||||||
left join user_group ug on pm.entity_id = ug.id and pm.entity_type = 'g'
|
left join user_group ug on pm.entity_id = ug.id and pm.entity_type = 'g'
|
||||||
left join role r on pm.role = r.role_id
|
left join role r on pm.role = r.role_id
|
||||||
where pm.project_id = ? and ug.group_name like ? order by entity_name ) `
|
where pm.project_id = ? and ug.group_name like ?
|
||||||
|
order by entity_name `
|
||||||
queryParam := make([]interface{}, 4)
|
queryParam := make([]interface{}, 4)
|
||||||
queryParam = append(queryParam, projectID)
|
queryParam = append(queryParam, projectID)
|
||||||
queryParam = append(queryParam, "%"+dao.Escape(entityName)+"%")
|
queryParam = append(queryParam, "%"+dao.Escape(entityName)+"%")
|
||||||
queryParam = append(queryParam, projectID)
|
queryParam = append(queryParam, projectID)
|
||||||
queryParam = append(queryParam, "%"+dao.Escape(entityName)+"%")
|
queryParam = append(queryParam, "%"+dao.Escape(entityName)+"%")
|
||||||
members := []*models.Member{}
|
members := []*models.Member{}
|
||||||
|
log.Debugf("Query sql: %v", sql)
|
||||||
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
||||||
return members, err
|
return members, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRolesByGroup -- Query group roles
|
||||||
|
func GetRolesByGroup(projectID int64, groupDNCondition string) []int {
|
||||||
|
var roles []int
|
||||||
|
o := dao.GetOrmer()
|
||||||
|
sql := `select role from project_member pm
|
||||||
|
left join user_group ug on pm.project_id = ?
|
||||||
|
where ug.group_type = 1 and ug.ldap_group_dn in (` + groupDNCondition + `)`
|
||||||
|
if _, err := o.Raw(sql, projectID).QueryRows(&roles); err != nil {
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
@ -285,3 +285,50 @@ func TestGetProjectMember(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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')`,
|
||||||
|
`insert into harbor_user (username, email, password, realname) values ('sample01', 'sample01@example.com', 'harbor12345', 'sample01')`,
|
||||||
|
`insert into project (name, owner_id) values ('group_project', 1)`,
|
||||||
|
`insert into project (name, owner_id) values ('group_project_private', 1)`,
|
||||||
|
`insert into project_metadata (project_id, name, value) values ((select project_id from project where name = 'group_project'), 'public', 'false')`,
|
||||||
|
`insert into project_metadata (project_id, name, value) values ((select project_id from project where name = 'group_project_private'), 'public', 'false')`,
|
||||||
|
`insert into project_member (project_id, entity_id, entity_type, role) values ((select project_id from project where name = 'group_project'), (select id from user_group where group_name = 'harbor_group_01'),'g', 2)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSqls := []string{
|
||||||
|
`delete from project_metadata where project_id in (select project_id from project where name in ('group_project', 'group_project_private'))`,
|
||||||
|
`delete from project where name in ('group_project', 'group_project_private')`,
|
||||||
|
`delete from project_member where project_id in (select project_id from project where name in ('group_project', 'group_project_private'))`,
|
||||||
|
`delete from user_group where group_name = 'harbor_group_01'`,
|
||||||
|
`delete from harbor_user where username = 'sample01'`,
|
||||||
|
}
|
||||||
|
dao.PrepareTestData(clearSqls, initSqls)
|
||||||
|
}
|
||||||
|
func TestGetRolesByGroup(t *testing.T) {
|
||||||
|
PrepareGroupTest()
|
||||||
|
|
||||||
|
project, err := dao.GetProjectByName("group_project")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when GetProjectByName : %v", err)
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
projectID int64
|
||||||
|
groupDNCondition string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want []int
|
||||||
|
}{
|
||||||
|
{"Query group with role", args{project.ProjectID, "'cn=harbor_user,dc=example,dc=com'"}, []int{2}},
|
||||||
|
{"Query group no role", args{project.ProjectID, "'cn=another_user,dc=example,dc=com'"}, []int{}},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := GetRolesByGroup(tt.args.projectID, tt.args.groupDNCondition); !dao.ArrayEqual(got, tt.want) {
|
||||||
|
t.Errorf("GetRolesByGroup() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -103,9 +103,9 @@ func Test_projectQueryConditions(t *testing.T) {
|
|||||||
args{query: &models.ProjectQueryParam{ProjectIDs: []int64{2, 3}, Owner: "admin", Name: "sample", Member: &models.MemberQuery{Name: "name", Role: 1}, Pagination: &models.Pagination{Page: 1, Size: 20}}},
|
args{query: &models.ProjectQueryParam{ProjectIDs: []int64{2, 3}, Owner: "admin", Name: "sample", Member: &models.MemberQuery{Name: "name", Role: 1}, Pagination: &models.Pagination{Page: 1, Size: 20}}},
|
||||||
` from project as p join harbor_user u1
|
` from project as p join harbor_user u1
|
||||||
on p.owner_id = u1.user_id join project_member pm
|
on p.owner_id = u1.user_id join project_member pm
|
||||||
on p.project_id = pm.project_id
|
on p.project_id = pm.project_id and pm.entity_type = 'u'
|
||||||
join harbor_user u2
|
join harbor_user u2
|
||||||
on pm.entity_id=u2.user_id where p.deleted=false and u1.username=? and p.name like ? and u2.username=? and pm.role = ? and p.project_id in ( ?,? ) order by p.name limit ? offset ?`,
|
on pm.entity_id=u2.user_id where p.deleted=false and u1.username=? and p.name like ? and u2.username=? and pm.role = ? and p.project_id in ( ?,? )`,
|
||||||
[]interface{}{1, []int64{2, 3}, 20, 0}},
|
[]interface{}{1, []int64{2, 3}, 20, 0}},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@ -117,3 +117,121 @@ func Test_projectQueryConditions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetGroupProjects(t *testing.T) {
|
||||||
|
prepareGroupTest()
|
||||||
|
query := &models.ProjectQueryParam{Member: &models.MemberQuery{Name: "sample_group"}}
|
||||||
|
type args struct {
|
||||||
|
groupDNCondition string
|
||||||
|
query *models.ProjectQueryParam
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantSize int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"Verify correct sql", args{groupDNCondition: "'cn=harbor_user,dc=example,dc=com'", query: query}, 1, false},
|
||||||
|
{"Verify missed sql", args{groupDNCondition: "'cn=another_user,dc=example,dc=com'", query: query}, 0, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := GetGroupProjects(tt.args.groupDNCondition, tt.args.query)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetGroupProjects() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(got) != tt.wantSize {
|
||||||
|
t.Errorf("GetGroupProjects() = %v, want %v", got, tt.wantSize)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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')`,
|
||||||
|
`insert into harbor_user (username, email, password, realname) values ('sample01', 'sample01@example.com', 'harbor12345', 'sample01')`,
|
||||||
|
`insert into project (name, owner_id) values ('group_project', 1)`,
|
||||||
|
`insert into project (name, owner_id) values ('group_project_private', 1)`,
|
||||||
|
`insert into project_metadata (project_id, name, value) values ((select project_id from project where name = 'group_project'), 'public', 'false')`,
|
||||||
|
`insert into project_metadata (project_id, name, value) values ((select project_id from project where name = 'group_project_private'), 'public', 'false')`,
|
||||||
|
`insert into project_member (project_id, entity_id, entity_type, role) values ((select project_id from project where name = 'group_project'), (select id from user_group where group_name = 'harbor_group_01'),'g', 2)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSqls := []string{
|
||||||
|
`delete from project_metadata where project_id in (select project_id from project where name in ('group_project', 'group_project_private'))`,
|
||||||
|
`delete from project where name in ('group_project', 'group_project_private')`,
|
||||||
|
`delete from project_member where project_id in (select project_id from project where name in ('group_project', 'group_project_private'))`,
|
||||||
|
`delete from user_group where group_name = 'harbor_group_01'`,
|
||||||
|
`delete from harbor_user where username = 'sample01'`,
|
||||||
|
}
|
||||||
|
PrepareTestData(clearSqls, initSqls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTotalGroupProjects(t *testing.T) {
|
||||||
|
prepareGroupTest()
|
||||||
|
query := &models.ProjectQueryParam{Member: &models.MemberQuery{Name: "sample_group"}}
|
||||||
|
type args struct {
|
||||||
|
groupDNCondition string
|
||||||
|
query *models.ProjectQueryParam
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"Verify correct sql", args{groupDNCondition: "'cn=harbor_user,dc=example,dc=com'", query: query}, 1, false},
|
||||||
|
{"Verify missed sql", args{groupDNCondition: "'cn=another_user,dc=example,dc=com'", query: query}, 0, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := GetTotalGroupProjects(tt.args.groupDNCondition, tt.args.query)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("GetTotalGroupProjects() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("GetTotalGroupProjects() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRolesByLDAPGroup(t *testing.T) {
|
||||||
|
prepareGroupTest()
|
||||||
|
project, err := GetProjectByName("group_project")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when Get project by name: %v", err)
|
||||||
|
}
|
||||||
|
privateProject, err := GetProjectByName("group_project_private")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error occurred when Get project by name: %v", err)
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
projectID int64
|
||||||
|
groupDNCondition string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantSize int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"Check normal", args{project.ProjectID, "'cn=harbor_user,dc=example,dc=com'"}, 1, false},
|
||||||
|
{"Check non exist", args{privateProject.ProjectID, "'cn=not_harbor_user,dc=example,dc=com'"}, 0, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := GetRolesByLDAPGroup(tt.args.projectID, tt.args.groupDNCondition)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -116,3 +116,17 @@ func PrepareTestData(clearSqls []string, initSqls []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ArrayEqual ...
|
||||||
|
func ArrayEqual(arrayA, arrayB []int) bool {
|
||||||
|
if len(arrayA) != len(arrayB) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
size := len(arrayA)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
if arrayA[i] != arrayB[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -149,6 +149,7 @@ type ProjectQueryParam struct {
|
|||||||
type MemberQuery struct {
|
type MemberQuery struct {
|
||||||
Name string // the username of member
|
Name string // the username of member
|
||||||
Role int // the role of the member has to the project
|
Role int // the role of the member has to the project
|
||||||
|
GroupList []*UserGroup // the group list of current user
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination ...
|
// Pagination ...
|
||||||
|
@ -40,6 +40,7 @@ type User struct {
|
|||||||
Salt string `orm:"column(salt)" json:"-"`
|
Salt string `orm:"column(salt)" json:"-"`
|
||||||
CreationTime time.Time `orm:"column(creation_time)" json:"creation_time"`
|
CreationTime time.Time `orm:"column(creation_time)" json:"creation_time"`
|
||||||
UpdateTime time.Time `orm:"column(update_time)" json:"update_time"`
|
UpdateTime time.Time `orm:"column(update_time)" json:"update_time"`
|
||||||
|
GroupList []*UserGroup `orm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserQuery ...
|
// UserQuery ...
|
||||||
|
@ -13,5 +13,3 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package admiral
|
package admiral
|
||||||
|
|
||||||
// TODO add test cases
|
|
||||||
|
@ -34,6 +34,8 @@ type Context interface {
|
|||||||
HasWritePerm(projectIDOrName interface{}) bool
|
HasWritePerm(projectIDOrName interface{}) bool
|
||||||
// HasAllPerm returns whether the user has all permissions to the project
|
// HasAllPerm returns whether the user has all permissions to the project
|
||||||
HasAllPerm(projectIDOrName interface{}) bool
|
HasAllPerm(projectIDOrName interface{}) bool
|
||||||
|
//Get current user's all project
|
||||||
GetMyProjects() ([]*models.Project, error)
|
GetMyProjects() ([]*models.Project, error)
|
||||||
|
//Get user's role in provided project
|
||||||
GetProjectRoles(projectIDOrName interface{}) []int
|
GetProjectRoles(projectIDOrName interface{}) []int
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package local
|
|||||||
import (
|
import (
|
||||||
"github.com/vmware/harbor/src/common"
|
"github.com/vmware/harbor/src/common"
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/dao/group"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
"github.com/vmware/harbor/src/ui/promgr"
|
"github.com/vmware/harbor/src/ui/promgr"
|
||||||
@ -88,7 +89,6 @@ func (s *SecurityContext) HasReadPerm(projectIDOrName interface{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
roles := s.GetProjectRoles(projectIDOrName)
|
roles := s.GetProjectRoles(projectIDOrName)
|
||||||
|
|
||||||
return len(roles) > 0
|
return len(roles) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,12 +97,10 @@ func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
|||||||
if !s.IsAuthenticated() {
|
if !s.IsAuthenticated() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// system admin
|
// system admin
|
||||||
if s.IsSysAdmin() {
|
if s.IsSysAdmin() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
roles := s.GetProjectRoles(projectIDOrName)
|
roles := s.GetProjectRoles(projectIDOrName)
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
switch role {
|
switch role {
|
||||||
@ -111,7 +109,6 @@ func (s *SecurityContext) HasWritePerm(projectIDOrName interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +117,10 @@ func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
|||||||
if !s.IsAuthenticated() {
|
if !s.IsAuthenticated() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// system admin
|
// system admin
|
||||||
if s.IsSysAdmin() {
|
if s.IsSysAdmin() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
roles := s.GetProjectRoles(projectIDOrName)
|
roles := s.GetProjectRoles(projectIDOrName)
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
switch role {
|
switch role {
|
||||||
@ -133,19 +128,9 @@ func (s *SecurityContext) HasAllPerm(projectIDOrName interface{}) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMyProjects ...
|
|
||||||
func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
|
||||||
return dao.GetProjects(&models.ProjectQueryParam{
|
|
||||||
Member: &models.MemberQuery{
|
|
||||||
Name: s.GetUsername(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProjectRoles ...
|
// GetProjectRoles ...
|
||||||
func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
||||||
if !s.IsAuthenticated() || projectIDOrName == nil {
|
if !s.IsAuthenticated() || projectIDOrName == nil {
|
||||||
@ -164,7 +149,6 @@ func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
|||||||
log.Debugf("user %s not found", s.GetUsername())
|
log.Debugf("user %s not found", s.GetUsername())
|
||||||
return roles
|
return roles
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err := s.pm.Get(projectIDOrName)
|
project, err := s.pm.Get(projectIDOrName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get project %v: %v", projectIDOrName, err)
|
log.Errorf("failed to get project %v: %v", projectIDOrName, err)
|
||||||
@ -174,13 +158,11 @@ func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
|||||||
log.Errorf("project %v not found", projectIDOrName)
|
log.Errorf("project %v not found", projectIDOrName)
|
||||||
return roles
|
return roles
|
||||||
}
|
}
|
||||||
|
|
||||||
roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID, common.UserMember)
|
roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID, common.UserMember)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get roles of user %d to project %d: %v", user.UserID, project.ProjectID, err)
|
log.Errorf("failed to get roles of user %d to project %d: %v", user.UserID, project.ProjectID, err)
|
||||||
return roles
|
return roles
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roleList {
|
for _, role := range roleList {
|
||||||
switch role.RoleCode {
|
switch role.RoleCode {
|
||||||
case "MDRWS":
|
case "MDRWS":
|
||||||
@ -191,8 +173,42 @@ func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int {
|
|||||||
roles = append(roles, common.RoleGuest)
|
roles = append(roles, common.RoleGuest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(roles) != 0 {
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
return s.GetRolesByGroup(projectIDOrName)
|
||||||
|
}
|
||||||
|
|
||||||
//If len(roles)==0, Get Group 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.GroupList) == 0 {
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
//Get role by LDAP group
|
||||||
|
groupDNConditions := group.GetGroupDNQueryCondition(user.GroupList)
|
||||||
|
roles, err = dao.GetRolesByLDAPGroup(project.ProjectID, groupDNConditions)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return roles
|
return roles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMyProjects ...
|
||||||
|
func (s *SecurityContext) GetMyProjects() ([]*models.Project, error) {
|
||||||
|
result, err := s.pm.List(
|
||||||
|
&models.ProjectQueryParam{
|
||||||
|
Member: &models.MemberQuery{
|
||||||
|
Name: s.GetUsername(),
|
||||||
|
GroupList: s.user.GroupList,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Projects, nil
|
||||||
|
}
|
||||||
|
@ -272,6 +272,25 @@ func TestHasAllPerm(t *testing.T) {
|
|||||||
assert.True(t, ctx.HasAllPerm(private.Name))
|
assert.True(t, ctx.HasAllPerm(private.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHasAllPermWithGroup(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)
|
||||||
|
}
|
||||||
|
developer.GroupList = []*models.UserGroup{
|
||||||
|
&models.UserGroup{GroupName: "test_group", GroupType: 1, LdapGroupDN: "cn=harbor_user,dc=example,dc=com"},
|
||||||
|
}
|
||||||
|
ctx := NewSecurityContext(developer, pm)
|
||||||
|
assert.False(t, ctx.HasAllPerm(project.Name))
|
||||||
|
assert.True(t, ctx.HasWritePerm(project.Name))
|
||||||
|
assert.True(t, ctx.HasReadPerm(project.Name))
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetMyProjects(t *testing.T) {
|
func TestGetMyProjects(t *testing.T) {
|
||||||
ctx := NewSecurityContext(guestUser, pm)
|
ctx := NewSecurityContext(guestUser, pm)
|
||||||
projects, err := ctx.GetMyProjects()
|
projects, err := ctx.GetMyProjects()
|
||||||
@ -309,3 +328,96 @@ func TestGetProjectRoles(t *testing.T) {
|
|||||||
assert.Equal(t, 1, len(roles))
|
assert.Equal(t, 1, len(roles))
|
||||||
assert.Equal(t, common.RoleProjectAdmin, roles[0])
|
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')`,
|
||||||
|
`insert into harbor_user (username, email, password, realname) values ('sample01', 'sample01@example.com', 'harbor12345', 'sample01')`,
|
||||||
|
`insert into project (name, owner_id) values ('group_project', 1)`,
|
||||||
|
`insert into project (name, owner_id) values ('group_project_private', 1)`,
|
||||||
|
`insert into project_metadata (project_id, name, value) values ((select project_id from project where name = 'group_project'), 'public', 'false')`,
|
||||||
|
`insert into project_metadata (project_id, name, value) values ((select project_id from project where name = 'group_project_private'), 'public', 'false')`,
|
||||||
|
`insert into project_member (project_id, entity_id, entity_type, role) values ((select project_id from project where name = 'group_project'), (select id from user_group where group_name = 'harbor_group_01'),'g', 2)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSqls := []string{
|
||||||
|
`delete from project_metadata where project_id in (select project_id from project where name in ('group_project', 'group_project_private'))`,
|
||||||
|
`delete from project where name in ('group_project', 'group_project_private')`,
|
||||||
|
`delete from project_member where project_id in (select project_id from project where name in ('group_project', 'group_project_private'))`,
|
||||||
|
`delete from user_group where group_name = 'harbor_group_01'`,
|
||||||
|
`delete from harbor_user where username = 'sample01'`,
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
developer.GroupList = []*models.UserGroup{
|
||||||
|
&models.UserGroup{GroupName: "test_group", GroupType: 1, LdapGroupDN: "cn=harbor_user,dc=example,dc=com"},
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -347,19 +347,16 @@ func (p *ProjectAPI) List() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
projects = append(projects, pros...)
|
projects = append(projects, pros...)
|
||||||
|
mps, err := p.SecurityCtx.GetMyProjects()
|
||||||
mps, err := p.ProjectMgr.List(&models.ProjectQueryParam{
|
|
||||||
Member: &models.MemberQuery{
|
|
||||||
Name: p.SecurityCtx.GetUsername(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.HandleInternalServerError(fmt.Sprintf("failed to list projects: %v", err))
|
p.HandleInternalServerError(fmt.Sprintf("failed to list projects: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
projects = append(projects, mps.Projects...)
|
projects = append(projects, mps...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Query projects by user group
|
||||||
|
|
||||||
if projects != nil {
|
if projects != nil {
|
||||||
projectIDs := []int64{}
|
projectIDs := []int64{}
|
||||||
for _, project := range projects {
|
for _, project := range projects {
|
||||||
|
@ -76,14 +76,31 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
|||||||
u.Username = ldapUsers[0].Username
|
u.Username = ldapUsers[0].Username
|
||||||
u.Email = strings.TrimSpace(ldapUsers[0].Email)
|
u.Email = strings.TrimSpace(ldapUsers[0].Email)
|
||||||
u.Realname = ldapUsers[0].Realname
|
u.Realname = ldapUsers[0].Realname
|
||||||
|
userGroups := make([]*models.UserGroup, 0)
|
||||||
|
|
||||||
dn := ldapUsers[0].DN
|
dn := ldapUsers[0].DN
|
||||||
|
|
||||||
if err = ldapSession.Bind(dn, m.Password); err != nil {
|
if err = ldapSession.Bind(dn, m.Password); err != nil {
|
||||||
log.Warningf("Failed to bind user, username: %s, dn: %s, error: %v", u.Username, dn, err)
|
log.Warningf("Failed to bind user, username: %s, dn: %s, error: %v", u.Username, dn, err)
|
||||||
return nil, auth.NewErrAuth(err.Error())
|
return nil, auth.NewErrAuth(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Attach user group
|
||||||
|
for _, groupDN := range ldapUsers[0].GroupDNList {
|
||||||
|
userGroupQuery := models.UserGroup{
|
||||||
|
GroupType: 1,
|
||||||
|
LdapGroupDN: groupDN,
|
||||||
|
}
|
||||||
|
userGroupList, err := group.QueryUserGroup(userGroupQuery)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(userGroupList) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
userGroups = append(userGroups, userGroupList[0])
|
||||||
|
}
|
||||||
|
u.GroupList = userGroups
|
||||||
|
|
||||||
return &u, nil
|
return &u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
//Extract to test utils
|
//Extract to test utils
|
||||||
initSqls := []string{
|
initSqls := []string{
|
||||||
"insert into user (username, email, password, realname) values ('member_test_01', 'member_test_01@example.com', '123456', 'member_test_01')",
|
"insert into harbor_user (username, email, password, realname) values ('member_test_01', 'member_test_01@example.com', '123456', 'member_test_01')",
|
||||||
"insert into project (name, owner_id) values ('member_test_01', 1)",
|
"insert into project (name, owner_id) values ('member_test_01', 1)",
|
||||||
"insert into user_group (group_name, group_type, group_property) values ('test_group_01', 1, 'CN=harbor_users,OU=sample,OU=vmware,DC=harbor,DC=com')",
|
"insert into user_group (group_name, group_type, group_property) values ('test_group_01', 1, 'CN=harbor_users,OU=sample,OU=vmware,DC=harbor,DC=com')",
|
||||||
"update project set owner_id = (select user_id from harbor_user where username = 'member_test_01') where name = 'member_test_01'",
|
"update project set owner_id = (select user_id from harbor_user where username = 'member_test_01') where name = 'member_test_01'",
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
"github.com/vmware/harbor/src/common/dao/group"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils"
|
"github.com/vmware/harbor/src/common/utils"
|
||||||
errutil "github.com/vmware/harbor/src/common/utils/error"
|
errutil "github.com/vmware/harbor/src/common/utils/error"
|
||||||
@ -117,7 +118,6 @@ func (d *driver) Delete(projectIDOrName interface{}) error {
|
|||||||
}
|
}
|
||||||
id = project.ProjectID
|
id = project.ProjectID
|
||||||
}
|
}
|
||||||
|
|
||||||
return dao.DeleteProject(id)
|
return dao.DeleteProject(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,17 +129,26 @@ func (d *driver) Update(projectIDOrName interface{},
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List returns a project list according to the query parameters
|
// List returns a project list according to the query parameters
|
||||||
func (d *driver) List(query *models.ProjectQueryParam) (
|
func (d *driver) List(query *models.ProjectQueryParam) (*models.ProjectQueryResult, error) {
|
||||||
*models.ProjectQueryResult, error) {
|
var total int64
|
||||||
total, err := dao.GetTotalOfProjects(query)
|
var projects []*models.Project
|
||||||
|
var groupDNCondition string
|
||||||
|
|
||||||
|
//List with LDAP group projects
|
||||||
|
if query != nil && query.Member != nil {
|
||||||
|
groupDNCondition = group.GetGroupDNQueryCondition(query.Member.GroupList)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := dao.GetTotalGroupProjects(groupDNCondition, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
total = int64(count)
|
||||||
|
projects, err = dao.GetGroupProjects(groupDNCondition, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
projects, err := dao.GetProjects(query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &models.ProjectQueryResult{
|
return &models.ProjectQueryResult{
|
||||||
Total: total,
|
Total: total,
|
||||||
Projects: projects,
|
Projects: projects,
|
||||||
|
@ -7,7 +7,11 @@ cp make/common/config/ui/private_key.pem /etc/ui/
|
|||||||
|
|
||||||
mkdir src/ui/conf
|
mkdir src/ui/conf
|
||||||
cp make/common/config/ui/app.conf src/ui/conf/
|
cp make/common/config/ui/app.conf src/ui/conf/
|
||||||
IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'`
|
if [ "$(uname)" == "Darwin" ]; then
|
||||||
|
IP=`ifconfig en0 | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}'`
|
||||||
|
else
|
||||||
|
IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'`
|
||||||
|
fi
|
||||||
echo "server ip is "$IP
|
echo "server ip is "$IP
|
||||||
sed -i -r "s/POSTGRESQL_HOST=postgresql/POSTGRESQL_HOST=$IP/" make/common/config/adminserver/env
|
sed -i -r "s/POSTGRESQL_HOST=postgresql/POSTGRESQL_HOST=$IP/" make/common/config/adminserver/env
|
||||||
sed -i -r "s|REGISTRY_URL=http://registry:5000|REGISTRY_URL=http://$IP:5000|" make/common/config/adminserver/env
|
sed -i -r "s|REGISTRY_URL=http://registry:5000|REGISTRY_URL=http://$IP:5000|" make/common/config/adminserver/env
|
||||||
|
Loading…
Reference in New Issue
Block a user