Merge branch 'master' into sync_image

Conflicts:
	api/repository.go
This commit is contained in:
Wenkai Yin 2016-05-26 14:12:26 +08:00
commit 039d94c13d
6 changed files with 170 additions and 117 deletions

View File

@ -114,23 +114,10 @@ func (pma *ProjectMemberAPI) Get() {
// Post ... // Post ...
func (pma *ProjectMemberAPI) Post() { func (pma *ProjectMemberAPI) Post() {
pid := pma.project.ProjectID currentUserID := pma.currentUserID
projectID := pma.project.ProjectID
//userQuery := models.User{UserID: pma.currentUserID, RoleID: models.PROJECTADMIN} if !hasProjectAdminRole(currentUserID, projectID) {
rolelist, err := dao.GetUserProjectRoles(pma.currentUserID, pid) log.Warningf("Current user, id: %d does not have project admin role for project, id:", currentUserID, projectID)
if err != nil {
log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err)
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
hasProjectAdminRole := false
for _, role := range rolelist {
if role.RoleID == models.PROJECTADMIN {
hasProjectAdminRole = true
break
}
}
if !hasProjectAdminRole {
log.Warningf("Current user, id: %d does not have project admin role for project, id:", pma.currentUserID, pid)
pma.RenderError(http.StatusForbidden, "") pma.RenderError(http.StatusForbidden, "")
return return
} }
@ -144,21 +131,21 @@ func (pma *ProjectMemberAPI) Post() {
pma.RenderError(http.StatusNotFound, "User does not exist") pma.RenderError(http.StatusNotFound, "User does not exist")
return return
} }
rolelist, err = dao.GetUserProjectRoles(userID, pid) rolelist, err := dao.GetUserProjectRoles(userID, projectID)
if err != nil { if err != nil {
log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err) log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err)
pma.CustomAbort(http.StatusInternalServerError, "Internal error.") pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
} }
if len(rolelist) > 0 { if len(rolelist) > 0 {
log.Warningf("user is already added to project, user id: %d, project id: %d", userID, pid) log.Warningf("user is already added to project, user id: %d, project id: %d", userID, projectID)
pma.RenderError(http.StatusConflict, "user is ready in project") pma.RenderError(http.StatusConflict, "user is ready in project")
return return
} }
for _, rid := range req.Roles { for _, rid := range req.Roles {
err = dao.AddProjectMember(pid, userID, int(rid)) err = dao.AddProjectMember(projectID, userID, int(rid))
if err != nil { if err != nil {
log.Errorf("Failed to update DB to add project user role, project id: %d, user id: %d, role id: %d", pid, userID, rid) log.Errorf("Failed to update DB to add project user role, project id: %d, user id: %d, role id: %d", projectID, userID, rid)
pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") pma.RenderError(http.StatusInternalServerError, "Failed to update data in database")
return return
} }
@ -167,27 +154,16 @@ func (pma *ProjectMemberAPI) Post() {
// Put ... // Put ...
func (pma *ProjectMemberAPI) Put() { func (pma *ProjectMemberAPI) Put() {
currentUserID := pma.currentUserID
pid := pma.project.ProjectID pid := pma.project.ProjectID
mid := pma.memberID if !hasProjectAdminRole(currentUserID, pid) {
log.Warningf("Current user, id: %d does not have project admin role for project, id:", currentUserID, pid)
rolelist, err := dao.GetUserProjectRoles(pma.currentUserID, pid)
if err != nil {
log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err)
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
hasProjectAdminRole := false
for _, role := range rolelist {
if role.RoleID == models.PROJECTADMIN {
hasProjectAdminRole = true
break
}
}
if !hasProjectAdminRole {
log.Warningf("Current user, id: %d does not have project admin role for project, id: %d", pma.currentUserID, pid)
pma.RenderError(http.StatusForbidden, "") pma.RenderError(http.StatusForbidden, "")
return return
} }
mid := pma.memberID
var req memberReq var req memberReq
pma.DecodeJSONReq(&req) pma.DecodeJSONReq(&req)
roleList, err := dao.GetUserProjectRoles(mid, pid) roleList, err := dao.GetUserProjectRoles(mid, pid)
@ -217,51 +193,20 @@ func (pma *ProjectMemberAPI) Put() {
// Delete ... // Delete ...
func (pma *ProjectMemberAPI) Delete() { func (pma *ProjectMemberAPI) Delete() {
currentUserID := pma.currentUserID
pid := pma.project.ProjectID pid := pma.project.ProjectID
mid := pma.memberID if !hasProjectAdminRole(currentUserID, pid) {
log.Warningf("Current user, id: %d does not have project admin role for project, id:", currentUserID, pid)
rolelist, err := dao.GetUserProjectRoles(pma.currentUserID, pid)
hasProjectAdminRole := false
for _, role := range rolelist {
if role.RoleID == models.PROJECTADMIN {
hasProjectAdminRole = true
break
}
}
if !hasProjectAdminRole {
log.Warningf("Current user, id: %d does not have project admin role for project, id: %d", pma.currentUserID, pid)
pma.RenderError(http.StatusForbidden, "") pma.RenderError(http.StatusForbidden, "")
return return
} }
err = dao.DeleteProjectMember(pid, mid)
mid := pma.memberID
err := dao.DeleteProjectMember(pid, mid)
if err != nil { if err != nil {
log.Errorf("Failed to delete project roles for user, user id: %d, project id: %d, error: %v", mid, pid, err) log.Errorf("Failed to delete project roles for user, user id: %d, project id: %d, error: %v", mid, pid, err)
pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB")
return 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
}

View File

@ -43,7 +43,6 @@ const projectNameMaxLen int = 30
// Prepare validates the URL and the user // Prepare validates the URL and the user
func (p *ProjectAPI) Prepare() { func (p *ProjectAPI) Prepare() {
p.userID = p.ValidateUser()
idStr := p.Ctx.Input.Param(":id") idStr := p.Ctx.Input.Param(":id")
if len(idStr) > 0 { if len(idStr) > 0 {
var err error var err error
@ -65,6 +64,8 @@ func (p *ProjectAPI) Prepare() {
// Post ... // Post ...
func (p *ProjectAPI) Post() { func (p *ProjectAPI) Post() {
p.userID = p.ValidateUser()
var req projectReq var req projectReq
var public int var public int
p.DecodeJSONReq(&req) p.DecodeJSONReq(&req)
@ -99,20 +100,52 @@ func (p *ProjectAPI) Post() {
// Head ... // Head ...
func (p *ProjectAPI) Head() { func (p *ProjectAPI) Head() {
projectName := p.GetString("project_name") projectName := p.GetString("project_name")
result, err := dao.ProjectExists(projectName) if len(projectName) == 0 {
p.CustomAbort(http.StatusBadRequest, "project_name is needed")
}
project, err := dao.GetProjectByName(projectName)
if err != nil { if err != nil {
log.Errorf("Error while communicating with DB, error: %v", err) log.Errorf("error occurred in GetProjectByName: %v", err)
p.RenderError(http.StatusInternalServerError, "Error while communicating with DB") p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
// only public project can be Headed by user without login
if project != nil && project.Public == 1 {
return return
} }
if !result {
p.RenderError(http.StatusNotFound, "") userID := p.ValidateUser()
return if project == nil {
p.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
if !checkProjectPermission(userID, project.ProjectID) {
p.CustomAbort(http.StatusForbidden, http.StatusText(http.StatusForbidden))
} }
} }
// Get ... // Get ...
func (p *ProjectAPI) Get() { func (p *ProjectAPI) Get() {
project, err := dao.GetProjectByID(p.projectID)
if err != nil {
log.Errorf("failed to get project %d: %v", p.projectID, err)
p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if project.Public == 0 {
userID := p.ValidateUser()
if !checkProjectPermission(userID, p.projectID) {
p.CustomAbort(http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized))
}
}
p.Data["json"] = project
p.ServeJSON()
}
// List ...
func (p *ProjectAPI) List() {
var projectList []models.Project var projectList []models.Project
projectName := p.GetString("project_name") projectName := p.GetString("project_name")
if len(projectName) > 0 { if len(projectName) > 0 {
@ -132,6 +165,8 @@ func (p *ProjectAPI) Get() {
if public == 1 { if public == 1 {
projectList, err = dao.GetPublicProjects(projectName) projectList, err = dao.GetPublicProjects(projectName)
} else { } else {
//if the request is not for public projects, user must login or provide credential
p.userID = p.ValidateUser()
isAdmin, err = dao.IsAdminRole(p.userID) isAdmin, err = dao.IsAdminRole(p.userID)
if err != nil { if err != nil {
log.Errorf("Error occured in check admin, error: %v", err) log.Errorf("Error occured in check admin, error: %v", err)
@ -164,6 +199,8 @@ func (p *ProjectAPI) Get() {
// Put ... // Put ...
func (p *ProjectAPI) Put() { func (p *ProjectAPI) Put() {
p.userID = p.ValidateUser()
var req projectReq var req projectReq
var public int var public int
@ -192,6 +229,7 @@ func (p *ProjectAPI) Put() {
// FilterAccessLog handles GET to /api/projects/{}/logs // FilterAccessLog handles GET to /api/projects/{}/logs
func (p *ProjectAPI) FilterAccessLog() { func (p *ProjectAPI) FilterAccessLog() {
p.userID = p.ValidateUser()
var filter models.AccessLog var filter models.AccessLog
p.DecodeJSONReq(&filter) p.DecodeJSONReq(&filter)

View File

@ -19,6 +19,7 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"os" "os"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -39,23 +40,13 @@ import (
// the security of registry // the security of registry
type RepositoryAPI struct { type RepositoryAPI struct {
BaseAPI BaseAPI
userID int
}
// Prepare will set a non existent user ID in case the request tries to view repositories under a project he doesn't has permission.
func (ra *RepositoryAPI) Prepare() {
if svc_utils.VerifySecret(ra.Ctx.Request) {
ra.userID = 1
} else {
ra.userID = ra.ValidateUser()
}
} }
// Get ... // Get ...
func (ra *RepositoryAPI) Get() { func (ra *RepositoryAPI) Get() {
projectID, err0 := ra.GetInt64("project_id") projectID, err := ra.GetInt64("project_id")
if err0 != nil { if err != nil {
log.Errorf("Failed to get project id, error: %v", err0) log.Errorf("Failed to get project id, error: %v", err)
ra.RenderError(http.StatusBadRequest, "Invalid project id") ra.RenderError(http.StatusBadRequest, "Invalid project id")
return return
} }
@ -69,10 +60,21 @@ func (ra *RepositoryAPI) Get() {
ra.RenderError(http.StatusNotFound, "") ra.RenderError(http.StatusNotFound, "")
return return
} }
if p.Public == 0 && !checkProjectPermission(ra.userID, projectID) {
if p.Public == 0 {
var userID int
if svc_utils.VerifySecret(ra.Ctx.Request) {
userID = 1
} else {
userID = ra.ValidateUser()
}
if !checkProjectPermission(userID, projectID) {
ra.RenderError(http.StatusForbidden, "") ra.RenderError(http.StatusForbidden, "")
return return
} }
}
repoList, err := cache.GetRepoFromCache() repoList, err := cache.GetRepoFromCache()
if err != nil { if err != nil {
@ -110,7 +112,7 @@ func (ra *RepositoryAPI) Delete() {
ra.CustomAbort(http.StatusBadRequest, "repo_name is nil") ra.CustomAbort(http.StatusBadRequest, "repo_name is nil")
} }
rc, err := ra.initializeRepositoryClient(repoName) rc, err := ra.initRepositoryClient(repoName)
if err != nil { if err != nil {
log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err) log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error") ra.CustomAbort(http.StatusInternalServerError, "internal error")
@ -166,7 +168,7 @@ func (ra *RepositoryAPI) GetTags() {
ra.CustomAbort(http.StatusBadRequest, "repo_name is nil") ra.CustomAbort(http.StatusBadRequest, "repo_name is nil")
} }
rc, err := ra.initializeRepositoryClient(repoName) rc, err := ra.initRepositoryClient(repoName)
if err != nil { if err != nil {
log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err) log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error") ra.CustomAbort(http.StatusInternalServerError, "internal error")
@ -186,6 +188,8 @@ func (ra *RepositoryAPI) GetTags() {
tags = append(tags, ts...) tags = append(tags, ts...)
sort.Strings(tags)
ra.Data["json"] = tags ra.Data["json"] = tags
ra.ServeJSON() ra.ServeJSON()
} }
@ -199,7 +203,7 @@ func (ra *RepositoryAPI) GetManifests() {
ra.CustomAbort(http.StatusBadRequest, "repo_name or tag is nil") ra.CustomAbort(http.StatusBadRequest, "repo_name or tag is nil")
} }
rc, err := ra.initializeRepositoryClient(repoName) rc, err := ra.initRepositoryClient(repoName)
if err != nil { if err != nil {
log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err) log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error") ra.CustomAbort(http.StatusInternalServerError, "internal error")
@ -238,16 +242,50 @@ func (ra *RepositoryAPI) GetManifests() {
ra.ServeJSON() ra.ServeJSON()
} }
func (ra *RepositoryAPI) initializeRepositoryClient(repoName string) (r *registry.Repository, err error) { func (ra *RepositoryAPI) initRepositoryClient(repoName string) (r *registry.Repository, err error) {
u := models.User{ username, err := ra.getUsername()
UserID: ra.userID,
}
user, err := dao.GetUser(u)
if err != nil { if err != nil {
return nil, err return nil, err
} }
endpoint := os.Getenv("REGISTRY_URL") endpoint := os.Getenv("REGISTRY_URL")
return registry.NewRepositoryWithUsername(repoName, endpoint, user.Username) return registry.NewRepositoryWithUsername(repoName, endpoint, username)
}
func (ra *RepositoryAPI) getUsername() (string, error) {
// get username from basic auth
username, _, ok := ra.Ctx.Request.BasicAuth()
if ok {
return username, nil
}
// get username from session
sessionUsername := ra.GetSession("username")
if sessionUsername != nil {
username, ok = sessionUsername.(string)
if ok {
return username, nil
}
}
// if username does not exist in session, try to get userId from sessiion
// and then get username from DB according to the userId
sessionUserID := ra.GetSession("userId")
if sessionUserID != nil {
userID, ok := sessionUserID.(int)
if ok {
u := models.User{
UserID: userID,
}
user, err := dao.GetUser(u)
if err != nil {
return "", err
}
return user.Username, nil
}
}
return "", nil
} }

View File

@ -29,20 +29,52 @@ import (
) )
func checkProjectPermission(userID int, projectID int64) bool { func checkProjectPermission(userID int, projectID int64) bool {
exist, err := dao.IsAdminRole(userID) roles, err := listRoles(userID, projectID)
if err != nil { if err != nil {
log.Errorf("Error occurred in IsAdminRole, error: %v", err) log.Errorf("error occurred in getProjectPermission: %v", err)
return false return false
} }
if exist { return len(roles) > 0
}
func hasProjectAdminRole(userID int, projectID int64) bool {
roles, err := listRoles(userID, projectID)
if err != nil {
log.Errorf("error occurred in getProjectPermission: %v", err)
return false
}
for _, role := range roles {
if role.RoleID == models.PROJECTADMIN {
return true return true
} }
roleList, err := dao.GetUserProjectRoles(userID, projectID) }
if err != nil {
log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err)
return false return false
} }
return len(roleList) > 0
//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
} }
func checkUserExists(name string) int { func checkUserExists(name string) int {

View File

@ -249,7 +249,6 @@ func getProjects(public int, projectName string) ([]models.Project, error) {
} }
sql += " order by name " sql += " order by name "
var projects []models.Project var projects []models.Project
log.Debugf("sql xxx", sql)
if _, err := o.Raw(sql, queryParam).QueryRows(&projects); err != nil { if _, err := o.Raw(sql, queryParam).QueryRows(&projects); err != nil {
return nil, err return nil, err
} }

View File

@ -53,6 +53,7 @@ func initRouters() {
//API: //API:
beego.Router("/api/search", &api.SearchAPI{}) beego.Router("/api/search", &api.SearchAPI{})
beego.Router("/api/projects/:pid/members/?:mid", &api.ProjectMemberAPI{}) beego.Router("/api/projects/:pid/members/?:mid", &api.ProjectMemberAPI{})
beego.Router("/api/projects/", &api.ProjectAPI{}, "get:List")
beego.Router("/api/projects/?:id", &api.ProjectAPI{}) beego.Router("/api/projects/?:id", &api.ProjectAPI{})
beego.Router("/api/statistics", &api.StatisticAPI{}) beego.Router("/api/statistics", &api.StatisticAPI{})
beego.Router("/api/projects/:id/logs/filter", &api.ProjectAPI{}, "post:FilterAccessLog") beego.Router("/api/projects/:id/logs/filter", &api.ProjectAPI{}, "post:FilterAccessLog")