From 8c8bad8602b8ddc7c3f6da2245a145b5c97e4ae8 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Mon, 9 May 2016 12:45:45 +0800 Subject: [PATCH 1/7] sysadmin has all privileges for projects --- api/member.go | 26 +++++++++++++++++++++++++- api/project.go | 10 ++++++++++ dao/role.go | 15 +++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/api/member.go b/api/member.go index 0b95e9f1f..2ae7c9c53 100644 --- a/api/member.go +++ b/api/member.go @@ -92,7 +92,7 @@ func (pma *ProjectMemberAPI) Get() { } pma.Data["json"] = userList } else { //return detail of a member - roleList, err := dao.GetUserProjectRoles(pma.memberID, pid) + roleList, err := listRoles(pma.memberID, pid) if err != nil { log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err) pma.CustomAbort(http.StatusInternalServerError, "Internal error.") @@ -241,3 +241,27 @@ func (pma *ProjectMemberAPI) Delete() { return } } + +//sysadmin has all privileges to all projects +func listRoles(userID int, projectID int64) ([]models.Role, error) { + roles := make([]models.Role, 1) + isSysAdmin, err := dao.IsAdminRole(userID) + if err != nil { + return roles, err + } + if isSysAdmin { + role, err := dao.GetRoleByID(models.PROJECTADMIN) + if err != nil { + return roles, err + } + roles = append(roles, *role) + return roles, nil + } + + rs, err := dao.GetUserProjectRoles(userID, projectID) + if err != nil { + return roles, err + } + roles = append(roles, rs...) + return roles, nil +} diff --git a/api/project.go b/api/project.go index 993cc9ad7..b0c404c2b 100644 --- a/api/project.go +++ b/api/project.go @@ -190,6 +190,16 @@ func (p *ProjectAPI) FilterAccessLog() { } func isProjectAdmin(userID int, pid int64) bool { + isSysAdmin, err := dao.IsAdminRole(userID) + if err != nil { + log.Errorf("Error occurred in IsAdminRole, returning false, error: %v", err) + return false + } + + if isSysAdmin { + return true + } + rolelist, err := dao.GetUserProjectRoles(userID, pid) if err != nil { log.Errorf("Error occurred in GetUserProjectRoles, returning false, error: %v", err) diff --git a/dao/role.go b/dao/role.go index aafecc74d..2adf93aaa 100644 --- a/dao/role.go +++ b/dao/role.go @@ -73,3 +73,18 @@ func IsAdminRole(userIDOrUsername interface{}) (bool, error) { return user.HasAdminRole == 1, nil } + +// GetRoleByID ... +func GetRoleByID(id int) (*models.Role, error) { + o := orm.NewOrm() + + sql := `select * + from role + where role_id = ?` + + var role models.Role + if err := o.Raw(sql, id).QueryRow(&role); err != nil { + return nil, err + } + return &role, nil +} From 56ccfc024aaa18447ca0df8c76652a908d8dc153 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Mon, 9 May 2016 16:48:59 +0800 Subject: [PATCH 2/7] search api modification for admin --- api/search.go | 39 +++++++++++++++++++++++++++++---------- dao/project.go | 33 +++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/api/search.go b/api/search.go index 043e5408f..d47bb5890 100644 --- a/api/search.go +++ b/api/search.go @@ -38,17 +38,36 @@ type searchResult struct { } // Get ... -func (n *SearchAPI) Get() { - userID, ok := n.GetSession("userId").(int) +func (s *SearchAPI) Get() { + userID, ok := s.GetSession("userId").(int) if !ok { userID = dao.NonExistUserID } - keyword := n.GetString("q") - projects, err := dao.QueryRelevantProjects(userID) + + keyword := s.GetString("q") + + isSysAdmin, err := dao.IsAdminRole(userID) if err != nil { - log.Errorf("Failed to get projects of user id: %d, error: %v", userID, err) - n.CustomAbort(http.StatusInternalServerError, "Failed to get project search result") + log.Errorf("failed to check whether the user %d is system admin: %v", userID, err) + s.CustomAbort(http.StatusInternalServerError, "internal error") } + + var projects []models.Project + + if isSysAdmin { + projects, err = dao.GetAllProjects() + if err != nil { + log.Errorf("failed to get all projects: %v", err) + s.CustomAbort(http.StatusInternalServerError, "internal error") + } + } else { + projects, err = dao.GetUserRelevantProjects(userID) + if err != nil { + log.Errorf("failed to get user %d 's relevant projects: %v", userID, err) + s.CustomAbort(http.StatusInternalServerError, "internal error") + } + } + projectSorter := &utils.ProjectSorter{Projects: projects} sort.Sort(projectSorter) projectResult := []map[string]interface{}{} @@ -69,17 +88,17 @@ func (n *SearchAPI) Get() { repositories, err2 := svc_utils.GetRepoFromCache() if err2 != nil { log.Errorf("Failed to get repos from cache, error: %v", err2) - n.CustomAbort(http.StatusInternalServerError, "Failed to get repositories search result") + s.CustomAbort(http.StatusInternalServerError, "Failed to get repositories search result") } sort.Strings(repositories) repositoryResult := filterRepositories(repositories, projects, keyword) result := &searchResult{Project: projectResult, Repository: repositoryResult} - n.Data["json"] = result - n.ServeJSON() + s.Data["json"] = result + s.ServeJSON() } func filterRepositories(repositories []string, projects []models.Project, keyword string) []map[string]interface{} { - var i, j int = 0, 0 + i, j := 0, 0 result := []map[string]interface{}{} for i < len(repositories) && j < len(projects) { r := &utils.Repository{Name: repositories[i]} diff --git a/dao/project.go b/dao/project.go index 9eba4f78e..6e01b070d 100644 --- a/dao/project.go +++ b/dao/project.go @@ -208,18 +208,35 @@ func ToggleProjectPublicity(projectID int64, publicity int) error { return err } -// QueryRelevantProjects returns all projects that the user is a member of. -func QueryRelevantProjects(userID int) ([]models.Project, error) { +// GetUserRelevantProjects returns a project list, +// which satisfies the following conditions: +// 1. the project is not deleted +// 2. the prject is public or the user is a member of the project +func GetUserRelevantProjects(userID int) ([]models.Project, error) { o := orm.NewOrm() sql := `select distinct p.project_id, p.name, p.public from project p left join project_member pm on p.project_id = pm.project_id - left join user u on u.user_id = pm.user_id - where u.user_id = ? or p.public = 1 and p.deleted = 0` - var res []models.Project - _, err := o.Raw(sql, userID).QueryRows(&res) - if err != nil { + where (pm.user_id = ? or p.public = 1) and p.deleted = 0` + + var projects []models.Project + + if _, err := o.Raw(sql, userID).QueryRows(&projects); err != nil { return nil, err } - return res, err + + return projects, nil +} + +// GetAllProjects returns all projects which are not deleted +func GetAllProjects() ([]models.Project, error) { + o := orm.NewOrm() + sql := `select project_id, name, public + from project + where deleted = 0` + var projects []models.Project + if _, err := o.Raw(sql).QueryRows(&projects); err != nil { + return nil, err + } + return projects, nil } From 48be0a988d7cbc5587a3e88bba12ce790395d871 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Mon, 9 May 2016 16:53:33 +0800 Subject: [PATCH 3/7] dao test --- dao/dao_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index 99ece3348..8f344af91 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -353,7 +353,7 @@ func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) { } func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) { - projects, err := QueryRelevantProjects(currentUser.UserID) + projects, err := GetUserRelevantProjects(currentUser.UserID) if err != nil { t.Errorf("Error occurred in QueryRelevantProjects: %v", err) } @@ -632,7 +632,7 @@ func TestProjectPermission(t *testing.T) { } func TestQueryRelevantProjects(t *testing.T) { - projects, err := QueryRelevantProjects(currentUser.UserID) + projects, err := GetUserRelevantProjects(currentUser.UserID) if err != nil { t.Errorf("Error occurred in QueryRelevantProjects: %v", err) } From af16c4c1744c4f93c6ea35b2aad34dd9b8211cd8 Mon Sep 17 00:00:00 2001 From: xiahaoshawn Date: Tue, 10 May 2016 14:16:51 +0800 Subject: [PATCH 4/7] update installation guide --- docs/installation_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation_guide.md b/docs/installation_guide.md index f6f6691ea..cfc0a2c01 100644 --- a/docs/installation_guide.md +++ b/docs/installation_guide.md @@ -207,7 +207,7 @@ $ rm -r /data/registry By default, the data of database and image files in the registry are persisted in the directory **/data/** of the target machine. When Harbor's containers are removed and recreated, the data remain unchanged. Harbor leverages rsyslog to collect the logs of each container, by default the log files are stored in the directory **/var/log/harbor/** on Harbor's host. ##Troubleshooting -1.When setting up Harbor behind another nginx proxy or elastic load balancing, remove the below line if the proxy already has similar settings. Be sure to remove the line under these 3 sections: "location /", "location /v2/" and "location /service/". +1.When setting up Harbor behind another nginx proxy or elastic load balancing, remove the below line if the proxy already has similar settings. Be sure to edit Deploy/config/nginx/nginx.conf and remove the line under these 3 sections: "location /", "location /v2/" and "location /service/". ``` proxy_set_header X-Forwarded-Proto $scheme; ``` From 3b8baf0139b8751bc4bece7b53141ab75d00ea18 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Tue, 10 May 2016 22:08:36 +0800 Subject: [PATCH 5/7] add ut for GetAllProjects() --- dao/dao_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index 8f344af91..5301bb990 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -631,10 +631,10 @@ func TestProjectPermission(t *testing.T) { } } -func TestQueryRelevantProjects(t *testing.T) { +func TestGetUserRelevantProjects(t *testing.T) { projects, err := GetUserRelevantProjects(currentUser.UserID) if err != nil { - t.Errorf("Error occurred in QueryRelevantProjects: %v", err) + t.Errorf("Error occurred in GetUserRelevantProjects: %v", err) } if len(projects) != 2 { t.Errorf("Expected length of relevant projects is 2, but actual: %d, the projects: %+v", len(projects), projects) @@ -644,6 +644,13 @@ func TestQueryRelevantProjects(t *testing.T) { } } +func TestGetAllProjects(t *testing.T) { + _, err := GetAllProjects() + if err != nil { + t.Errorf("Error occurred in GetAllProjects: %v", err) + } +} + func TestAddProjectMember(t *testing.T) { err := AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER) if err != nil { From 0a5d5b638e2bda85a33a96acfe0325717417ac75 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Tue, 10 May 2016 22:11:07 +0800 Subject: [PATCH 6/7] add ut for GetAllProjects() --- dao/dao_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dao/dao_test.go b/dao/dao_test.go index 5301bb990..0ef18faec 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -645,10 +645,16 @@ func TestGetUserRelevantProjects(t *testing.T) { } func TestGetAllProjects(t *testing.T) { - _, err := GetAllProjects() + projects, err := GetAllProjects() if err != nil { t.Errorf("Error occurred in GetAllProjects: %v", err) } + if len(projects) != 2 { + t.Errorf("Expected length of projects is 2, but actual: %d, the projects: %+v", len(projects), projects) + } + if projects[1].Name != projectName { + t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name) + } } func TestAddProjectMember(t *testing.T) { From dbc20a57bca797463484a0f6c95d1339da567dcf Mon Sep 17 00:00:00 2001 From: Tan Jiang Date: Wed, 11 May 2016 14:25:22 +0800 Subject: [PATCH 7/7] set the Host header to registry to include the port information --- Deploy/config/nginx/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Deploy/config/nginx/nginx.conf b/Deploy/config/nginx/nginx.conf index 8f3430e48..8bc79fa6c 100644 --- a/Deploy/config/nginx/nginx.conf +++ b/Deploy/config/nginx/nginx.conf @@ -47,7 +47,7 @@ http { location /v2/ { proxy_pass http://registry/v2/; - proxy_set_header Host $host; + proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;