mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-22 18:25:56 +01:00
commit
38d6d50e23
20
api/base.go
20
api/base.go
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -24,19 +25,23 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// BaseAPI wraps common methods for controllers to host API
|
||||
type BaseAPI struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// Render returns nil as it won't render template
|
||||
func (b *BaseAPI) Render() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RenderError provides shortcut to render http error
|
||||
func (b *BaseAPI) RenderError(code int, text string) {
|
||||
http.Error(b.Ctx.ResponseWriter, text, code)
|
||||
}
|
||||
|
||||
func (b *BaseAPI) DecodeJsonReq(v interface{}) {
|
||||
// DecodeJSONReq decodes a json request
|
||||
func (b *BaseAPI) DecodeJSONReq(v interface{}) {
|
||||
err := json.Unmarshal(b.Ctx.Input.CopyBody(1<<32), v)
|
||||
if err != nil {
|
||||
beego.Error("Error while decoding the json request:", err)
|
||||
@ -44,22 +49,23 @@ func (b *BaseAPI) DecodeJsonReq(v interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateUser checks if the request triggered by a valid user
|
||||
func (b *BaseAPI) ValidateUser() int {
|
||||
|
||||
sessionUserId := b.GetSession("userId")
|
||||
if sessionUserId == nil {
|
||||
sessionUserID := b.GetSession("userId")
|
||||
if sessionUserID == nil {
|
||||
beego.Warning("No user id in session, canceling request")
|
||||
b.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
userId := sessionUserId.(int)
|
||||
u, err := dao.GetUser(models.User{UserId: userId})
|
||||
userID := sessionUserID.(int)
|
||||
u, err := dao.GetUser(models.User{UserID: userID})
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
b.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
beego.Warning("User was deleted already, user id: ", userId, " canceling request.")
|
||||
beego.Warning("User was deleted already, user id: ", userID, " canceling request.")
|
||||
b.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
return userId
|
||||
return userID
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -24,19 +25,21 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// ProjectMemberAPI handles request to /api/projects/{}/members/{}
|
||||
type ProjectMemberAPI struct {
|
||||
BaseAPI
|
||||
memberId int
|
||||
currentUserId int
|
||||
memberID int
|
||||
currentUserID int
|
||||
project *models.Project
|
||||
}
|
||||
|
||||
type memberReq struct {
|
||||
Username string `json:"user_name"`
|
||||
UserId int `json:"user_id"`
|
||||
UserID int `json:"user_id"`
|
||||
Roles []int `json:"roles"`
|
||||
}
|
||||
|
||||
// Prepare validates the URL and parms
|
||||
func (pma *ProjectMemberAPI) Prepare() {
|
||||
pid, err := strconv.ParseInt(pma.Ctx.Input.Param(":pid"), 10, 64)
|
||||
if err != nil {
|
||||
@ -44,7 +47,7 @@ func (pma *ProjectMemberAPI) Prepare() {
|
||||
pma.CustomAbort(http.StatusBadRequest, "invalid project Id")
|
||||
return
|
||||
}
|
||||
p, err := dao.GetProjectById(pid)
|
||||
p, err := dao.GetProjectByID(pid)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetProjectById:", err)
|
||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
@ -55,30 +58,31 @@ func (pma *ProjectMemberAPI) Prepare() {
|
||||
pma.CustomAbort(http.StatusNotFound, "Project does not exist")
|
||||
}
|
||||
pma.project = p
|
||||
pma.currentUserId = pma.ValidateUser()
|
||||
pma.currentUserID = pma.ValidateUser()
|
||||
mid := pma.Ctx.Input.Param(":mid")
|
||||
if mid == "current" {
|
||||
pma.memberId = pma.currentUserId
|
||||
pma.memberID = pma.currentUserID
|
||||
} else if len(mid) == 0 {
|
||||
pma.memberId = 0
|
||||
pma.memberID = 0
|
||||
} else if len(mid) > 0 {
|
||||
memberId, err := strconv.Atoi(mid)
|
||||
memberID, err := strconv.Atoi(mid)
|
||||
if err != nil {
|
||||
beego.Error("Invalid member Id, error:", err)
|
||||
pma.CustomAbort(http.StatusBadRequest, "Invalid member id")
|
||||
}
|
||||
pma.memberId = memberId
|
||||
pma.memberID = memberID
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (pma *ProjectMemberAPI) Get() {
|
||||
pid := pma.project.ProjectId
|
||||
if !CheckProjectPermission(pma.currentUserId, pid) {
|
||||
beego.Warning("Current user, user id :", pma.currentUserId, "does not have permission for project, id:", pid)
|
||||
pid := pma.project.ProjectID
|
||||
if !checkProjectPermission(pma.currentUserID, pid) {
|
||||
beego.Warning("Current user, user id :", pma.currentUserID, "does not have permission for project, id:", pid)
|
||||
pma.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
||||
if pma.memberId == 0 { //member id not set return list of the members
|
||||
if pma.memberID == 0 { //member id not set return list of the members
|
||||
username := pma.GetString("username")
|
||||
queryUser := models.User{Username: "%" + username + "%"}
|
||||
userList, err := dao.GetUserByProject(pid, queryUser)
|
||||
@ -89,86 +93,88 @@ func (pma *ProjectMemberAPI) Get() {
|
||||
}
|
||||
pma.Data["json"] = userList
|
||||
} else { //return detail of a member
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserId: pma.memberId}, pid)
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserID: pma.memberID}, pid)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err)
|
||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
//return empty role list to indicate if a user is not a member
|
||||
result := make(map[string]interface{})
|
||||
user, err := dao.GetUser(models.User{UserId: pma.memberId})
|
||||
user, err := dao.GetUser(models.User{UserID: pma.memberID})
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
result["user_name"] = user.Username
|
||||
result["user_id"] = pma.memberId
|
||||
result["user_id"] = pma.memberID
|
||||
result["roles"] = roleList
|
||||
pma.Data["json"] = result
|
||||
}
|
||||
pma.ServeJSON()
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (pma *ProjectMemberAPI) Post() {
|
||||
pid := pma.project.ProjectId
|
||||
userQuery := models.User{UserId: pma.currentUserId, RoleId: models.PROJECTADMIN}
|
||||
pid := pma.project.ProjectID
|
||||
userQuery := models.User{UserID: pma.currentUserID, RoleID: models.PROJECTADMIN}
|
||||
rolelist, err := dao.GetUserProjectRoles(userQuery, pid)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err)
|
||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if len(rolelist) == 0 {
|
||||
beego.Warning("Current user, id:", pma.currentUserId, "does not have project admin role for project, id:", pid)
|
||||
beego.Warning("Current user, id:", pma.currentUserID, "does not have project admin role for project, id:", pid)
|
||||
pma.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
||||
var req memberReq
|
||||
pma.DecodeJsonReq(&req)
|
||||
pma.DecodeJSONReq(&req)
|
||||
username := req.Username
|
||||
userId := CheckUserExists(username)
|
||||
if userId <= 0 {
|
||||
userID := checkUserExists(username)
|
||||
if userID <= 0 {
|
||||
beego.Warning("User does not exist, user name:", username)
|
||||
pma.RenderError(http.StatusNotFound, "User does not exist")
|
||||
return
|
||||
}
|
||||
rolelist, err = dao.GetUserProjectRoles(models.User{UserId: userId}, pid)
|
||||
rolelist, err = dao.GetUserProjectRoles(models.User{UserID: userID}, pid)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err)
|
||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if len(rolelist) > 0 {
|
||||
beego.Warning("user is already added to project, user id:", userId, ", project id:", pid)
|
||||
beego.Warning("user is already added to project, user id:", userID, ", project id:", pid)
|
||||
pma.RenderError(http.StatusConflict, "user is ready in project")
|
||||
return
|
||||
}
|
||||
|
||||
for _, rid := range req.Roles {
|
||||
err = dao.AddUserProjectRole(userId, pid, int(rid))
|
||||
err = dao.AddUserProjectRole(userID, pid, int(rid))
|
||||
if err != nil {
|
||||
beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", userId, ", role id:", rid)
|
||||
beego.Error("Failed to update DB to add project user role, project id:", pid, ", user id:", userID, ", role id:", rid)
|
||||
pma.RenderError(http.StatusInternalServerError, "Failed to update data in database")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put ...
|
||||
func (pma *ProjectMemberAPI) Put() {
|
||||
pid := pma.project.ProjectId
|
||||
mid := pma.memberId
|
||||
userQuery := models.User{UserId: pma.currentUserId, RoleId: models.PROJECTADMIN}
|
||||
pid := pma.project.ProjectID
|
||||
mid := pma.memberID
|
||||
userQuery := models.User{UserID: pma.currentUserID, RoleID: models.PROJECTADMIN}
|
||||
rolelist, err := dao.GetUserProjectRoles(userQuery, pid)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err)
|
||||
pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if len(rolelist) == 0 {
|
||||
beego.Warning("Current user, id:", pma.currentUserId, ", does not have project admin role for project, id:", pid)
|
||||
beego.Warning("Current user, id:", pma.currentUserID, ", does not have project admin role for project, id:", pid)
|
||||
pma.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
||||
var req memberReq
|
||||
pma.DecodeJsonReq(&req)
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserId: mid}, pid)
|
||||
pma.DecodeJSONReq(&req)
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserID: mid}, pid)
|
||||
if len(roleList) == 0 {
|
||||
beego.Warning("User is not in project, user id:", mid, ", project id:", pid)
|
||||
pma.RenderError(http.StatusNotFound, "user not exist in project")
|
||||
@ -193,13 +199,14 @@ func (pma *ProjectMemberAPI) Put() {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (pma *ProjectMemberAPI) Delete() {
|
||||
pid := pma.project.ProjectId
|
||||
mid := pma.memberId
|
||||
userQuery := models.User{UserId: pma.currentUserId, RoleId: models.PROJECTADMIN}
|
||||
pid := pma.project.ProjectID
|
||||
mid := pma.memberID
|
||||
userQuery := models.User{UserID: pma.currentUserID, RoleID: models.PROJECTADMIN}
|
||||
rolelist, err := dao.GetUserProjectRoles(userQuery, pid)
|
||||
if len(rolelist) == 0 {
|
||||
beego.Warning("Current user, id:", pma.currentUserId, ", does not have project admin role for project, id:", pid)
|
||||
beego.Warning("Current user, id:", pma.currentUserID, ", does not have project admin role for project, id:", pid)
|
||||
pma.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -28,10 +29,11 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// ProjectAPI handles request to /api/projects/{} /api/projects/{}/logs
|
||||
type ProjectAPI struct {
|
||||
BaseAPI
|
||||
userId int
|
||||
projectId int64
|
||||
userID int
|
||||
projectID int64
|
||||
}
|
||||
|
||||
type projectReq struct {
|
||||
@ -39,33 +41,35 @@ type projectReq struct {
|
||||
Public bool `json:"public"`
|
||||
}
|
||||
|
||||
const PROJECT_NAME_MAX_LEN int = 30
|
||||
const projectNameMaxLen int = 30
|
||||
|
||||
// Prepare validates the URL and the user
|
||||
func (p *ProjectAPI) Prepare() {
|
||||
p.userId = p.ValidateUser()
|
||||
id_str := p.Ctx.Input.Param(":id")
|
||||
if len(id_str) > 0 {
|
||||
p.userID = p.ValidateUser()
|
||||
idStr := p.Ctx.Input.Param(":id")
|
||||
if len(idStr) > 0 {
|
||||
var err error
|
||||
p.projectId, err = strconv.ParseInt(id_str, 10, 64)
|
||||
p.projectID, err = strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("Error parsing project id: %s, error: %v", id_str, err)
|
||||
log.Printf("Error parsing project id: %s, error: %v", idStr, err)
|
||||
p.CustomAbort(http.StatusBadRequest, "invalid project id")
|
||||
}
|
||||
exist, err := dao.ProjectExists(p.projectId)
|
||||
exist, err := dao.ProjectExists(p.projectID)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in ProjectExists: %v", err)
|
||||
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if !exist {
|
||||
p.CustomAbort(http.StatusNotFound, fmt.Sprintf("project does not exist, id: %v", p.projectId))
|
||||
p.CustomAbort(http.StatusNotFound, fmt.Sprintf("project does not exist, id: %v", p.projectID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (p *ProjectAPI) Post() {
|
||||
var req projectReq
|
||||
var public int
|
||||
p.DecodeJsonReq(&req)
|
||||
p.DecodeJSONReq(&req)
|
||||
if req.Public {
|
||||
public = 1
|
||||
}
|
||||
@ -84,14 +88,15 @@ func (p *ProjectAPI) Post() {
|
||||
p.RenderError(http.StatusConflict, "")
|
||||
return
|
||||
}
|
||||
project := models.Project{OwnerId: p.userId, Name: projectName, CreationTime: time.Now(), Public: public}
|
||||
project := models.Project{OwnerID: p.userID, Name: projectName, CreationTime: time.Now(), Public: public}
|
||||
err = dao.AddProject(project)
|
||||
if err != nil {
|
||||
beego.Error("Failed to add project, error: %v", err)
|
||||
beego.Error("Failed to add project, error: ", err)
|
||||
p.RenderError(http.StatusInternalServerError, "Failed to add project")
|
||||
}
|
||||
}
|
||||
|
||||
// Head ...
|
||||
func (p *ProjectAPI) Head() {
|
||||
projectName := p.GetString("project_name")
|
||||
result, err := dao.ProjectExists(projectName)
|
||||
@ -106,8 +111,9 @@ func (p *ProjectAPI) Head() {
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (p *ProjectAPI) Get() {
|
||||
queryProject := models.Project{UserId: p.userId}
|
||||
queryProject := models.Project{UserID: p.userID}
|
||||
projectName := p.GetString("project_name")
|
||||
if len(projectName) > 0 {
|
||||
queryProject.Name = "%" + projectName + "%"
|
||||
@ -121,7 +127,7 @@ func (p *ProjectAPI) Get() {
|
||||
p.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
for i := 0; i < len(projectList); i++ {
|
||||
if isProjectAdmin(p.userId, projectList[i].ProjectId) {
|
||||
if isProjectAdmin(p.userID, projectList[i].ProjectID) {
|
||||
projectList[i].Togglable = true
|
||||
}
|
||||
}
|
||||
@ -129,37 +135,39 @@ func (p *ProjectAPI) Get() {
|
||||
p.ServeJSON()
|
||||
}
|
||||
|
||||
// Put ...
|
||||
func (p *ProjectAPI) Put() {
|
||||
var req projectReq
|
||||
var public int
|
||||
|
||||
projectId, err := strconv.ParseInt(p.Ctx.Input.Param(":id"), 10, 64)
|
||||
projectID, err := strconv.ParseInt(p.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil {
|
||||
beego.Error("Error parsing project id:", projectId, ", error: ", err)
|
||||
beego.Error("Error parsing project id:", projectID, ", error: ", err)
|
||||
p.RenderError(http.StatusBadRequest, "invalid project id")
|
||||
return
|
||||
}
|
||||
|
||||
p.DecodeJsonReq(&req)
|
||||
p.DecodeJSONReq(&req)
|
||||
if req.Public {
|
||||
public = 1
|
||||
}
|
||||
if !isProjectAdmin(p.userId, projectId) {
|
||||
beego.Warning("Current user, id:", p.userId, ", does not have project admin role for project, id:", projectId)
|
||||
if !isProjectAdmin(p.userID, projectID) {
|
||||
beego.Warning("Current user, id:", p.userID, ", does not have project admin role for project, id:", projectID)
|
||||
p.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
||||
err = dao.ToggleProjectPublicity(p.projectId, public)
|
||||
err = dao.ToggleProjectPublicity(p.projectID, public)
|
||||
if err != nil {
|
||||
beego.Error("Error while updating project, project id:", projectId, ", error:", err)
|
||||
beego.Error("Error while updating project, project id:", projectID, ", error:", err)
|
||||
p.RenderError(http.StatusInternalServerError, "Failed to update project")
|
||||
}
|
||||
}
|
||||
|
||||
// FilterAccessLog handles GET to /api/projects/{}/logs
|
||||
func (p *ProjectAPI) FilterAccessLog() {
|
||||
|
||||
var filter models.AccessLog
|
||||
p.DecodeJsonReq(&filter)
|
||||
p.DecodeJSONReq(&filter)
|
||||
|
||||
username := filter.Username
|
||||
keywords := filter.Keywords
|
||||
@ -167,7 +175,7 @@ func (p *ProjectAPI) FilterAccessLog() {
|
||||
beginTime := time.Unix(filter.BeginTimestamp, 0)
|
||||
endTime := time.Unix(filter.EndTimestamp, 0)
|
||||
|
||||
query := models.AccessLog{ProjectId: p.projectId, Username: "%" + username + "%", Keywords: keywords, BeginTime: beginTime, BeginTimestamp: filter.BeginTimestamp, EndTime: endTime, EndTimestamp: filter.EndTimestamp}
|
||||
query := models.AccessLog{ProjectID: p.projectID, Username: "%" + username + "%", Keywords: keywords, BeginTime: beginTime, BeginTimestamp: filter.BeginTimestamp, EndTime: endTime, EndTimestamp: filter.EndTimestamp}
|
||||
|
||||
log.Printf("Query AccessLog: begin: %v, end: %v, keywords: %s", query.BeginTime, query.EndTime, query.Keywords)
|
||||
|
||||
@ -180,8 +188,8 @@ func (p *ProjectAPI) FilterAccessLog() {
|
||||
p.ServeJSON()
|
||||
}
|
||||
|
||||
func isProjectAdmin(userId int, pid int64) bool {
|
||||
userQuery := models.User{UserId: userId, RoleId: models.PROJECTADMIN}
|
||||
func isProjectAdmin(userID int, pid int64) bool {
|
||||
userQuery := models.User{UserID: userID, RoleID: models.PROJECTADMIN}
|
||||
rolelist, err := dao.GetUserProjectRoles(userQuery, pid)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err, ", returning false")
|
||||
@ -195,7 +203,7 @@ func validateProjectReq(req projectReq) error {
|
||||
if len(pn) == 0 {
|
||||
return fmt.Errorf("Project name can not be empty")
|
||||
}
|
||||
if len(pn) > PROJECT_NAME_MAX_LEN {
|
||||
if len(pn) > projectNameMaxLen {
|
||||
return fmt.Errorf("Project name is too long")
|
||||
}
|
||||
return nil
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -28,21 +29,23 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
//For repostiories, we won't check the session in this API due to search functionality, querying manifest will be contorlled by
|
||||
//the security of registry
|
||||
|
||||
// RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put
|
||||
// in the query string as the web framework can not parse the URL if it contains veriadic sectors.
|
||||
// For repostiories, we won't check the session in this API due to search functionality, querying manifest will be contorlled by
|
||||
// the security of registry
|
||||
type RepositoryAPI struct {
|
||||
BaseAPI
|
||||
userId int
|
||||
userID int
|
||||
username string
|
||||
}
|
||||
|
||||
// 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() {
|
||||
userId, ok := ra.GetSession("userId").(int)
|
||||
userID, ok := ra.GetSession("userId").(int)
|
||||
if !ok {
|
||||
ra.userId = dao.NON_EXIST_USER_ID
|
||||
ra.userID = dao.NonExistUserID
|
||||
} else {
|
||||
ra.userId = userId
|
||||
ra.userID = userID
|
||||
}
|
||||
username, ok := ra.GetSession("username").(string)
|
||||
if !ok {
|
||||
@ -53,24 +56,25 @@ func (ra *RepositoryAPI) Prepare() {
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (ra *RepositoryAPI) Get() {
|
||||
projectId, err0 := ra.GetInt64("project_id")
|
||||
projectID, err0 := ra.GetInt64("project_id")
|
||||
if err0 != nil {
|
||||
beego.Error("Failed to get project id, error:", err0)
|
||||
ra.RenderError(http.StatusBadRequest, "Invalid project id")
|
||||
return
|
||||
}
|
||||
p, err := dao.GetProjectById(projectId)
|
||||
p, err := dao.GetProjectByID(projectID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetProjectById:", err)
|
||||
ra.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if p == nil {
|
||||
beego.Warning("Project with Id:", projectId, ", does not exist", projectId)
|
||||
beego.Warning("Project with Id:", projectID, ", does not exist")
|
||||
ra.RenderError(http.StatusNotFound, "")
|
||||
return
|
||||
}
|
||||
if p.Public == 0 && !CheckProjectPermission(ra.userId, projectId) {
|
||||
if p.Public == 0 && !checkProjectPermission(ra.userID, projectID) {
|
||||
ra.RenderError(http.StatusForbidden, "")
|
||||
return
|
||||
}
|
||||
@ -102,34 +106,35 @@ func (ra *RepositoryAPI) Get() {
|
||||
ra.ServeJSON()
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Name string `json: "name"`
|
||||
type tag struct {
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type HistroyItem struct {
|
||||
type histroyItem struct {
|
||||
V1Compatibility string `json:"v1Compatibility"`
|
||||
}
|
||||
|
||||
type Manifest struct {
|
||||
type manifest struct {
|
||||
Name string `json:"name"`
|
||||
Tag string `json:"tag"`
|
||||
Architecture string `json:"architecture"`
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
History []HistroyItem `json:"history"`
|
||||
History []histroyItem `json:"history"`
|
||||
}
|
||||
|
||||
// GetTags handles GET /api/repositories/tags
|
||||
func (ra *RepositoryAPI) GetTags() {
|
||||
|
||||
var tags []string
|
||||
|
||||
repoName := ra.GetString("repo_name")
|
||||
result, err := svc_utils.RegistryApiGet(svc_utils.BuildRegistryUrl(repoName, "tags", "list"), ra.username)
|
||||
result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "tags", "list"), ra.username)
|
||||
if err != nil {
|
||||
beego.Error("Failed to get repo tags, repo name:", repoName, ", error: ", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Failed to get repo tags")
|
||||
} else {
|
||||
t := Tag{}
|
||||
t := tag{}
|
||||
json.Unmarshal(result, &t)
|
||||
tags = t.Tags
|
||||
}
|
||||
@ -137,38 +142,36 @@ func (ra *RepositoryAPI) GetTags() {
|
||||
ra.ServeJSON()
|
||||
}
|
||||
|
||||
// GetManifests handles GET /api/repositories/manifests
|
||||
func (ra *RepositoryAPI) GetManifests() {
|
||||
repoName := ra.GetString("repo_name")
|
||||
tag := ra.GetString("tag")
|
||||
|
||||
item := models.RepoItem{}
|
||||
|
||||
result, err := svc_utils.RegistryApiGet(svc_utils.BuildRegistryUrl(repoName, "manifests", tag), ra.username)
|
||||
result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "manifests", tag), ra.username)
|
||||
if err != nil {
|
||||
beego.Error("Failed to get manifests for repo, repo name:", repoName, ", tag:", tag, ", error:", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
} else {
|
||||
mani := Manifest{}
|
||||
err = json.Unmarshal(result, &mani)
|
||||
if err != nil {
|
||||
beego.Error("Failed to decode json from response for manifests, repo name:", repoName, ", tag:", tag, ", error:", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
} else {
|
||||
v1Compatibility := mani.History[0].V1Compatibility
|
||||
|
||||
err = json.Unmarshal([]byte(v1Compatibility), &item)
|
||||
if err != nil {
|
||||
beego.Error("Failed to decode V1 field for repo, repo name:", repoName, ", tag:", tag, ", error:", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
} else {
|
||||
item.CreatedStr = item.Created.Format("2006-01-02 15:04:05")
|
||||
item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days"
|
||||
}
|
||||
}
|
||||
}
|
||||
mani := manifest{}
|
||||
err = json.Unmarshal(result, &mani)
|
||||
if err != nil {
|
||||
beego.Error("Failed to decode json from response for manifests, repo name:", repoName, ", tag:", tag, ", error:", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
v1Compatibility := mani.History[0].V1Compatibility
|
||||
|
||||
err = json.Unmarshal([]byte(v1Compatibility), &item)
|
||||
if err != nil {
|
||||
beego.Error("Failed to decode V1 field for repo, repo name:", repoName, ", tag:", tag, ", error:", err)
|
||||
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
item.CreatedStr = item.Created.Format("2006-01-02 15:04:05")
|
||||
item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days"
|
||||
|
||||
ra.Data["json"] = item
|
||||
ra.ServeJSON()
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -27,24 +28,26 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// SearchAPI handles requesst to /api/search
|
||||
type SearchAPI struct {
|
||||
BaseAPI
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
type searchResult struct {
|
||||
Project []map[string]interface{} `json:"project"`
|
||||
Repository []map[string]interface{} `json:"repository"`
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (n *SearchAPI) Get() {
|
||||
userId, ok := n.GetSession("userId").(int)
|
||||
userID, ok := n.GetSession("userId").(int)
|
||||
if !ok {
|
||||
userId = dao.NON_EXIST_USER_ID
|
||||
userID = dao.NonExistUserID
|
||||
}
|
||||
keyword := n.GetString("q")
|
||||
projects, err := dao.QueryRelevantProjects(userId)
|
||||
projects, err := dao.QueryRelevantProjects(userID)
|
||||
if err != nil {
|
||||
beego.Error("Failed to get projects of user id:", userId, ", error:", err)
|
||||
beego.Error("Failed to get projects of user id:", userID, ", error:", err)
|
||||
n.CustomAbort(http.StatusInternalServerError, "Failed to get project search result")
|
||||
}
|
||||
projectSorter := &utils.ProjectSorter{Projects: projects}
|
||||
@ -57,7 +60,7 @@ func (n *SearchAPI) Get() {
|
||||
}
|
||||
if match {
|
||||
entry := make(map[string]interface{})
|
||||
entry["id"] = p.ProjectId
|
||||
entry["id"] = p.ProjectID
|
||||
entry["name"] = p.Name
|
||||
entry["public"] = p.Public
|
||||
projectResult = append(projectResult, entry)
|
||||
@ -71,7 +74,7 @@ func (n *SearchAPI) Get() {
|
||||
}
|
||||
sort.Strings(repositories)
|
||||
repositoryResult := filterRepositories(repositories, projects, keyword)
|
||||
result := &SearchResult{Project: projectResult, Repository: repositoryResult}
|
||||
result := &searchResult{Project: projectResult, Repository: repositoryResult}
|
||||
n.Data["json"] = result
|
||||
n.ServeJSON()
|
||||
}
|
||||
@ -93,7 +96,7 @@ func filterRepositories(repositories []string, projects []models.Project, keywor
|
||||
entry := make(map[string]interface{})
|
||||
entry["repository_name"] = r.Name
|
||||
entry["project_name"] = projects[j].Name
|
||||
entry["project_id"] = projects[j].ProjectId
|
||||
entry["project_id"] = projects[j].ProjectID
|
||||
entry["project_public"] = projects[j].Public
|
||||
result = append(result, entry)
|
||||
} else {
|
||||
|
44
api/user.go
44
api/user.go
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -24,48 +25,51 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// UserAPI handles request to /api/users/{}
|
||||
type UserAPI struct {
|
||||
BaseAPI
|
||||
currentUid int
|
||||
userId int
|
||||
currentUserID int
|
||||
userID int
|
||||
}
|
||||
|
||||
// Prepare validates the URL and parms
|
||||
func (ua *UserAPI) Prepare() {
|
||||
|
||||
ua.currentUid = ua.ValidateUser()
|
||||
ua.currentUserID = ua.ValidateUser()
|
||||
id := ua.Ctx.Input.Param(":id")
|
||||
if id == "current" {
|
||||
ua.userId = ua.currentUid
|
||||
ua.userID = ua.currentUserID
|
||||
} else if len(id) > 0 {
|
||||
var err error
|
||||
ua.userId, err = strconv.Atoi(id)
|
||||
ua.userID, err = strconv.Atoi(id)
|
||||
if err != nil {
|
||||
beego.Error("Invalid user id, error:", err)
|
||||
ua.CustomAbort(http.StatusBadRequest, "Invalid user Id")
|
||||
}
|
||||
userQuery := models.User{UserId: ua.userId}
|
||||
userQuery := models.User{UserID: ua.userID}
|
||||
u, err := dao.GetUser(userQuery)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
beego.Error("User with Id:", ua.userId, "does not exist")
|
||||
beego.Error("User with Id:", ua.userID, "does not exist")
|
||||
ua.CustomAbort(http.StatusNotFound, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (ua *UserAPI) Get() {
|
||||
exist, err := dao.IsAdminRole(ua.currentUid)
|
||||
exist, err := dao.IsAdminRole(ua.currentUserID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in IsAdminRole:", err)
|
||||
ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
|
||||
if ua.userId == 0 { //list users
|
||||
if ua.userID == 0 { //list users
|
||||
if !exist {
|
||||
beego.Error("Current user, id:", ua.currentUid, ", does not have admin role, can not list users")
|
||||
beego.Error("Current user, id:", ua.currentUserID, ", does not have admin role, can not list users")
|
||||
ua.RenderError(http.StatusForbidden, "User does not have admin role")
|
||||
return
|
||||
}
|
||||
@ -82,8 +86,8 @@ func (ua *UserAPI) Get() {
|
||||
}
|
||||
ua.Data["json"] = userList
|
||||
|
||||
} else if ua.userId == ua.currentUid || exist {
|
||||
userQuery := models.User{UserId: ua.userId}
|
||||
} else if ua.userID == ua.currentUserID || exist {
|
||||
userQuery := models.User{UserID: ua.userID}
|
||||
u, err := dao.GetUser(userQuery)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
@ -91,40 +95,42 @@ func (ua *UserAPI) Get() {
|
||||
}
|
||||
ua.Data["json"] = u
|
||||
} else {
|
||||
beego.Error("Current user, id:", ua.currentUid, "does not have admin role, can not view other user's detail")
|
||||
beego.Error("Current user, id:", ua.currentUserID, "does not have admin role, can not view other user's detail")
|
||||
ua.RenderError(http.StatusForbidden, "User does not have admin role")
|
||||
return
|
||||
}
|
||||
ua.ServeJSON()
|
||||
}
|
||||
|
||||
// Put ...
|
||||
func (ua *UserAPI) Put() { //currently only for toggle admin, so no request body
|
||||
exist, err := dao.IsAdminRole(ua.currentUid)
|
||||
exist, err := dao.IsAdminRole(ua.currentUserID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in IsAdminRole:", err)
|
||||
ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if !exist {
|
||||
beego.Warning("current user, id:", ua.currentUid, ", does not have admin role, can not update other user's role")
|
||||
beego.Warning("current user, id:", ua.currentUserID, ", does not have admin role, can not update other user's role")
|
||||
ua.RenderError(http.StatusForbidden, "User does not have admin role")
|
||||
return
|
||||
}
|
||||
userQuery := models.User{UserId: ua.userId}
|
||||
userQuery := models.User{UserID: ua.userID}
|
||||
dao.ToggleUserAdminRole(userQuery)
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (ua *UserAPI) Delete() {
|
||||
exist, err := dao.IsAdminRole(ua.currentUid)
|
||||
exist, err := dao.IsAdminRole(ua.currentUserID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in IsAdminRole:", err)
|
||||
ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if !exist {
|
||||
beego.Warning("current user, id:", ua.currentUid, ", does not have admin role, can not remove user")
|
||||
beego.Warning("current user, id:", ua.currentUserID, ", does not have admin role, can not remove user")
|
||||
ua.RenderError(http.StatusForbidden, "User does not have admin role")
|
||||
return
|
||||
}
|
||||
err = dao.DeleteUser(ua.userId)
|
||||
err = dao.DeleteUser(ua.userID)
|
||||
if err != nil {
|
||||
beego.Error("Failed to delete data from database, error:", err)
|
||||
ua.RenderError(http.StatusInternalServerError, "Failed to delete User")
|
||||
|
11
api/utils.go
11
api/utils.go
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
@ -21,8 +22,8 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func CheckProjectPermission(userId int, projectId int64) bool {
|
||||
exist, err := dao.IsAdminRole(userId)
|
||||
func checkProjectPermission(userID int, projectID int64) bool {
|
||||
exist, err := dao.IsAdminRole(userID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in IsAdminRole:", err)
|
||||
return false
|
||||
@ -30,7 +31,7 @@ func CheckProjectPermission(userId int, projectId int64) bool {
|
||||
if exist {
|
||||
return true
|
||||
}
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserId: userId}, projectId)
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserID: userID}, projectID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err)
|
||||
return false
|
||||
@ -38,14 +39,14 @@ func CheckProjectPermission(userId int, projectId int64) bool {
|
||||
return len(roleList) > 0
|
||||
}
|
||||
|
||||
func CheckUserExists(name string) int {
|
||||
func checkUserExists(name string) int {
|
||||
u, err := dao.GetUser(models.User{Username: name})
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
return 0
|
||||
}
|
||||
if u != nil {
|
||||
return u.UserId
|
||||
return u.UserID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package opt_auth
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/vmware/harbor/models"
|
||||
@ -23,31 +25,36 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
type OptAuth interface {
|
||||
Validate(auth models.AuthModel) (*models.User, error)
|
||||
// Authenticator provides interface to authenticate user credentials.
|
||||
type Authenticator interface {
|
||||
|
||||
// Authenticate ...
|
||||
Authenticate(m models.AuthModel) (*models.User, error)
|
||||
}
|
||||
|
||||
var registry = make(map[string]OptAuth)
|
||||
var registry = make(map[string]Authenticator)
|
||||
|
||||
func Register(name string, optAuth OptAuth) {
|
||||
// Register add different authenticators to registry map.
|
||||
func Register(name string, authenticator Authenticator) {
|
||||
if _, dup := registry[name]; dup {
|
||||
panic(name + " already exist.")
|
||||
log.Printf("authenticator: %s has been registered", name)
|
||||
return
|
||||
}
|
||||
registry[name] = optAuth
|
||||
registry[name] = authenticator
|
||||
}
|
||||
|
||||
func Login(auth models.AuthModel) (*models.User, error) {
|
||||
// Login authenticates user credentials based on setting.
|
||||
func Login(m models.AuthModel) (*models.User, error) {
|
||||
|
||||
var authMode string = os.Getenv("AUTH_MODE")
|
||||
if authMode == "" || auth.Principal == "admin" {
|
||||
var authMode = os.Getenv("AUTH_MODE")
|
||||
if authMode == "" || m.Principal == "admin" {
|
||||
authMode = "db_auth"
|
||||
}
|
||||
beego.Debug("Current AUTH_MODE is ", authMode)
|
||||
|
||||
optAuth := registry[authMode]
|
||||
if optAuth == nil {
|
||||
authenticator, ok := registry[authMode]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Unrecognized auth_mode: %s", authMode)
|
||||
}
|
||||
return optAuth.Validate(auth)
|
||||
return authenticator.Authenticate(m)
|
||||
}
|
@ -12,18 +12,21 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/vmware/harbor/auth"
|
||||
"github.com/vmware/harbor/dao"
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/opt_auth"
|
||||
)
|
||||
|
||||
type DbAuth struct{}
|
||||
// Auth implements Authenticator interface to authenticate user against DB.
|
||||
type Auth struct{}
|
||||
|
||||
func (d *DbAuth) Validate(auth models.AuthModel) (*models.User, error) {
|
||||
u, err := dao.LoginByDb(auth)
|
||||
// Authenticate calls dao to authenticate user.
|
||||
func (d *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
u, err := dao.LoginByDb(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -31,5 +34,5 @@ func (d *DbAuth) Validate(auth models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
opt_auth.Register("db_auth", &DbAuth{})
|
||||
auth.Register("db_auth", &Auth{})
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
@ -21,35 +22,38 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/harbor/auth"
|
||||
"github.com/vmware/harbor/dao"
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/opt_auth"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/mqu/openldap"
|
||||
)
|
||||
|
||||
type LdapAuth struct{}
|
||||
// Auth implements Authenticator interface to authenticate against LDAP
|
||||
type Auth struct{}
|
||||
|
||||
const META_CHARS = "&|!=~*<>()"
|
||||
const metaChars = "&|!=~*<>()"
|
||||
|
||||
func (l *LdapAuth) Validate(auth models.AuthModel) (*models.User, error) {
|
||||
// Authenticate checks user's credential agains LDAP based on basedn template and LDAP URL,
|
||||
// if the check is successful a dummy record will be insert into DB, such that this user can
|
||||
// be associated to other entities in the system.
|
||||
func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
|
||||
ldapUrl := os.Getenv("LDAP_URL")
|
||||
if ldapUrl == "" {
|
||||
ldapURL := os.Getenv("LDAP_URL")
|
||||
if ldapURL == "" {
|
||||
return nil, errors.New("Can not get any available LDAP_URL.")
|
||||
}
|
||||
beego.Debug("ldapUrl:", ldapUrl)
|
||||
beego.Debug("ldapURL:", ldapURL)
|
||||
|
||||
p := auth.Principal
|
||||
for _, c := range META_CHARS {
|
||||
p := m.Principal
|
||||
for _, c := range metaChars {
|
||||
if strings.ContainsRune(p, c) {
|
||||
log.Printf("The principal contains meta char: %q", c)
|
||||
return nil, nil
|
||||
return nil, fmt.Errorf("the principal contains meta char: %q", c)
|
||||
}
|
||||
}
|
||||
|
||||
ldap, err := openldap.Initialize(ldapUrl)
|
||||
ldap, err := openldap.Initialize(ldapURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -62,10 +66,10 @@ func (l *LdapAuth) Validate(auth models.AuthModel) (*models.User, error) {
|
||||
return nil, errors.New("Can not get any available LDAP_BASE_DN.")
|
||||
}
|
||||
|
||||
baseDn := fmt.Sprintf(ldapBaseDn, auth.Principal)
|
||||
baseDn := fmt.Sprintf(ldapBaseDn, m.Principal)
|
||||
beego.Debug("baseDn:", baseDn)
|
||||
|
||||
err = ldap.Bind(baseDn, auth.Password)
|
||||
err = ldap.Bind(baseDn, m.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -108,19 +112,19 @@ func (l *LdapAuth) Validate(auth models.AuthModel) (*models.User, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.UserId = currentUser.UserId
|
||||
u.UserID = currentUser.UserID
|
||||
} else {
|
||||
u.Password = "12345678AbC"
|
||||
u.Comment = "registered from LDAP."
|
||||
userId, err := dao.Register(u)
|
||||
userID, err := dao.Register(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.UserId = int(userId)
|
||||
u.UserID = int(userID)
|
||||
}
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
opt_auth.Register("ldap_auth", &LdapAuth{})
|
||||
auth.Register("ldap_auth", &Auth{})
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
@ -23,14 +24,17 @@ import (
|
||||
"github.com/beego/i18n"
|
||||
)
|
||||
|
||||
// CommonController handles request from UI that doesn't expect a page, such as /login /logout ...
|
||||
type CommonController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Render returns nil.
|
||||
func (c *CommonController) Render() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// BaseController wraps common methods such as i18n support, forward, which can be leveraged by other UI render controllers.
|
||||
type BaseController struct {
|
||||
beego.Controller
|
||||
i18n.Locale
|
||||
@ -42,14 +46,15 @@ type langType struct {
|
||||
}
|
||||
|
||||
const (
|
||||
DEFAULT_LANG = "en-US"
|
||||
defaultLang = "en-US"
|
||||
)
|
||||
|
||||
var supportLanguages map[string]langType
|
||||
|
||||
// Prepare extracts the language information from request and populate data for rendering templates.
|
||||
func (b *BaseController) Prepare() {
|
||||
|
||||
var lang string = ""
|
||||
var lang string
|
||||
al := b.Ctx.Request.Header.Get("Accept-Language")
|
||||
|
||||
if len(al) > 4 {
|
||||
@ -60,7 +65,7 @@ func (b *BaseController) Prepare() {
|
||||
}
|
||||
|
||||
if _, exist := supportLanguages[lang]; exist == false { //Check if support the request language.
|
||||
lang = DEFAULT_LANG //Set default language if not supported.
|
||||
lang = defaultLang //Set default language if not supported.
|
||||
}
|
||||
|
||||
sessionLang := b.GetSession("lang")
|
||||
@ -88,8 +93,8 @@ func (b *BaseController) Prepare() {
|
||||
b.Data["CurLang"] = curLang.Name
|
||||
b.Data["RestLangs"] = restLangs
|
||||
|
||||
sessionUserId := b.GetSession("userId")
|
||||
if sessionUserId != nil {
|
||||
sessionUserID := b.GetSession("userId")
|
||||
if sessionUserID != nil {
|
||||
b.Data["Username"] = b.GetSession("username")
|
||||
}
|
||||
authMode := os.Getenv("AUTH_MODE")
|
||||
@ -99,6 +104,7 @@ func (b *BaseController) Prepare() {
|
||||
b.Data["AuthMode"] = authMode
|
||||
}
|
||||
|
||||
// ForwardTo setup layout and template for content for a page.
|
||||
func (b *BaseController) ForwardTo(pageTitle string, pageName string) {
|
||||
b.Layout = "segment/base-layout.tpl"
|
||||
b.TplName = "segment/base-layout.tpl"
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
@ -25,21 +26,24 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// ItemDetailController handles requet to /registry/detail, which shows the detail of a project.
|
||||
type ItemDetailController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get will check if user has permission to view a certain project, if not user will be redirected to signin or his homepage.
|
||||
// If the check is passed it renders the project detail page.
|
||||
func (idc *ItemDetailController) Get() {
|
||||
|
||||
projectId, _ := idc.GetInt64("project_id")
|
||||
projectID, _ := idc.GetInt64("project_id")
|
||||
|
||||
if projectId <= 0 {
|
||||
beego.Error("Invalid project id:", projectId)
|
||||
if projectID <= 0 {
|
||||
beego.Error("Invalid project id:", projectID)
|
||||
idc.Redirect("/signIn", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
project, err := dao.GetProjectById(projectId)
|
||||
project, err := dao.GetProjectByID(projectID)
|
||||
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetProjectById:", err)
|
||||
@ -51,19 +55,19 @@ func (idc *ItemDetailController) Get() {
|
||||
return
|
||||
}
|
||||
|
||||
sessionUserId := idc.GetSession("userId")
|
||||
sessionUserID := idc.GetSession("userId")
|
||||
|
||||
if project.Public != 1 && sessionUserId == nil {
|
||||
if project.Public != 1 && sessionUserID == nil {
|
||||
idc.Redirect("/signIn?uri="+url.QueryEscape(idc.Ctx.Input.URI()), http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
if sessionUserId != nil {
|
||||
if sessionUserID != nil {
|
||||
|
||||
idc.Data["Username"] = idc.GetSession("username")
|
||||
idc.Data["UserId"] = sessionUserId.(int)
|
||||
idc.Data["UserId"] = sessionUserID.(int)
|
||||
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserId: sessionUserId.(int)}, projectId)
|
||||
roleList, err := dao.GetUserProjectRoles(models.User{UserID: sessionUserID.(int)}, projectID)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUserProjectRoles:", err)
|
||||
idc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
@ -75,14 +79,14 @@ func (idc *ItemDetailController) Get() {
|
||||
}
|
||||
|
||||
if len(roleList) > 0 {
|
||||
idc.Data["RoleId"] = roleList[0].RoleId
|
||||
idc.Data["RoleId"] = roleList[0].RoleID
|
||||
}
|
||||
}
|
||||
|
||||
idc.Data["ProjectId"] = project.ProjectId
|
||||
idc.Data["ProjectId"] = project.ProjectID
|
||||
idc.Data["ProjectName"] = project.Name
|
||||
idc.Data["OwnerName"] = project.OwnerName
|
||||
idc.Data["OwnerId"] = project.OwnerId
|
||||
idc.Data["OwnerId"] = project.OwnerID
|
||||
|
||||
idc.Data["HarborRegUrl"] = os.Getenv("HARBOR_REG_URL")
|
||||
idc.Data["RepoName"] = idc.GetString("repo_name")
|
||||
|
@ -12,39 +12,45 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/auth"
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/opt_auth"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// IndexController handles request to /
|
||||
type IndexController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the index page.
|
||||
func (c *IndexController) Get() {
|
||||
c.Data["Username"] = c.GetSession("username")
|
||||
c.ForwardTo("page_title_index", "index")
|
||||
}
|
||||
|
||||
// SignInController handles request to /signIn
|
||||
type SignInController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders Sign In page.
|
||||
func (sic *SignInController) Get() {
|
||||
sic.ForwardTo("page_title_sign_in", "sign-in")
|
||||
}
|
||||
|
||||
// Login handles login request from UI.
|
||||
func (c *CommonController) Login() {
|
||||
principal := c.GetString("principal")
|
||||
password := c.GetString("password")
|
||||
|
||||
user, err := opt_auth.Login(models.AuthModel{principal, password})
|
||||
user, err := auth.Login(models.AuthModel{principal, password})
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in UserLogin:", err)
|
||||
c.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
@ -54,10 +60,11 @@ func (c *CommonController) Login() {
|
||||
c.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
|
||||
c.SetSession("userId", user.UserId)
|
||||
c.SetSession("userId", user.UserID)
|
||||
c.SetSession("username", user.Username)
|
||||
}
|
||||
|
||||
// SwitchLanguage handles UI request to switch between different languages and re-render template based on language.
|
||||
func (c *CommonController) SwitchLanguage() {
|
||||
lang := c.GetString("lang")
|
||||
if lang == "en-US" || lang == "zh-CN" {
|
||||
@ -67,6 +74,7 @@ func (c *CommonController) SwitchLanguage() {
|
||||
c.Redirect(c.Ctx.Request.Header.Get("Referer"), http.StatusFound)
|
||||
}
|
||||
|
||||
// Logout handles UI request to logout.
|
||||
func (c *CommonController) Logout() {
|
||||
c.DestroySession()
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
@ -28,13 +29,15 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// ChangePasswordController handles request to /changePassword
|
||||
type ChangePasswordController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the page for user to change password.
|
||||
func (cpc *ChangePasswordController) Get() {
|
||||
sessionUserId := cpc.GetSession("userId")
|
||||
if sessionUserId == nil {
|
||||
sessionUserID := cpc.GetSession("userId")
|
||||
if sessionUserID == nil {
|
||||
cpc.Redirect("/signIn", http.StatusFound)
|
||||
return
|
||||
}
|
||||
@ -42,148 +45,154 @@ func (cpc *ChangePasswordController) Get() {
|
||||
cpc.ForwardTo("page_title_change_password", "change-password")
|
||||
}
|
||||
|
||||
func (cpc *CommonController) UpdatePassword() {
|
||||
// UpdatePassword handles UI request to update user's password, it only works when the auth mode is db_auth.
|
||||
func (cc *CommonController) UpdatePassword() {
|
||||
|
||||
sessionUserId := cpc.GetSession("userId")
|
||||
sessionUserID := cc.GetSession("userId")
|
||||
|
||||
if sessionUserId == nil {
|
||||
if sessionUserID == nil {
|
||||
beego.Warning("User does not login.")
|
||||
cpc.CustomAbort(http.StatusUnauthorized, "please_login_first")
|
||||
cc.CustomAbort(http.StatusUnauthorized, "please_login_first")
|
||||
}
|
||||
|
||||
oldPassword := cpc.GetString("old_password")
|
||||
oldPassword := cc.GetString("old_password")
|
||||
if oldPassword == "" {
|
||||
beego.Error("Old password is blank")
|
||||
cpc.CustomAbort(http.StatusBadRequest, "Old password is blank")
|
||||
cc.CustomAbort(http.StatusBadRequest, "Old password is blank")
|
||||
}
|
||||
|
||||
queryUser := models.User{UserId: sessionUserId.(int), Password: oldPassword}
|
||||
queryUser := models.User{UserID: sessionUserID.(int), Password: oldPassword}
|
||||
user, err := dao.CheckUserPassword(queryUser)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in CheckUserPassword:", err)
|
||||
cpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
beego.Warning("Password input is not correct")
|
||||
cpc.CustomAbort(http.StatusForbidden, "old_password_is_not_correct")
|
||||
cc.CustomAbort(http.StatusForbidden, "old_password_is_not_correct")
|
||||
}
|
||||
|
||||
password := cpc.GetString("password")
|
||||
password := cc.GetString("password")
|
||||
if password != "" {
|
||||
updateUser := models.User{UserId: sessionUserId.(int), Password: password, Salt: user.Salt}
|
||||
updateUser := models.User{UserID: sessionUserID.(int), Password: password, Salt: user.Salt}
|
||||
err = dao.ChangeUserPassword(updateUser, oldPassword)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in ChangeUserPassword:", err)
|
||||
cpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
} else {
|
||||
cpc.CustomAbort(http.StatusBadRequest, "please_input_new_password")
|
||||
cc.CustomAbort(http.StatusBadRequest, "please_input_new_password")
|
||||
}
|
||||
}
|
||||
|
||||
// ForgotPasswordController handles request to /forgotPassword
|
||||
type ForgotPasswordController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
type MessageDetail struct {
|
||||
Hint string
|
||||
Url string
|
||||
Uuid string
|
||||
}
|
||||
|
||||
// Get Renders the page for user to input Email to reset password.
|
||||
func (fpc *ForgotPasswordController) Get() {
|
||||
fpc.ForwardTo("page_title_forgot_password", "forgot-password")
|
||||
}
|
||||
|
||||
func (fpc *CommonController) SendEmail() {
|
||||
type messageDetail struct {
|
||||
Hint string
|
||||
URL string
|
||||
UUID string
|
||||
}
|
||||
|
||||
email := fpc.GetString("email")
|
||||
// SendEmail verifies the Email address and contact SMTP server to send reset password Email.
|
||||
func (cc *CommonController) SendEmail() {
|
||||
|
||||
email := cc.GetString("email")
|
||||
|
||||
pass, _ := regexp.MatchString(`^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`, email)
|
||||
|
||||
if !pass {
|
||||
fpc.CustomAbort(http.StatusBadRequest, "email_content_illegal")
|
||||
cc.CustomAbort(http.StatusBadRequest, "email_content_illegal")
|
||||
} else {
|
||||
|
||||
queryUser := models.User{Email: email}
|
||||
exist, err := dao.UserExists(queryUser, "email")
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in UserExists:", err)
|
||||
fpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if !exist {
|
||||
fpc.CustomAbort(http.StatusNotFound, "email_does_not_exist")
|
||||
cc.CustomAbort(http.StatusNotFound, "email_does_not_exist")
|
||||
}
|
||||
|
||||
messageTemplate, err := template.ParseFiles("views/reset-password-mail.tpl")
|
||||
if err != nil {
|
||||
beego.Error("Parse email template file failed:", err)
|
||||
fpc.CustomAbort(http.StatusInternalServerError, err.Error())
|
||||
cc.CustomAbort(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
message := new(bytes.Buffer)
|
||||
|
||||
harborUrl := os.Getenv("HARBOR_URL")
|
||||
if harborUrl == "" {
|
||||
harborUrl = "localhost"
|
||||
harborURL := os.Getenv("HARBOR_URL")
|
||||
if harborURL == "" {
|
||||
harborURL = "localhost"
|
||||
}
|
||||
uuid, err := dao.GenerateRandomString()
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GenerateRandomString:", err)
|
||||
fpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
err = messageTemplate.Execute(message, MessageDetail{
|
||||
Hint: fpc.Tr("reset_email_hint"),
|
||||
Url: harborUrl,
|
||||
Uuid: uuid,
|
||||
err = messageTemplate.Execute(message, messageDetail{
|
||||
Hint: cc.Tr("reset_email_hint"),
|
||||
URL: harborURL,
|
||||
UUID: uuid,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
beego.Error("message template error:", err)
|
||||
fpc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
config, err := beego.AppConfig.GetSection("mail")
|
||||
if err != nil {
|
||||
beego.Error("Can not load app.conf:", err)
|
||||
fpc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
mail := utils.Mail{
|
||||
From: config["from"],
|
||||
To: []string{email},
|
||||
Subject: fpc.Tr("reset_email_subject"),
|
||||
Subject: cc.Tr("reset_email_subject"),
|
||||
Message: message.String()}
|
||||
|
||||
err = mail.SendMail()
|
||||
|
||||
if err != nil {
|
||||
beego.Error("send email failed:", err)
|
||||
fpc.CustomAbort(http.StatusInternalServerError, "send_email_failed")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "send_email_failed")
|
||||
}
|
||||
|
||||
user := models.User{ResetUuid: uuid, Email: email}
|
||||
dao.UpdateUserResetUuid(user)
|
||||
user := models.User{ResetUUID: uuid, Email: email}
|
||||
dao.UpdateUserResetUUID(user)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ResetPasswordController handles request to /resetPassword
|
||||
type ResetPasswordController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get checks if reset_uuid in the reset link is valid and render the result page for user to reset password.
|
||||
func (rpc *ResetPasswordController) Get() {
|
||||
|
||||
resetUuid := rpc.GetString("reset_uuid")
|
||||
if resetUuid == "" {
|
||||
resetUUID := rpc.GetString("reset_uuid")
|
||||
if resetUUID == "" {
|
||||
beego.Error("Reset uuid is blank.")
|
||||
rpc.Redirect("/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
queryUser := models.User{ResetUuid: resetUuid}
|
||||
queryUser := models.User{ResetUUID: resetUUID}
|
||||
user, err := dao.GetUser(queryUser)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
@ -191,41 +200,42 @@ func (rpc *ResetPasswordController) Get() {
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
rpc.Data["ResetUuid"] = user.ResetUuid
|
||||
rpc.Data["ResetUuid"] = user.ResetUUID
|
||||
rpc.ForwardTo("page_title_reset_password", "reset-password")
|
||||
} else {
|
||||
rpc.Redirect("/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func (rpc *CommonController) ResetPassword() {
|
||||
// ResetPassword handles request from the reset page and reset password
|
||||
func (cc *CommonController) ResetPassword() {
|
||||
|
||||
resetUuid := rpc.GetString("reset_uuid")
|
||||
if resetUuid == "" {
|
||||
rpc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.")
|
||||
resetUUID := cc.GetString("reset_uuid")
|
||||
if resetUUID == "" {
|
||||
cc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.")
|
||||
}
|
||||
|
||||
queryUser := models.User{ResetUuid: resetUuid}
|
||||
queryUser := models.User{ResetUUID: resetUUID}
|
||||
user, err := dao.GetUser(queryUser)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in GetUser:", err)
|
||||
rpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if user == nil {
|
||||
beego.Error("User does not exist")
|
||||
rpc.CustomAbort(http.StatusBadRequest, "User does not exist")
|
||||
cc.CustomAbort(http.StatusBadRequest, "User does not exist")
|
||||
}
|
||||
|
||||
password := rpc.GetString("password")
|
||||
password := cc.GetString("password")
|
||||
|
||||
if password != "" {
|
||||
user.Password = password
|
||||
err = dao.ResetUserPassword(*user)
|
||||
if err != nil {
|
||||
beego.Error("Error occurred in ResetUserPassword:", err)
|
||||
rpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
} else {
|
||||
rpc.CustomAbort(http.StatusBadRequest, "password_is_required")
|
||||
cc.CustomAbort(http.StatusBadRequest, "password_is_required")
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 controllers
|
||||
|
||||
// ProjectController handles request to /registry/project
|
||||
type ProjectController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders project page.
|
||||
func (p *ProjectController) Get() {
|
||||
p.Data["Username"] = p.GetSession("username")
|
||||
p.ForwardTo("page_title_project", "project")
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
@ -25,10 +26,12 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// RegisterController handles request to /register
|
||||
type RegisterController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the Sign In page, it only works if the auth mode is set to db_auth
|
||||
func (rc *RegisterController) Get() {
|
||||
authMode := os.Getenv("AUTH_MODE")
|
||||
if authMode == "" || authMode == "db_auth" {
|
||||
@ -38,6 +41,7 @@ func (rc *RegisterController) Get() {
|
||||
}
|
||||
}
|
||||
|
||||
// SignUp insert data into DB based on data in form.
|
||||
func (rc *CommonController) SignUp() {
|
||||
username := strings.TrimSpace(rc.GetString("username"))
|
||||
email := strings.TrimSpace(rc.GetString("email"))
|
||||
@ -54,6 +58,7 @@ func (rc *CommonController) SignUp() {
|
||||
}
|
||||
}
|
||||
|
||||
// UserExists checks if user exists when user input value in sign in form.
|
||||
func (rc *CommonController) UserExists() {
|
||||
target := rc.GetString("target")
|
||||
value := rc.GetString("value")
|
||||
|
@ -1,23 +1,26 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 controllers
|
||||
|
||||
// SearchController handles request to /search
|
||||
type SearchController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders page for displaying search result.
|
||||
func (sc *SearchController) Get() {
|
||||
sc.Data["Username"] = sc.GetSession("username")
|
||||
sc.Data["QueryParam"] = sc.GetString("q")
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -22,6 +23,7 @@ import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// AddAccessLog persists the access logs
|
||||
func AddAccessLog(accessLog models.AccessLog) error {
|
||||
o := orm.NewOrm()
|
||||
p, err := o.Raw(`insert into access_log
|
||||
@ -32,11 +34,12 @@ func AddAccessLog(accessLog models.AccessLog) error {
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
_, err = p.Exec(accessLog.UserId, accessLog.ProjectId, accessLog.RepoName, accessLog.Guid, accessLog.Operation)
|
||||
_, err = p.Exec(accessLog.UserID, accessLog.ProjectID, accessLog.RepoName, accessLog.GUID, accessLog.Operation)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
//GetAccessLogs gets access logs according to different conditions
|
||||
func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) {
|
||||
|
||||
o := orm.NewOrm()
|
||||
@ -44,11 +47,11 @@ func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) {
|
||||
from access_log a left join user u on a.user_id = u.user_id
|
||||
where a.project_id = ? `
|
||||
queryParam := make([]interface{}, 1)
|
||||
queryParam = append(queryParam, accessLog.ProjectId)
|
||||
queryParam = append(queryParam, accessLog.ProjectID)
|
||||
|
||||
if accessLog.UserId != 0 {
|
||||
if accessLog.UserID != 0 {
|
||||
sql += ` and a.user_id = ? `
|
||||
queryParam = append(queryParam, accessLog.UserId)
|
||||
queryParam = append(queryParam, accessLog.UserID)
|
||||
}
|
||||
if accessLog.Operation != "" {
|
||||
sql += ` and a.operation = ? `
|
||||
@ -92,6 +95,7 @@ func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) {
|
||||
return accessLogList, nil
|
||||
}
|
||||
|
||||
// AccessLog ...
|
||||
func AccessLog(username, projectName, repoName, action string) error {
|
||||
o := orm.NewOrm()
|
||||
sql := "insert into access_log (user_id, project_id, repo_name, operation, op_time) " +
|
||||
|
32
dao/base.go
32
dao/base.go
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -22,12 +23,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/orm"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/go-sql-driver/mysql" //register mysql driver
|
||||
)
|
||||
|
||||
const NON_EXIST_USER_ID = 0
|
||||
// NonExistUserID : if a user does not exist, the ID of the user will be 0.
|
||||
const NonExistUserID = 0
|
||||
|
||||
func isIllegalLength(s string, min int, max int) bool {
|
||||
if min == -1 {
|
||||
@ -48,6 +49,7 @@ func isContainIllegalChar(s string, illegalChar []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GenerateRandomString generates a random string
|
||||
func GenerateRandomString() (string, error) {
|
||||
o := orm.NewOrm()
|
||||
var uuid string
|
||||
@ -59,6 +61,7 @@ func GenerateRandomString() (string, error) {
|
||||
|
||||
}
|
||||
|
||||
//InitDB initializes the database
|
||||
func InitDB() {
|
||||
orm.RegisterDriver("mysql", orm.DRMySQL)
|
||||
addr := os.Getenv("MYSQL_HOST")
|
||||
@ -74,26 +77,7 @@ func InitDB() {
|
||||
password = os.Getenv("MYSQL_PWD")
|
||||
}
|
||||
|
||||
var flag bool = true
|
||||
if addr == "" {
|
||||
beego.Error("Unset env of MYSQL_HOST")
|
||||
flag = false
|
||||
} else if port == "" {
|
||||
beego.Error("Unset env of MYSQL_PORT_3306_TCP_PORT")
|
||||
flag = false
|
||||
} else if username == "" {
|
||||
beego.Error("Unset env of MYSQL_USR")
|
||||
flag = false
|
||||
} else if password == "" {
|
||||
beego.Error("Unset env of MYSQL_PWD")
|
||||
flag = false
|
||||
}
|
||||
|
||||
if !flag {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
db_str := username + ":" + password + "@tcp(" + addr + ":" + port + ")/registry"
|
||||
dbStr := username + ":" + password + "@tcp(" + addr + ":" + port + ")/registry"
|
||||
ch := make(chan int, 1)
|
||||
go func() {
|
||||
var err error
|
||||
@ -114,7 +98,7 @@ func InitDB() {
|
||||
case <-time.After(60 * time.Second):
|
||||
panic("Failed to connect to DB after 60 seconds")
|
||||
}
|
||||
err := orm.RegisterDataBase("default", "mysql", db_str)
|
||||
err := orm.RegisterDataBase("default", "mysql", dbStr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
201
dao/dao_test.go
201
dao/dao_test.go
@ -12,11 +12,11 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
// "fmt"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
@ -83,15 +83,15 @@ func clearUp(username string) {
|
||||
o.Commit()
|
||||
}
|
||||
|
||||
const USERNAME string = "Tester01"
|
||||
const PROJECT_NAME string = "test_project"
|
||||
const SYS_ADMIN int = 1
|
||||
const PROJECT_ADMIN int = 2
|
||||
const DEVELOPER int = 3
|
||||
const GUEST int = 4
|
||||
const username string = "Tester01"
|
||||
const projectName string = "test_project"
|
||||
const SysAdmin int = 1
|
||||
const projectAdmin int = 2
|
||||
const developer int = 3
|
||||
const guest int = 4
|
||||
|
||||
const PUBLICITY_ON = 1
|
||||
const PUBLICITY_OFF = 0
|
||||
const publicityOn = 1
|
||||
const publicityOff = 0
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
@ -108,9 +108,6 @@ func TestMain(m *testing.M) {
|
||||
log.Fatalf("environment variable DB_PORT is not set")
|
||||
}
|
||||
dbPassword := os.Getenv("DB_PWD")
|
||||
if len(dbPassword) == 0 {
|
||||
log.Fatalf("environment variable DB_PWD is not set")
|
||||
}
|
||||
|
||||
fmt.Printf("DB_HOST: %s, DB_USR: %s, DB_PORT: %s, DB_PWD: %s\n", dbHost, dbUser, dbPort, dbPassword)
|
||||
|
||||
@ -120,7 +117,7 @@ func TestMain(m *testing.M) {
|
||||
os.Setenv("MYSQL_PWD", dbPassword)
|
||||
os.Setenv("AUTH_MODE", "db_auth")
|
||||
InitDB()
|
||||
clearUp(USERNAME)
|
||||
clearUp(username)
|
||||
os.Exit(m.Run())
|
||||
|
||||
}
|
||||
@ -128,7 +125,7 @@ func TestMain(m *testing.M) {
|
||||
func TestRegister(t *testing.T) {
|
||||
|
||||
user := models.User{
|
||||
Username: USERNAME,
|
||||
Username: username,
|
||||
Email: "tester01@vmware.com",
|
||||
Password: "Abc12345",
|
||||
Realname: "tester01",
|
||||
@ -142,15 +139,15 @@ func TestRegister(t *testing.T) {
|
||||
|
||||
//Check if user registered successfully.
|
||||
queryUser := models.User{
|
||||
Username: USERNAME,
|
||||
Username: username,
|
||||
}
|
||||
newUser, err := GetUser(queryUser)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetUser: %v", err)
|
||||
}
|
||||
|
||||
if newUser.Username != USERNAME {
|
||||
t.Errorf("Username does not match, expected: %s, actual: %s", USERNAME, newUser.Username)
|
||||
if newUser.Username != username {
|
||||
t.Errorf("Username does not match, expected: %s, actual: %s", username, newUser.Username)
|
||||
}
|
||||
if newUser.Email != "tester01@vmware.com" {
|
||||
t.Errorf("Email does not match, expected: %s, actual: %s", "tester01@vmware.com", newUser.Email)
|
||||
@ -161,12 +158,12 @@ func TestUserExists(t *testing.T) {
|
||||
var exists bool
|
||||
var err error
|
||||
|
||||
exists, err = UserExists(models.User{Username: USERNAME}, "username")
|
||||
exists, err = UserExists(models.User{Username: username}, "username")
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in UserExists: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("User %s was inserted but does not exist", USERNAME)
|
||||
t.Errorf("User %s was inserted but does not exist", username)
|
||||
}
|
||||
exists, err = UserExists(models.User{Email: "tester01@vmware.com"}, "email")
|
||||
|
||||
@ -188,7 +185,7 @@ func TestUserExists(t *testing.T) {
|
||||
func TestLoginByUserName(t *testing.T) {
|
||||
|
||||
userQuery := models.User{
|
||||
Username: USERNAME,
|
||||
Username: username,
|
||||
Password: "Abc12345",
|
||||
}
|
||||
|
||||
@ -200,8 +197,8 @@ func TestLoginByUserName(t *testing.T) {
|
||||
t.Errorf("No found for user logined by username and password: %v", userQuery)
|
||||
}
|
||||
|
||||
if loginUser.Username != USERNAME {
|
||||
t.Errorf("User's username does not match after login, expected: %s, actual: %s", USERNAME, loginUser.Username)
|
||||
if loginUser.Username != username {
|
||||
t.Errorf("User's username does not match after login, expected: %s, actual: %s", username, loginUser.Username)
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,8 +216,8 @@ func TestLoginByEmail(t *testing.T) {
|
||||
if loginUser == nil {
|
||||
t.Errorf("No found for user logined by email and password : %v", userQuery)
|
||||
}
|
||||
if loginUser.Username != USERNAME {
|
||||
t.Errorf("User's username does not match after login, expected: %s, actual: %s", USERNAME, loginUser.Username)
|
||||
if loginUser.Username != username {
|
||||
t.Errorf("User's username does not match after login, expected: %s, actual: %s", username, loginUser.Username)
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +225,7 @@ var currentUser *models.User
|
||||
|
||||
func TestGetUser(t *testing.T) {
|
||||
queryUser := models.User{
|
||||
Username: USERNAME,
|
||||
Username: username,
|
||||
}
|
||||
var err error
|
||||
currentUser, err = GetUser(queryUser)
|
||||
@ -251,12 +248,12 @@ func TestListUsers(t *testing.T) {
|
||||
if len(users) != 1 {
|
||||
t.Errorf("Expect one user in list, but the acutal length is %d, the list: %+v", len(users), users)
|
||||
}
|
||||
users2, err := ListUsers(models.User{Username: USERNAME})
|
||||
users2, err := ListUsers(models.User{Username: username})
|
||||
if len(users2) != 1 {
|
||||
t.Errorf("Expect one user in list, but the acutal length is %d, the list: %+v", len(users), users)
|
||||
}
|
||||
if users2[0].Username != USERNAME {
|
||||
t.Errorf("The username in result list does not match, expected: %s, actual: %s", USERNAME, users2[0].Username)
|
||||
if users2[0].Username != username {
|
||||
t.Errorf("The username in result list does not match, expected: %s, actual: %s", username, users2[0].Username)
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,12 +263,12 @@ func TestResetUserPassword(t *testing.T) {
|
||||
t.Errorf("Error occurred in GenerateRandomString: %v", err)
|
||||
}
|
||||
|
||||
err = UpdateUserResetUuid(models.User{ResetUuid: uuid, Email: currentUser.Email})
|
||||
err = UpdateUserResetUUID(models.User{ResetUUID: uuid, Email: currentUser.Email})
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in UpdateUserResetUuid: %v", err)
|
||||
}
|
||||
|
||||
err = ResetUserPassword(models.User{UserId: currentUser.UserId, Password: "HarborTester12345", ResetUuid: uuid, Salt: currentUser.Salt})
|
||||
err = ResetUserPassword(models.User{UserID: currentUser.UserID, Password: "HarborTester12345", ResetUUID: uuid, Salt: currentUser.Salt})
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in ResetUserPassword: %v", err)
|
||||
}
|
||||
@ -281,13 +278,13 @@ func TestResetUserPassword(t *testing.T) {
|
||||
t.Errorf("Error occurred in LoginByDb: %v", err)
|
||||
}
|
||||
|
||||
if loginedUser.Username != USERNAME {
|
||||
t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", USERNAME, loginedUser.Username)
|
||||
if loginedUser.Username != username {
|
||||
t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", username, loginedUser.Username)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeUserPassword(t *testing.T) {
|
||||
err := ChangeUserPassword(models.User{UserId: currentUser.UserId, Password: "NewHarborTester12345", Salt: currentUser.Salt})
|
||||
err := ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NewHarborTester12345", Salt: currentUser.Salt})
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in ChangeUserPassword: %v", err)
|
||||
}
|
||||
@ -297,13 +294,13 @@ func TestChangeUserPassword(t *testing.T) {
|
||||
t.Errorf("Error occurred in LoginByDb: %v", err)
|
||||
}
|
||||
|
||||
if loginedUser.Username != USERNAME {
|
||||
t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", USERNAME, loginedUser.Username)
|
||||
if loginedUser.Username != username {
|
||||
t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", username, loginedUser.Username)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeUserPasswordWithOldPassword(t *testing.T) {
|
||||
err := ChangeUserPassword(models.User{UserId: currentUser.UserId, Password: "NewerHarborTester12345", Salt: currentUser.Salt}, "NewHarborTester12345")
|
||||
err := ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NewerHarborTester12345", Salt: currentUser.Salt}, "NewHarborTester12345")
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in ChangeUserPassword: %v", err)
|
||||
}
|
||||
@ -311,13 +308,13 @@ func TestChangeUserPasswordWithOldPassword(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in LoginByDb: %v", err)
|
||||
}
|
||||
if loginedUser.Username != USERNAME {
|
||||
t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", USERNAME, loginedUser.Username)
|
||||
if loginedUser.Username != username {
|
||||
t.Errorf("The username returned by Login does not match, expected: %s, acutal: %s", username, loginedUser.Username)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) {
|
||||
err := ChangeUserPassword(models.User{UserId: currentUser.UserId, Password: "NNewerHarborTester12345", Salt: currentUser.Salt}, "WrongNewerHarborTester12345")
|
||||
err := ChangeUserPassword(models.User{UserID: currentUser.UserID, Password: "NNewerHarborTester12345", Salt: currentUser.Salt}, "WrongNewerHarborTester12345")
|
||||
if err == nil {
|
||||
t.Errorf("Error does not occurred due to old password is incorrect.")
|
||||
}
|
||||
@ -331,7 +328,7 @@ func TestChangeUserPasswordWithIncorrectOldPassword(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) {
|
||||
projects, err := QueryRelevantProjects(currentUser.UserId)
|
||||
projects, err := QueryRelevantProjects(currentUser.UserID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in QueryRelevantProjects: %v", err)
|
||||
}
|
||||
@ -346,8 +343,8 @@ func TestQueryRelevantProjectsWhenNoProjectAdded(t *testing.T) {
|
||||
func TestAddProject(t *testing.T) {
|
||||
|
||||
project := models.Project{
|
||||
OwnerId: currentUser.UserId,
|
||||
Name: PROJECT_NAME,
|
||||
OwnerID: currentUser.UserID,
|
||||
Name: projectName,
|
||||
CreationTime: time.Now(),
|
||||
OwnerName: currentUser.Username,
|
||||
}
|
||||
@ -357,12 +354,12 @@ func TestAddProject(t *testing.T) {
|
||||
t.Errorf("Error occurred in AddProject: %v", err)
|
||||
}
|
||||
|
||||
newProject, err := GetProjectByName(PROJECT_NAME)
|
||||
newProject, err := GetProjectByName(projectName)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetProjectByName: %v", err)
|
||||
}
|
||||
if newProject == nil {
|
||||
t.Errorf("No project found queried by project name: %v", PROJECT_NAME)
|
||||
t.Errorf("No project found queried by project name: %v", projectName)
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,25 +367,25 @@ var currentProject *models.Project
|
||||
|
||||
func TestGetProject(t *testing.T) {
|
||||
var err error
|
||||
currentProject, err = GetProjectByName(PROJECT_NAME)
|
||||
currentProject, err = GetProjectByName(projectName)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetProjectByName: %v", err)
|
||||
}
|
||||
if currentProject == nil {
|
||||
t.Errorf("No project found queried by project name: %v", PROJECT_NAME)
|
||||
t.Errorf("No project found queried by project name: %v", projectName)
|
||||
}
|
||||
if currentProject.Name != PROJECT_NAME {
|
||||
t.Errorf("Project name does not match, expected: %s, actual: %s", PROJECT_NAME, currentProject.Name)
|
||||
if currentProject.Name != projectName {
|
||||
t.Errorf("Project name does not match, expected: %s, actual: %s", projectName, currentProject.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func getProjectRole(projectId int64) []models.Role {
|
||||
func getProjectRole(projectID int64) []models.Role {
|
||||
o := orm.NewOrm()
|
||||
var r []models.Role
|
||||
_, err := o.Raw(`select r.role_id, r.name
|
||||
from project_role pr
|
||||
left join role r on pr.role_id = r.role_id
|
||||
where project_id = ?`, projectId).QueryRows(&r)
|
||||
where project_id = ?`, projectID).QueryRows(&r)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in querying project_role: %v", err)
|
||||
}
|
||||
@ -396,12 +393,12 @@ func getProjectRole(projectId int64) []models.Role {
|
||||
}
|
||||
|
||||
func TestCheckProjectRoles(t *testing.T) {
|
||||
r := getProjectRole(currentProject.ProjectId)
|
||||
r := getProjectRole(currentProject.ProjectID)
|
||||
if len(r) != 3 {
|
||||
t.Errorf("The length of project roles is not 3")
|
||||
}
|
||||
if r[1].RoleId != 3 {
|
||||
t.Errorf("The role id does not match, expected: 3, acutal: %d", r[1].RoleId)
|
||||
if r[1].RoleID != 3 {
|
||||
t.Errorf("The role id does not match, expected: 3, acutal: %d", r[1].RoleID)
|
||||
}
|
||||
if r[1].Name != "developer" {
|
||||
t.Errorf("The name of role id: 3 should be developer, actual:%s", r[1].Name)
|
||||
@ -410,8 +407,8 @@ func TestCheckProjectRoles(t *testing.T) {
|
||||
|
||||
func TestGetAccessLog(t *testing.T) {
|
||||
queryAccessLog := models.AccessLog{
|
||||
UserId: currentUser.UserId,
|
||||
ProjectId: currentProject.ProjectId,
|
||||
UserID: currentUser.UserID,
|
||||
ProjectID: currentProject.ProjectID,
|
||||
}
|
||||
accessLogs, err := GetAccessLogs(queryAccessLog)
|
||||
if err != nil {
|
||||
@ -420,20 +417,20 @@ func TestGetAccessLog(t *testing.T) {
|
||||
if len(accessLogs) != 1 {
|
||||
t.Errorf("The length of accesslog list should be 1, actual: %d", len(accessLogs))
|
||||
}
|
||||
if accessLogs[0].RepoName != PROJECT_NAME+"/" {
|
||||
t.Errorf("The project name does not match, expected: %s, actual: %s", PROJECT_NAME+"/", accessLogs[0].RepoName)
|
||||
if accessLogs[0].RepoName != projectName+"/" {
|
||||
t.Errorf("The project name does not match, expected: %s, actual: %s", projectName+"/", accessLogs[0].RepoName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectExists(t *testing.T) {
|
||||
var exists bool
|
||||
var err error
|
||||
exists, err = ProjectExists(currentProject.ProjectId)
|
||||
exists, err = ProjectExists(currentProject.ProjectID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in ProjectExists: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
t.Errorf("The project with id: %d, does not exist", currentProject.ProjectId)
|
||||
t.Errorf("The project with id: %d, does not exist", currentProject.ProjectID)
|
||||
}
|
||||
exists, err = ProjectExists(currentProject.Name)
|
||||
if err != nil {
|
||||
@ -445,8 +442,8 @@ func TestProjectExists(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetProjectById(t *testing.T) {
|
||||
id := currentProject.ProjectId
|
||||
p, err := GetProjectById(id)
|
||||
id := currentProject.ProjectID
|
||||
p, err := GetProjectByID(id)
|
||||
if err != nil {
|
||||
t.Errorf("Error in GetProjectById: %v, id: %d", err, id)
|
||||
}
|
||||
@ -456,7 +453,7 @@ func TestGetProjectById(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetUserByProject(t *testing.T) {
|
||||
pid := currentProject.ProjectId
|
||||
pid := currentProject.ProjectID
|
||||
u1 := models.User{
|
||||
Username: "%%Tester%%",
|
||||
}
|
||||
@ -465,14 +462,14 @@ func TestGetUserByProject(t *testing.T) {
|
||||
}
|
||||
users, err := GetUserByProject(pid, u1)
|
||||
if err != nil {
|
||||
t.Errorf("Error happened in GetUserByProject: %v, project Id: %d, user: %+v", u1)
|
||||
t.Errorf("Error happened in GetUserByProject: %v, project Id: %d, user: %+v", err, pid, u1)
|
||||
}
|
||||
if len(users) != 1 {
|
||||
t.Errorf("unexpected length of user list, expected: 1, the users list: %+v", users)
|
||||
}
|
||||
users, err = GetUserByProject(pid, u2)
|
||||
if err != nil {
|
||||
t.Errorf("Error happened in GetUserByProject: %v, project Id: %d, user: %+v", u2)
|
||||
t.Errorf("Error happened in GetUserByProject: %v, project Id: %d, user: %+v", err, pid, u2)
|
||||
}
|
||||
if len(users) != 0 {
|
||||
t.Errorf("unexpected length of user list, expected: 0, the users list: %+v", users)
|
||||
@ -481,44 +478,44 @@ func TestGetUserByProject(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestToggleProjectPublicity(t *testing.T) {
|
||||
err := ToggleProjectPublicity(currentProject.ProjectId, PUBLICITY_ON)
|
||||
err := ToggleProjectPublicity(currentProject.ProjectID, publicityOn)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in ToggleProjectPublicity: %v", err)
|
||||
}
|
||||
|
||||
currentProject, err = GetProjectByName(PROJECT_NAME)
|
||||
currentProject, err = GetProjectByName(projectName)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetProjectByName: %v", err)
|
||||
}
|
||||
if currentProject.Public != PUBLICITY_ON {
|
||||
t.Errorf("project, id: %d, its publicity is not on", currentProject.ProjectId)
|
||||
if currentProject.Public != publicityOn {
|
||||
t.Errorf("project, id: %d, its publicity is not on", currentProject.ProjectID)
|
||||
}
|
||||
err = ToggleProjectPublicity(currentProject.ProjectId, PUBLICITY_OFF)
|
||||
err = ToggleProjectPublicity(currentProject.ProjectID, publicityOff)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in ToggleProjectPublicity: %v", err)
|
||||
}
|
||||
|
||||
currentProject, err = GetProjectByName(PROJECT_NAME)
|
||||
currentProject, err = GetProjectByName(projectName)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetProjectByName: %v", err)
|
||||
}
|
||||
|
||||
if currentProject.Public != PUBLICITY_OFF {
|
||||
t.Errorf("project, id: %d, its publicity is not off", currentProject.ProjectId)
|
||||
if currentProject.Public != publicityOff {
|
||||
t.Errorf("project, id: %d, its publicity is not off", currentProject.ProjectID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestIsProjectPublic(t *testing.T) {
|
||||
|
||||
if isPublic := IsProjectPublic(PROJECT_NAME); isPublic {
|
||||
t.Errorf("project, id: %d, its publicity is not false after turning off", currentProject.ProjectId)
|
||||
if isPublic := IsProjectPublic(projectName); isPublic {
|
||||
t.Errorf("project, id: %d, its publicity is not false after turning off", currentProject.ProjectID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryProject(t *testing.T) {
|
||||
query1 := models.Project{
|
||||
UserId: 1,
|
||||
UserID: 1,
|
||||
}
|
||||
projects, err := QueryProject(query1)
|
||||
if err != nil {
|
||||
@ -538,7 +535,7 @@ func TestQueryProject(t *testing.T) {
|
||||
t.Errorf("Expecting get 1 project, but actual: %d, the list: %+v", len(projects), projects)
|
||||
}
|
||||
query3 := models.Project{
|
||||
UserId: 9,
|
||||
UserID: 9,
|
||||
}
|
||||
projects, err = QueryProject(query3)
|
||||
if err != nil {
|
||||
@ -549,14 +546,14 @@ func TestQueryProject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getUserProjectRole(projectId int64, userId int) []models.Role {
|
||||
func getUserProjectRole(projectID int64, userID int) []models.Role {
|
||||
o := orm.NewOrm()
|
||||
var r []models.Role
|
||||
_, err := o.Raw(`select r.role_id, r.name
|
||||
from user_project_role upr
|
||||
left join project_role pr on upr.pr_id = pr.pr_id
|
||||
left join role r on r.role_id = pr.role_id
|
||||
where pr.project_id = ? and upr.user_id = ?`, projectId, userId).QueryRows(&r)
|
||||
where pr.project_id = ? and upr.user_id = ?`, projectID, userID).QueryRows(&r)
|
||||
if err != nil {
|
||||
log.Fatalf("Error occurred in querying user_project_role: %v", err)
|
||||
}
|
||||
@ -565,28 +562,28 @@ func getUserProjectRole(projectId int64, userId int) []models.Role {
|
||||
|
||||
func TestGetUserProjectRoles(t *testing.T) {
|
||||
user := *currentUser
|
||||
r, err := GetUserProjectRoles(user, currentProject.ProjectId)
|
||||
r, err := GetUserProjectRoles(user, currentProject.ProjectID)
|
||||
if err != nil {
|
||||
t.Errorf("Error happened in GetUserProjectRole: %v, user: %+v, project Id: %d", err, user, currentProject.ProjectId)
|
||||
t.Errorf("Error happened in GetUserProjectRole: %v, user: %+v, project Id: %d", err, user, 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))
|
||||
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)
|
||||
}
|
||||
user.RoleId = 1
|
||||
user.RoleID = 1
|
||||
|
||||
r, err = GetUserProjectRoles(user, currentProject.ProjectId)
|
||||
r, err = GetUserProjectRoles(user, currentProject.ProjectID)
|
||||
if err != nil {
|
||||
t.Errorf("Error happened in GetUserProjectRole: %v, user: %+v, project Id: %d", err, user, currentProject.ProjectId)
|
||||
t.Errorf("Error happened in GetUserProjectRole: %v, user: %+v, project Id: %d", err, user, currentProject.ProjectID)
|
||||
}
|
||||
//Get the size of current user project role.
|
||||
if len(r) != 0 {
|
||||
t.Errorf("The user, id: %d, should not have role id: 1 in project id: %d, actual role list: %v", currentUser.UserId, currentProject.ProjectId, r)
|
||||
t.Errorf("The user, id: %d, should not have role id: 1 in project id: %d, actual role list: %v", currentUser.UserID, currentProject.ProjectID, r)
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,43 +598,43 @@ func TestProjectPermission(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQueryRelevantProjects(t *testing.T) {
|
||||
projects, err := QueryRelevantProjects(currentUser.UserId)
|
||||
projects, err := QueryRelevantProjects(currentUser.UserID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in QueryRelevantProjects: %v", err)
|
||||
}
|
||||
if len(projects) != 2 {
|
||||
t.Errorf("Expected length of relevant projects is 2, but actual: %d, the projects: %+v", len(projects), projects)
|
||||
}
|
||||
if projects[1].Name != PROJECT_NAME {
|
||||
t.Errorf("Expected project name in the list: %s, actual: %s", PROJECT_NAME, projects[1].Name)
|
||||
if projects[1].Name != projectName {
|
||||
t.Errorf("Expected project name in the list: %s, actual: %s", projectName, projects[1].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssignUserProjectRole(t *testing.T) {
|
||||
err := AddUserProjectRole(currentUser.UserId, currentProject.ProjectId, DEVELOPER)
|
||||
err := AddUserProjectRole(currentUser.UserID, currentProject.ProjectID, developer)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in AddUserProjectRole: %v", err)
|
||||
}
|
||||
|
||||
r := getUserProjectRole(currentProject.ProjectId, currentUser.UserId)
|
||||
r := getUserProjectRole(currentProject.ProjectID, currentUser.UserID)
|
||||
|
||||
//Get the size of current user project role info.
|
||||
if len(r) != 2 {
|
||||
t.Errorf("Expected length of role list is 2, actual: %d", len(r))
|
||||
}
|
||||
|
||||
if r[1].RoleId != 3 {
|
||||
t.Errorf("Expected role id of the second role in list is 3, actual: %d", r[1].RoleId)
|
||||
if r[1].RoleID != 3 {
|
||||
t.Errorf("Expected role id of the second role in list is 3, actual: %d", r[1].RoleID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteUserProjectRole(t *testing.T) {
|
||||
err := DeleteUserProjectRoles(currentUser.UserId, currentProject.ProjectId)
|
||||
err := DeleteUserProjectRoles(currentUser.UserID, currentProject.ProjectID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in DeleteUserProjectRoles: %v", err)
|
||||
}
|
||||
|
||||
r := getUserProjectRole(currentProject.ProjectId, currentUser.UserId)
|
||||
r := getUserProjectRole(currentProject.ProjectID, currentUser.UserID)
|
||||
//Get the size of current user project role.
|
||||
if len(r) != 0 {
|
||||
t.Errorf("Expected role list length is 0, actual: %d, role list: %+v", len(r), r)
|
||||
@ -649,28 +646,28 @@ func TestToggleAdminRole(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Error in toggle ToggleUserAdmin role: %v, user: %+v", err, currentUser)
|
||||
}
|
||||
isAdmin, err := IsAdminRole(currentUser.UserId)
|
||||
isAdmin, err := IsAdminRole(currentUser.UserID)
|
||||
if err != nil {
|
||||
t.Errorf("Error in IsAdminRole: %v, user id: %d", err, currentUser.UserId)
|
||||
t.Errorf("Error in IsAdminRole: %v, user id: %d", err, currentUser.UserID)
|
||||
}
|
||||
if !isAdmin {
|
||||
t.Errorf("User is not admin after toggled, user id: %d", currentUser.UserId)
|
||||
t.Errorf("User is not admin after toggled, user id: %d", currentUser.UserID)
|
||||
}
|
||||
err = ToggleUserAdminRole(*currentUser)
|
||||
if err != nil {
|
||||
t.Errorf("Error in toggle ToggleUserAdmin role: %v, user: %+v", err, currentUser)
|
||||
}
|
||||
isAdmin, err = IsAdminRole(currentUser.UserId)
|
||||
isAdmin, err = IsAdminRole(currentUser.UserID)
|
||||
if err != nil {
|
||||
t.Errorf("Error in IsAdminRole: %v, user id: %d", err, currentUser.UserId)
|
||||
t.Errorf("Error in IsAdminRole: %v, user id: %d", err, currentUser.UserID)
|
||||
}
|
||||
if isAdmin {
|
||||
t.Errorf("User is still admin after toggled, user id: %d", currentUser.UserId)
|
||||
t.Errorf("User is still admin after toggled, user id: %d", currentUser.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteUser(t *testing.T) {
|
||||
err := DeleteUser(currentUser.UserId)
|
||||
err := DeleteUser(currentUser.UserID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in DeleteUser: %v", err)
|
||||
}
|
||||
@ -679,6 +676,6 @@ func TestDeleteUser(t *testing.T) {
|
||||
t.Errorf("Error occurred in GetUser: %v", err)
|
||||
}
|
||||
if user != nil {
|
||||
t.Error("user is not nil after deletion, user: %+v", user)
|
||||
t.Errorf("user is not nil after deletion, user: %+v", user)
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -20,7 +21,8 @@ import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
func GetUserByProject(projectId int64, queryUser models.User) ([]models.User, error) {
|
||||
// GetUserByProject gets all members of the project.
|
||||
func GetUserByProject(projectID int64, queryUser models.User) ([]models.User, error) {
|
||||
o := orm.NewOrm()
|
||||
u := []models.User{}
|
||||
sql := `select
|
||||
@ -35,7 +37,7 @@ func GetUserByProject(projectId int64, queryUser models.User) ([]models.User, er
|
||||
and pr.project_id = ? `
|
||||
|
||||
queryParam := make([]interface{}, 1)
|
||||
queryParam = append(queryParam, projectId)
|
||||
queryParam = append(queryParam, projectID)
|
||||
|
||||
if queryUser.Username != "" {
|
||||
sql += " and u.username like ? "
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -26,6 +27,8 @@ import (
|
||||
)
|
||||
|
||||
//TODO:transaction, return err
|
||||
|
||||
// AddProject adds a project to the database along with project roles information and access log records.
|
||||
func AddProject(project models.Project) error {
|
||||
|
||||
if isIllegalLength(project.Name, 4, 30) {
|
||||
@ -42,46 +45,47 @@ func AddProject(project models.Project) error {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := p.Exec(project.OwnerId, project.Name, project.Deleted, project.Public)
|
||||
r, err := p.Exec(project.OwnerID, project.Name, project.Deleted, project.Public)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectId, err := r.LastInsertId()
|
||||
projectID, err := r.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectAdminRole := models.ProjectRole{ProjectId: projectId, RoleId: models.PROJECTADMIN}
|
||||
projectAdminRole := models.ProjectRole{ProjectID: projectID, RoleID: models.PROJECTADMIN}
|
||||
_, err = AddProjectRole(projectAdminRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectDeveloperRole := models.ProjectRole{ProjectId: projectId, RoleId: models.DEVELOPER}
|
||||
projectDeveloperRole := models.ProjectRole{ProjectID: projectID, RoleID: models.DEVELOPER}
|
||||
_, err = AddProjectRole(projectDeveloperRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectGuestRole := models.ProjectRole{ProjectId: projectId, RoleId: models.GUEST}
|
||||
projectGuestRole := models.ProjectRole{ProjectID: projectID, RoleID: models.GUEST}
|
||||
_, err = AddProjectRole(projectGuestRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Add all project roles, after that when assigning a user to a project just update the upr table
|
||||
err = AddUserProjectRole(project.OwnerId, projectId, models.PROJECTADMIN)
|
||||
err = AddUserProjectRole(project.OwnerID, projectID, models.PROJECTADMIN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessLog := models.AccessLog{UserId: project.OwnerId, ProjectId: projectId, RepoName: project.Name + "/", Guid: "N/A", Operation: "create", OpTime: time.Now()}
|
||||
accessLog := models.AccessLog{UserID: project.OwnerID, ProjectID: projectID, RepoName: project.Name + "/", GUID: "N/A", Operation: "create", OpTime: time.Now()}
|
||||
err = AddAccessLog(accessLog)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// IsProjectPublic ...
|
||||
func IsProjectPublic(projectName string) bool {
|
||||
project, err := GetProjectByName(projectName)
|
||||
if err != nil {
|
||||
@ -94,7 +98,7 @@ func IsProjectPublic(projectName string) bool {
|
||||
return project.Public == 1
|
||||
}
|
||||
|
||||
//Query the projects based on publicity and user, disregarding the names etc.
|
||||
// QueryProject querys the projects based on publicity and user, disregarding the names etc.
|
||||
func QueryProject(query models.Project) ([]models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
@ -111,10 +115,10 @@ func QueryProject(query models.Project) ([]models.Project, error) {
|
||||
if query.Public == 1 {
|
||||
sql += ` and p.public = ?`
|
||||
queryParam = append(queryParam, query.Public)
|
||||
} else if isAdmin, _ := IsAdminRole(query.UserId); isAdmin == false {
|
||||
} else if isAdmin, _ := IsAdminRole(query.UserID); isAdmin == false {
|
||||
sql += ` and (p.owner_id = ? or u.user_id = ?) `
|
||||
queryParam = append(queryParam, query.UserId)
|
||||
queryParam = append(queryParam, query.UserId)
|
||||
queryParam = append(queryParam, query.UserID)
|
||||
queryParam = append(queryParam, query.UserID)
|
||||
}
|
||||
|
||||
if query.Name != "" {
|
||||
@ -133,21 +137,22 @@ func QueryProject(query models.Project) ([]models.Project, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func ProjectExists(nameOrId interface{}) (bool, error) {
|
||||
//ProjectExists returns whether the project exists according to its name of ID.
|
||||
func ProjectExists(nameOrID interface{}) (bool, error) {
|
||||
o := orm.NewOrm()
|
||||
type dummy struct{}
|
||||
sql := `select project_id from project where deleted = 0 and `
|
||||
switch nameOrId.(type) {
|
||||
switch nameOrID.(type) {
|
||||
case int64:
|
||||
sql += `project_id = ?`
|
||||
case string:
|
||||
sql += `name = ?`
|
||||
default:
|
||||
return false, errors.New(fmt.Sprintf("Invalid nameOrId: %v", nameOrId))
|
||||
return false, fmt.Errorf("Invalid nameOrId: %v", nameOrID)
|
||||
}
|
||||
|
||||
var d []dummy
|
||||
num, err := o.Raw(sql, nameOrId).QueryRows(&d)
|
||||
num, err := o.Raw(sql, nameOrID).QueryRows(&d)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -155,13 +160,14 @@ func ProjectExists(nameOrId interface{}) (bool, error) {
|
||||
|
||||
}
|
||||
|
||||
func GetProjectById(projectId int64) (*models.Project, error) {
|
||||
// GetProjectByID ...
|
||||
func GetProjectByID(projectID int64) (*models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.public
|
||||
from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
|
||||
queryParam := make([]interface{}, 1)
|
||||
queryParam = append(queryParam, projectId)
|
||||
queryParam = append(queryParam, projectID)
|
||||
|
||||
p := []models.Project{}
|
||||
count, err := o.Raw(sql, queryParam).QueryRows(&p)
|
||||
@ -175,6 +181,7 @@ func GetProjectById(projectId int64) (*models.Project, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetProjectByName ...
|
||||
func GetProjectByName(projectName string) (*models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
var p []models.Project
|
||||
@ -188,6 +195,7 @@ func GetProjectByName(projectName string) (*models.Project, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPermission gets roles that the user has according to the project.
|
||||
func GetPermission(username, projectName string) (string, error) {
|
||||
o := orm.NewOrm()
|
||||
|
||||
@ -209,21 +217,23 @@ func GetPermission(username, projectName string) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func ToggleProjectPublicity(projectId int64, publicity int) error {
|
||||
// ToggleProjectPublicity toggles the publicity of the project.
|
||||
func ToggleProjectPublicity(projectID int64, publicity int) error {
|
||||
o := orm.NewOrm()
|
||||
sql := "update project set public = ? where project_id = ?"
|
||||
_, err := o.Raw(sql, publicity, projectId).Exec()
|
||||
_, err := o.Raw(sql, publicity, projectID).Exec()
|
||||
return err
|
||||
}
|
||||
|
||||
func QueryRelevantProjects(userId int) ([]models.Project, error) {
|
||||
// QueryRelevantProjects returns all projects that the user is a member of.
|
||||
func QueryRelevantProjects(userID int) ([]models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
sql := `SELECT distinct p.project_id, p.name, p.public FROM registry.project p
|
||||
left join project_role pr on p.project_id = pr.project_id
|
||||
left join user_project_role upr on upr.pr_id = pr.pr_id
|
||||
where upr.user_id = ? or p.public = 1 and p.deleted = 0`
|
||||
var res []models.Project
|
||||
_, err := o.Raw(sql, userId).QueryRows(&res)
|
||||
_, err := o.Raw(sql, userID).QueryRows(&res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// AddProjectRole ...
|
||||
func AddProjectRole(projectRole models.ProjectRole) (int64, error) {
|
||||
o := orm.NewOrm()
|
||||
p, err := o.Raw("insert into project_role (project_id, role_id) values (?, ?)").Prepare()
|
||||
@ -27,7 +29,7 @@ func AddProjectRole(projectRole models.ProjectRole) (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
defer p.Close()
|
||||
r, err := p.Exec(projectRole.ProjectId, projectRole.RoleId)
|
||||
r, err := p.Exec(projectRole.ProjectID, projectRole.RoleID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -35,16 +37,17 @@ func AddProjectRole(projectRole models.ProjectRole) (int64, error) {
|
||||
return id, err
|
||||
}
|
||||
|
||||
func AddUserProjectRole(userId int, projectId int64, roleId int) error {
|
||||
// AddUserProjectRole inserts role information to table project_role and user_project_role.
|
||||
func AddUserProjectRole(userID int, projectID int64, roleID int) error {
|
||||
|
||||
o := orm.NewOrm()
|
||||
|
||||
var pr []models.ProjectRole
|
||||
|
||||
var prId int
|
||||
var prID int
|
||||
|
||||
sql := `select pr.pr_id, pr.project_id, pr.role_id from project_role pr where pr.project_id = ? and pr.role_id = ?`
|
||||
n, err := o.Raw(sql, projectId, roleId).QueryRows(&pr)
|
||||
n, err := o.Raw(sql, projectID, roleID).QueryRows(&pr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -55,7 +58,7 @@ func AddUserProjectRole(userId int, projectId int64, roleId int) error {
|
||||
return err
|
||||
}
|
||||
defer p.Close()
|
||||
r, err := p.Exec(projectId, roleId)
|
||||
r, err := p.Exec(projectID, roleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -63,20 +66,21 @@ func AddUserProjectRole(userId int, projectId int64, roleId int) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prId = int(id)
|
||||
prID = int(id)
|
||||
} else if n > 0 {
|
||||
prId = pr[0].PrId
|
||||
prID = pr[0].PrID
|
||||
}
|
||||
p, err := o.Raw("insert into user_project_role (user_id, pr_id) values (?, ?)").Prepare()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer p.Close()
|
||||
_, err = p.Exec(userId, prId)
|
||||
_, err = p.Exec(userID, prID)
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteUserProjectRoles(userId int, projectId int64) error {
|
||||
// DeleteUserProjectRoles ...
|
||||
func DeleteUserProjectRoles(userID int, projectID int64) error {
|
||||
o := orm.NewOrm()
|
||||
sql := `delete from user_project_role where user_id = ? and pr_id in
|
||||
(select pr_id from project_role where project_id = ?)`
|
||||
@ -84,6 +88,6 @@ func DeleteUserProjectRoles(userId int, projectId int64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = p.Exec(userId, projectId)
|
||||
_, err = p.Exec(userID, projectID)
|
||||
return err
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -24,6 +25,7 @@ import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// Register is used for user to register, the password is encrypted before the record is inserted into database.
|
||||
func Register(user models.User) (int64, error) {
|
||||
|
||||
err := validate(user)
|
||||
@ -48,12 +50,12 @@ func Register(user models.User) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
userId, err := r.LastInsertId()
|
||||
userID, err := r.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return userId, nil
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
func validate(user models.User) error {
|
||||
@ -99,6 +101,7 @@ func validate(user models.User) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UserExists returns whether a user exists according username or Email.
|
||||
func UserExists(user models.User, target string) (bool, error) {
|
||||
|
||||
if user.Username == "" && user.Email == "" {
|
||||
|
19
dao/role.go
19
dao/role.go
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -20,7 +21,8 @@ import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
func GetUserProjectRoles(userQuery models.User, projectId int64) ([]models.Role, error) {
|
||||
// GetUserProjectRoles returns roles that the user has according to the project.
|
||||
func GetUserProjectRoles(userQuery models.User, projectID int64) ([]models.Role, error) {
|
||||
|
||||
o := orm.NewOrm()
|
||||
|
||||
@ -32,15 +34,15 @@ func GetUserProjectRoles(userQuery models.User, projectId int64) ([]models.Role,
|
||||
where u.deleted = 0
|
||||
and u.user_id = ? `
|
||||
queryParam := make([]interface{}, 1)
|
||||
queryParam = append(queryParam, userQuery.UserId)
|
||||
queryParam = append(queryParam, userQuery.UserID)
|
||||
|
||||
if projectId > 0 {
|
||||
if projectID > 0 {
|
||||
sql += ` and pr.project_id = ? `
|
||||
queryParam = append(queryParam, projectId)
|
||||
queryParam = append(queryParam, projectID)
|
||||
}
|
||||
if userQuery.RoleId > 0 {
|
||||
if userQuery.RoleID > 0 {
|
||||
sql += ` and r.role_id = ? `
|
||||
queryParam = append(queryParam, userQuery.RoleId)
|
||||
queryParam = append(queryParam, userQuery.RoleID)
|
||||
}
|
||||
|
||||
var roleList []models.Role
|
||||
@ -52,9 +54,10 @@ func GetUserProjectRoles(userQuery models.User, projectId int64) ([]models.Role,
|
||||
return roleList, nil
|
||||
}
|
||||
|
||||
func IsAdminRole(userId int) (bool, error) {
|
||||
// IsAdminRole returns whether the user is admin.
|
||||
func IsAdminRole(userID int) (bool, error) {
|
||||
//role_id == 1 means the user is system admin
|
||||
userQuery := models.User{UserId: userId, RoleId: models.SYSADMIN}
|
||||
userQuery := models.User{UserID: userID, RoleID: models.SYSADMIN}
|
||||
adminRoleList, err := GetUserProjectRoles(userQuery, 0)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
42
dao/user.go
42
dao/user.go
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
@ -25,6 +26,7 @@ import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// GetUser ...
|
||||
func GetUser(query models.User) (*models.User, error) {
|
||||
|
||||
o := orm.NewOrm()
|
||||
@ -38,9 +40,9 @@ func GetUser(query models.User) (*models.User, error) {
|
||||
from user u
|
||||
where deleted = 0 `
|
||||
queryParam := make([]interface{}, 1)
|
||||
if query.UserId != 0 {
|
||||
if query.UserID != 0 {
|
||||
sql += ` and user_id = ? `
|
||||
queryParam = append(queryParam, query.UserId)
|
||||
queryParam = append(queryParam, query.UserID)
|
||||
}
|
||||
|
||||
if query.Username != "" {
|
||||
@ -48,9 +50,9 @@ func GetUser(query models.User) (*models.User, error) {
|
||||
queryParam = append(queryParam, query.Username)
|
||||
}
|
||||
|
||||
if query.ResetUuid != "" {
|
||||
if query.ResetUUID != "" {
|
||||
sql += ` and reset_uuid = ? `
|
||||
queryParam = append(queryParam, query.ResetUuid)
|
||||
queryParam = append(queryParam, query.ResetUUID)
|
||||
}
|
||||
|
||||
var u []models.User
|
||||
@ -65,6 +67,7 @@ func GetUser(query models.User) (*models.User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// LoginByDb is used for user to login with database auth mode.
|
||||
func LoginByDb(auth models.AuthModel) (*models.User, error) {
|
||||
|
||||
query := models.User{Username: auth.Principal, Email: auth.Principal}
|
||||
@ -84,6 +87,7 @@ func LoginByDb(auth models.AuthModel) (*models.User, error) {
|
||||
|
||||
}
|
||||
|
||||
// ListUsers lists all users according to different conditions.
|
||||
func ListUsers(query models.User) ([]models.User, error) {
|
||||
o := orm.NewOrm()
|
||||
u := []models.User{}
|
||||
@ -106,15 +110,16 @@ func ListUsers(query models.User) ([]models.User, error) {
|
||||
return u, err
|
||||
}
|
||||
|
||||
// ToggleUserAdminRole gives a user admim role.
|
||||
func ToggleUserAdminRole(u models.User) error {
|
||||
|
||||
projectRole := models.ProjectRole{PrId: 1} //admin project role
|
||||
projectRole := models.ProjectRole{PrID: 1} //admin project role
|
||||
|
||||
o := orm.NewOrm()
|
||||
|
||||
var pr []models.ProjectRole
|
||||
|
||||
n, err := o.Raw(`select user_id from user_project_role where user_id = ? and pr_id = ? `, u.UserId, projectRole.PrId).QueryRows(&pr)
|
||||
n, err := o.Raw(`select user_id from user_project_role where user_id = ? and pr_id = ? `, u.UserID, projectRole.PrID).QueryRows(&pr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -131,20 +136,21 @@ func ToggleUserAdminRole(u models.User) error {
|
||||
return err
|
||||
}
|
||||
defer p.Close()
|
||||
_, err = p.Exec(u.UserId, projectRole.PrId)
|
||||
_, err = p.Exec(u.UserID, projectRole.PrID)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ChangeUserPassword ...
|
||||
func ChangeUserPassword(u models.User, oldPassword ...string) error {
|
||||
o := orm.NewOrm()
|
||||
var err error
|
||||
var r sql.Result
|
||||
if len(oldPassword) == 0 {
|
||||
//In some cases, it may no need to check old password, just as Linux change password policies.
|
||||
_, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserId).Exec()
|
||||
_, err = o.Raw(`update user set password=?, salt=? where user_id=?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID).Exec()
|
||||
} else if len(oldPassword) == 1 {
|
||||
r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserId, utils.Encrypt(oldPassword[0], u.Salt)).Exec()
|
||||
r, err = o.Raw(`update user set password=?, salt=? where user_id=? and password = ?`, utils.Encrypt(u.Password, u.Salt), u.Salt, u.UserID, utils.Encrypt(oldPassword[0], u.Salt)).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -161,9 +167,10 @@ func ChangeUserPassword(u models.User, oldPassword ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// ResetUserPassword ...
|
||||
func ResetUserPassword(u models.User) error {
|
||||
o := orm.NewOrm()
|
||||
r, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUuid).Exec()
|
||||
r, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUUID).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -177,12 +184,14 @@ func ResetUserPassword(u models.User) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateUserResetUuid(u models.User) error {
|
||||
// UpdateUserResetUUID ...
|
||||
func UpdateUserResetUUID(u models.User) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Raw(`update user set reset_uuid=? where email=?`, u.ResetUuid, u.Email).Exec()
|
||||
_, err := o.Raw(`update user set reset_uuid=? where email=?`, u.ResetUUID, u.Email).Exec()
|
||||
return err
|
||||
}
|
||||
|
||||
// CheckUserPassword checks whether the password is correct.
|
||||
func CheckUserPassword(query models.User) (*models.User, error) {
|
||||
|
||||
currentUser, err := GetUser(query)
|
||||
@ -199,10 +208,10 @@ func CheckUserPassword(query models.User) (*models.User, error) {
|
||||
|
||||
queryParam := make([]interface{}, 1)
|
||||
|
||||
if query.UserId != 0 {
|
||||
if query.UserID != 0 {
|
||||
sql += ` and password = ? and user_id = ?`
|
||||
queryParam = append(queryParam, utils.Encrypt(query.Password, currentUser.Salt))
|
||||
queryParam = append(queryParam, query.UserId)
|
||||
queryParam = append(queryParam, query.UserID)
|
||||
} else {
|
||||
sql += ` and username = ? and password = ?`
|
||||
queryParam = append(queryParam, currentUser.Username)
|
||||
@ -223,8 +232,9 @@ func CheckUserPassword(query models.User) (*models.User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteUser(userId int) error {
|
||||
// DeleteUser ...
|
||||
func DeleteUser(userID int) error {
|
||||
o := orm.NewOrm()
|
||||
_, err := o.Raw(`update user set deleted = 1 where user_id = ?`, userId).Exec()
|
||||
_, err := o.Raw(`update user set deleted = 1 where user_id = ?`, userID).Exec()
|
||||
return err
|
||||
}
|
||||
|
26
main.go
26
main.go
@ -12,17 +12,17 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
_ "github.com/vmware/harbor/auth/db"
|
||||
_ "github.com/vmware/harbor/auth/ldap"
|
||||
"github.com/vmware/harbor/dao"
|
||||
"github.com/vmware/harbor/models"
|
||||
_ "github.com/vmware/harbor/opt_auth/db"
|
||||
_ "github.com/vmware/harbor/opt_auth/ldap"
|
||||
_ "github.com/vmware/harbor/routers"
|
||||
|
||||
"os"
|
||||
@ -31,19 +31,19 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ADMIN_USER_ID = 1
|
||||
adminUserID = 1
|
||||
)
|
||||
|
||||
func updateInitPassword(userId int, password string) error {
|
||||
queryUser := models.User{UserId: userId}
|
||||
func updateInitPassword(userID int, password string) error {
|
||||
queryUser := models.User{UserID: userID}
|
||||
user, err := dao.GetUser(queryUser)
|
||||
if err != nil {
|
||||
log.Println("Failed to get user, userId:", userId)
|
||||
log.Println("Failed to get user, userID:", userID)
|
||||
return err
|
||||
}
|
||||
if user == nil {
|
||||
log.Printf("User id: %d does not exist.", userId)
|
||||
return errors.New(fmt.Sprintf("User id: %s does not exist.", userId))
|
||||
log.Printf("User id: %d does not exist.", userID)
|
||||
return fmt.Errorf("User id: %d does not exist.", userID)
|
||||
} else if user.Salt == "" {
|
||||
salt, err := dao.GenerateRandomString()
|
||||
if err != nil {
|
||||
@ -54,12 +54,12 @@ func updateInitPassword(userId int, password string) error {
|
||||
user.Password = password
|
||||
err = dao.ChangeUserPassword(*user)
|
||||
if err != nil {
|
||||
log.Printf("Failed to update user encrypted password, userId: %d, err: %v", userId, err)
|
||||
log.Printf("Failed to update user encrypted password, userID: %d, err: %v", userID, err)
|
||||
return err
|
||||
}
|
||||
log.Printf("User id: %d updated its encypted password successfully.", userId)
|
||||
log.Printf("User id: %d updated its encypted password successfully.", userID)
|
||||
} else {
|
||||
log.Printf("User id: %d already has its encrypted password.", userId)
|
||||
log.Printf("User id: %d already has its encrypted password.", userID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -68,6 +68,6 @@ func main() {
|
||||
|
||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||
dao.InitDB()
|
||||
updateInitPassword(ADMIN_USER_ID, os.Getenv("HARBOR_ADMIN_PASSWORD"))
|
||||
updateInitPassword(adminUserID, os.Getenv("HARBOR_ADMIN_PASSWORD"))
|
||||
beego.Run()
|
||||
}
|
||||
|
@ -12,20 +12,22 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// AccessLog holds information about logs which are used to record the actions that user take to the resourses.
|
||||
type AccessLog struct {
|
||||
LogId int
|
||||
UserId int
|
||||
ProjectId int64
|
||||
RepoName string
|
||||
Guid string
|
||||
Operation string
|
||||
OpTime time.Time
|
||||
LogID int `orm:"column(log_id)" json:"LogId"`
|
||||
UserID int `orm:"column(user_id)" json:"UserId"`
|
||||
ProjectID int64 `orm:"column(project_id)" json:"ProjectId"`
|
||||
RepoName string `orm:"column(repo_name)"`
|
||||
GUID string `orm:"column(GUID)" json:"Guid"`
|
||||
Operation string `orm:"column(operation)"`
|
||||
OpTime time.Time `orm:"column(op_time)"`
|
||||
Username string
|
||||
Keywords string
|
||||
|
||||
|
@ -1,19 +1,21 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
// AuthModel holds information used to authenticate.
|
||||
type AuthModel struct {
|
||||
Principal string
|
||||
Password string
|
||||
|
@ -1,29 +1,32 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Notification holds all events.
|
||||
type Notification struct {
|
||||
Events []Event
|
||||
}
|
||||
|
||||
// Event holds the details of a event.
|
||||
type Event struct {
|
||||
Id string
|
||||
ID string `json:"Id"`
|
||||
TimeStamp time.Time
|
||||
Action string
|
||||
Target *Target
|
||||
@ -31,19 +34,22 @@ type Event struct {
|
||||
Actor *Actor
|
||||
}
|
||||
|
||||
// Target holds information about the target of a event.
|
||||
type Target struct {
|
||||
MediaType string
|
||||
Digest string
|
||||
Repository string
|
||||
Url string
|
||||
URL string `json:"Url"`
|
||||
}
|
||||
|
||||
// Actor holds information about actor.
|
||||
type Actor struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// Request holds information about a request.
|
||||
type Request struct {
|
||||
Id string
|
||||
ID string `json:"Id"`
|
||||
Method string
|
||||
UserAgent string
|
||||
}
|
||||
|
@ -1,33 +1,35 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Project holds the details of a project.
|
||||
type Project struct {
|
||||
ProjectId int64
|
||||
OwnerId int
|
||||
Name string
|
||||
CreationTime time.Time
|
||||
ProjectID int64 `orm:"column(project_id)" json:"ProjectId"`
|
||||
OwnerID int `orm:"column(owner_id)" json:"OwnerId"`
|
||||
Name string `orm:"column(name)"`
|
||||
CreationTime time.Time `orm:"column(creation_time)"`
|
||||
CreationTimeStr string
|
||||
Deleted int
|
||||
UserId int
|
||||
Deleted int `orm:"column(deleted)"`
|
||||
UserID int `json:"UserId"`
|
||||
OwnerName string
|
||||
Public int
|
||||
Public int `orm:"column(public)"`
|
||||
//This field does not have correspondent column in DB, this is just for UI to disable button
|
||||
Togglable bool
|
||||
}
|
||||
|
@ -1,21 +1,23 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
// ProjectRole holds information about the relationship of project and role.
|
||||
type ProjectRole struct {
|
||||
PrId int
|
||||
ProjectId int64
|
||||
RoleId int
|
||||
PrID int `orm:"column(pr_id)" json:"PrId"`
|
||||
ProjectID int64 `orm:"column(project_id)" json:"ProjectId"`
|
||||
RoleID int `orm:"column(role_id)" json:"RoleId"`
|
||||
}
|
||||
|
@ -1,25 +1,21 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
type V1Repo struct {
|
||||
NumResults int
|
||||
Query string
|
||||
Results []RepoItem
|
||||
}
|
||||
|
||||
// Repo holds information about repositories.
|
||||
type Repo struct {
|
||||
Repositories []string `json:repositories`
|
||||
Repositories []string `json:"repositories"`
|
||||
}
|
||||
|
@ -1,32 +1,34 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RepoItem holds manifest of an image.
|
||||
type RepoItem struct {
|
||||
Id string `json:"Id"`
|
||||
Parent string `json:"Parent"`
|
||||
Created time.Time `json:"Created"`
|
||||
CreatedStr string `json:"CreatedStr"`
|
||||
DurationDays string `json:"Duration Days"`
|
||||
Author string `json:"Author"`
|
||||
Architecture string `json:"Architecture"`
|
||||
Docker_version string `json:"Docker Version"`
|
||||
Os string `json:"OS"`
|
||||
ID string `json:"Id"`
|
||||
Parent string `json:"Parent"`
|
||||
Created time.Time `json:"Created"`
|
||||
CreatedStr string `json:"CreatedStr"`
|
||||
DurationDays string `json:"Duration Days"`
|
||||
Author string `json:"Author"`
|
||||
Architecture string `json:"Architecture"`
|
||||
DockerVersion string `json:"Docker Version"`
|
||||
Os string `json:"OS"`
|
||||
//Size int `json:"Size"`
|
||||
}
|
||||
|
@ -1,28 +1,34 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
const (
|
||||
SYSADMIN = 1
|
||||
//SYSADMIN system administrator
|
||||
SYSADMIN = 1
|
||||
//PROJECTADMIN project administrator
|
||||
PROJECTADMIN = 2
|
||||
DEVELOPER = 3
|
||||
GUEST = 4
|
||||
//DEVELOPER developer
|
||||
DEVELOPER = 3
|
||||
//GUEST guest
|
||||
GUEST = 4
|
||||
)
|
||||
|
||||
// Role holds the details of a role.
|
||||
type Role struct {
|
||||
RoleId int `json:"role_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
Name string `json:"role_name"`
|
||||
RoleID int `json:"role_id" orm:"column(role_id)"`
|
||||
RoleCode string `json:"role_code" orm:"column(role_code)"`
|
||||
Name string `json:"role_name" orm:"column(name)"`
|
||||
}
|
||||
|
@ -1,20 +1,22 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
// Tag holds information about a tag.
|
||||
type Tag struct {
|
||||
Version string `json:version`
|
||||
ImageId string `json:image_id`
|
||||
Version string `json:"version"`
|
||||
ImageID string `json:"image_id"`
|
||||
}
|
||||
|
@ -1,31 +1,33 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
// User holds the details of a user.
|
||||
type User struct {
|
||||
UserId int
|
||||
Username string
|
||||
Email string
|
||||
Password string
|
||||
Realname string
|
||||
Comment string
|
||||
Deleted int
|
||||
UserID int `orm:"column(user_id)" json:"UserId"`
|
||||
Username string `orm:"column(username)"`
|
||||
Email string `orm:"column(email)"`
|
||||
Password string `orm:"column(password)"`
|
||||
Realname string `orm:"column(realname)"`
|
||||
Comment string `orm:"column(comment)"`
|
||||
Deleted int `orm:"column(deleted)"`
|
||||
Rolename string
|
||||
RoleId int
|
||||
RoleID int `json:"RoleId"`
|
||||
RoleList []Role
|
||||
HasAdminRole int
|
||||
ResetUuid string
|
||||
Salt string
|
||||
ResetUUID string `orm:"column(reset_uuid)" json:"ResetUuid"`
|
||||
Salt string `orm:"column(salt)"`
|
||||
}
|
||||
|
@ -1,21 +1,23 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 models
|
||||
|
||||
// UserProjectRole holds information about relationship of user, project and role.
|
||||
type UserProjectRole struct {
|
||||
UprId int
|
||||
UserId int
|
||||
PrId int64
|
||||
UprID int `orm:"column(upr_id)" json:"UprId"`
|
||||
UserID int `orm:"column(user_id)" json:"UserId"`
|
||||
PrID int64 `orm:"column(pr_id)" json:"PrId"`
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routers
|
||||
|
||||
import (
|
||||
@ -61,5 +62,5 @@ func init() {
|
||||
|
||||
//external service that hosted on harbor process:
|
||||
beego.Router("/service/notifications", &service.NotificationHandler{})
|
||||
beego.Router("/service/token", &service.AuthController{}, "get:Auth")
|
||||
beego.Router("/service/token", &service.TokenHandler{})
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
@ -25,12 +26,14 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// NotificationHandler handles request on /service/notifications/, which listens to registry's events.
|
||||
type NotificationHandler struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
const MEDIA_TYPE_MANIFEST = "application/vnd.docker.distribution.manifest.v1+json"
|
||||
const mediaTypeManifest = "application/vnd.docker.distribution.manifest.v1+json"
|
||||
|
||||
// Post handles POST request, and records audit log or refreshes cache based on event.
|
||||
func (n *NotificationHandler) Post() {
|
||||
var notification models.Notification
|
||||
// log.Printf("Notification Handler triggered!\n")
|
||||
@ -43,7 +46,7 @@ func (n *NotificationHandler) Post() {
|
||||
}
|
||||
var username, action, repo, project string
|
||||
for _, e := range notification.Events {
|
||||
if e.Target.MediaType == MEDIA_TYPE_MANIFEST && strings.HasPrefix(e.Request.UserAgent, "docker") {
|
||||
if e.Target.MediaType == mediaTypeManifest && strings.HasPrefix(e.Request.UserAgent, "docker") {
|
||||
username = e.Actor.Name
|
||||
action = e.Action
|
||||
repo = e.Target.Repository
|
||||
@ -67,6 +70,7 @@ func (n *NotificationHandler) Post() {
|
||||
|
||||
}
|
||||
|
||||
// Render returns nil as it won't render any template.
|
||||
func (n *NotificationHandler) Render() error {
|
||||
return nil
|
||||
}
|
||||
|
@ -12,14 +12,15 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/auth"
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/opt_auth"
|
||||
svc_utils "github.com/vmware/harbor/service/utils"
|
||||
"github.com/vmware/harbor/utils"
|
||||
|
||||
@ -27,12 +28,15 @@ import (
|
||||
"github.com/docker/distribution/registry/auth/token"
|
||||
)
|
||||
|
||||
type AuthController struct {
|
||||
// TokenHandler handles request on /service/token, which is the auth provider for registry.
|
||||
type TokenHandler struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
//handle request
|
||||
func (a *AuthController) Auth() {
|
||||
// Get handles GET request, it checks the http header for user credentials
|
||||
// and parse service and scope based on docker registry v2 standard,
|
||||
// checkes the permission agains local DB and generates jwt token.
|
||||
func (a *TokenHandler) Get() {
|
||||
|
||||
request := a.Ctx.Request
|
||||
|
||||
@ -56,7 +60,7 @@ func (a *AuthController) Auth() {
|
||||
a.serveToken(username, service, access)
|
||||
}
|
||||
|
||||
func (a *AuthController) serveToken(username, service string, access []*token.ResourceActions) {
|
||||
func (a *TokenHandler) serveToken(username, service string, access []*token.ResourceActions) {
|
||||
writer := a.Ctx.ResponseWriter
|
||||
//create token
|
||||
rawToken, err := svc_utils.MakeToken(username, service, access)
|
||||
@ -72,14 +76,14 @@ func (a *AuthController) serveToken(username, service string, access []*token.Re
|
||||
}
|
||||
|
||||
func authenticate(principal, password string) bool {
|
||||
user, err := opt_auth.Login(models.AuthModel{principal, password})
|
||||
user, err := auth.Login(models.AuthModel{principal, password})
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in UserLogin: %v", err)
|
||||
return false
|
||||
}
|
||||
if user == nil {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
@ -36,6 +37,7 @@ const (
|
||||
expiration = 5 //minute
|
||||
)
|
||||
|
||||
// GetResourceActions ...
|
||||
func GetResourceActions(scope string) []*token.ResourceActions {
|
||||
var res []*token.ResourceActions
|
||||
if scope == "" {
|
||||
@ -50,55 +52,54 @@ func GetResourceActions(scope string) []*token.ResourceActions {
|
||||
return res
|
||||
}
|
||||
|
||||
//Try to modify the action list in access based on permission
|
||||
//determine if the request needs to be authenticated.
|
||||
//for details see:https://github.com/docker/docker/issues/15640
|
||||
// FilterAccess modify the action list in access based on permission
|
||||
// determine if the request needs to be authenticated.
|
||||
func FilterAccess(username string, authenticated bool, a *token.ResourceActions) {
|
||||
|
||||
if a.Type == "registry" && a.Name == "catalog" {
|
||||
return
|
||||
} else {
|
||||
//clear action list to assign to new acess element after perm check.
|
||||
a.Actions = []string{}
|
||||
if a.Type == "repository" {
|
||||
if strings.Contains(a.Name, "/") { //Only check the permission when the requested image has a namespace, i.e. project
|
||||
projectName := a.Name[0:strings.LastIndex(a.Name, "/")]
|
||||
var permission string
|
||||
var err error
|
||||
if authenticated {
|
||||
if username == "admin" {
|
||||
exist, err := dao.ProjectExists(projectName)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in CheckExistProject: %v", err)
|
||||
return
|
||||
}
|
||||
if exist {
|
||||
permission = "RW"
|
||||
} else {
|
||||
permission = ""
|
||||
log.Printf("project %s does not exist, set empty permission for admin", projectName)
|
||||
}
|
||||
}
|
||||
|
||||
//clear action list to assign to new acess element after perm check.
|
||||
a.Actions = []string{}
|
||||
if a.Type == "repository" {
|
||||
if strings.Contains(a.Name, "/") { //Only check the permission when the requested image has a namespace, i.e. project
|
||||
projectName := a.Name[0:strings.LastIndex(a.Name, "/")]
|
||||
var permission string
|
||||
var err error
|
||||
if authenticated {
|
||||
if username == "admin" {
|
||||
exist, err := dao.ProjectExists(projectName)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in CheckExistProject: %v", err)
|
||||
return
|
||||
}
|
||||
if exist {
|
||||
permission = "RW"
|
||||
} else {
|
||||
permission, err = dao.GetPermission(username, projectName)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in GetPermission: %v", err)
|
||||
return
|
||||
}
|
||||
permission = ""
|
||||
log.Printf("project %s does not exist, set empty permission for admin", projectName)
|
||||
}
|
||||
} else {
|
||||
permission, err = dao.GetPermission(username, projectName)
|
||||
if err != nil {
|
||||
log.Printf("Error occurred in GetPermission: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if strings.Contains(permission, "W") {
|
||||
a.Actions = append(a.Actions, "push")
|
||||
}
|
||||
if strings.Contains(permission, "R") || dao.IsProjectPublic(projectName) {
|
||||
a.Actions = append(a.Actions, "pull")
|
||||
}
|
||||
}
|
||||
if strings.Contains(permission, "W") {
|
||||
a.Actions = append(a.Actions, "push")
|
||||
}
|
||||
if strings.Contains(permission, "R") || dao.IsProjectPublic(projectName) {
|
||||
a.Actions = append(a.Actions, "pull")
|
||||
}
|
||||
}
|
||||
log.Printf("current access, type: %s, name:%s, actions:%v \n", a.Type, a.Name, a.Actions)
|
||||
}
|
||||
log.Printf("current access, type: %s, name:%s, actions:%v \n", a.Type, a.Name, a.Actions)
|
||||
}
|
||||
|
||||
//For the UI process to call, so it won't establish a https connection from UI to proxy.
|
||||
// GenTokenForUI is for the UI process to call, so it won't establish a https connection from UI to proxy.
|
||||
func GenTokenForUI(username, service, scope string) (string, error) {
|
||||
access := GetResourceActions(scope)
|
||||
for _, a := range access {
|
||||
@ -107,6 +108,7 @@ func GenTokenForUI(username, service, scope string) (string, error) {
|
||||
return MakeToken(username, service, access)
|
||||
}
|
||||
|
||||
// MakeToken makes a valid jwt token based on parms.
|
||||
func MakeToken(username, service string, access []*token.ResourceActions) (string, error) {
|
||||
pk, err := libtrust.LoadKeyFile(privateKey)
|
||||
if err != nil {
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
@ -25,9 +26,10 @@ import (
|
||||
"github.com/astaxie/beego/cache"
|
||||
)
|
||||
|
||||
// Cache is the global cache in system.
|
||||
var Cache cache.Cache
|
||||
|
||||
const CATALOG string = "catalog"
|
||||
const catalogKey string = "catalog"
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
@ -37,8 +39,9 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// RefreshCatalogCache calls registry's API to get repository list and write it to cache.
|
||||
func RefreshCatalogCache() error {
|
||||
result, err := RegistryApiGet(BuildRegistryUrl("_catalog"), "")
|
||||
result, err := RegistryAPIGet(BuildRegistryURL("_catalog"), "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -47,19 +50,20 @@ func RefreshCatalogCache() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Cache.Put(CATALOG, repoResp.Repositories, 600*time.Second)
|
||||
Cache.Put(catalogKey, repoResp.Repositories, 600*time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRepoFromCache get repository list from cache, it refreshes the cache if it's empty.
|
||||
func GetRepoFromCache() ([]string, error) {
|
||||
|
||||
result := Cache.Get(CATALOG)
|
||||
result := Cache.Get(catalogKey)
|
||||
if result == nil {
|
||||
err := RefreshCatalogCache()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cached := Cache.Get(CATALOG)
|
||||
cached := Cache.Get(catalogKey)
|
||||
if cached != nil {
|
||||
return cached.([]string), nil
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
@ -24,7 +25,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func BuildRegistryUrl(segments ...string) string {
|
||||
// BuildRegistryURL ...
|
||||
func BuildRegistryURL(segments ...string) string {
|
||||
registryURL := os.Getenv("REGISTRY_URL")
|
||||
if registryURL == "" {
|
||||
registryURL = "http://localhost:5000"
|
||||
@ -40,7 +42,9 @@ func BuildRegistryUrl(segments ...string) string {
|
||||
return url
|
||||
}
|
||||
|
||||
func RegistryApiGet(url, username string) ([]byte, error) {
|
||||
// RegistryAPIGet triggers GET request to the URL which is the endpoint of registry and returns the response body.
|
||||
// It will attach a valid jwt token to the request if registry requires.
|
||||
func RegistryAPIGet(url, username string) ([]byte, error) {
|
||||
response, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -12,4 +12,5 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package test
|
||||
|
@ -1,17 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 utils
|
||||
|
||||
import (
|
||||
@ -21,6 +22,7 @@ import (
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
// Encrypt encrypts the content with salt
|
||||
func Encrypt(content string, salt string) string {
|
||||
return fmt.Sprintf("%x", pbkdf2.Key([]byte(content), []byte(salt), 4096, 16, sha1.New))
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 utils
|
||||
|
||||
import (
|
||||
@ -23,12 +24,15 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// Mail holds information about content of Email
|
||||
type Mail struct {
|
||||
From string
|
||||
To []string
|
||||
Subject string
|
||||
Message string
|
||||
}
|
||||
|
||||
// MailConfig holds information about Email configurations
|
||||
type MailConfig struct {
|
||||
Identity string
|
||||
Host string
|
||||
@ -39,6 +43,7 @@ type MailConfig struct {
|
||||
|
||||
var mc MailConfig
|
||||
|
||||
// SendMail sends Email according to the configurations
|
||||
func (m Mail) SendMail() error {
|
||||
|
||||
if mc.Host == "" {
|
||||
|
@ -1,17 +1,18 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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.
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
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 utils
|
||||
|
||||
import (
|
||||
@ -27,9 +28,10 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
const SESSION_COOKIE = "beegosessionID"
|
||||
const sessionCookie = "beegosessionID"
|
||||
|
||||
func BuildRegistryUrl(segments ...string) string {
|
||||
// BuildRegistryURL builds the URL of registry
|
||||
func BuildRegistryURL(segments ...string) string {
|
||||
registryURL := os.Getenv("REGISTRY_URL")
|
||||
if registryURL == "" {
|
||||
registryURL = "http://localhost:5000"
|
||||
@ -45,8 +47,9 @@ func BuildRegistryUrl(segments ...string) string {
|
||||
return url
|
||||
}
|
||||
|
||||
func HttpGet(url, sessionId, username, password string) ([]byte, error) {
|
||||
response, err := http.Get(url)
|
||||
// HTTPGet is used to call the API of registry. If a token is needed, it will get a token first.
|
||||
func HTTPGet(URL, sessionID, username, password string) ([]byte, error) {
|
||||
response, err := http.Get(URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -60,7 +63,7 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) {
|
||||
} else if response.StatusCode == http.StatusUnauthorized {
|
||||
authenticate := response.Header.Get("WWW-Authenticate")
|
||||
str := strings.Split(authenticate, " ")[1]
|
||||
beego.Trace("url: " + url)
|
||||
beego.Trace("url: " + URL)
|
||||
beego.Trace("Authentication Header: " + str)
|
||||
var realm string
|
||||
var service string
|
||||
@ -72,7 +75,7 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) {
|
||||
} else if strings.Contains(s, "service") {
|
||||
service = s
|
||||
} else if strings.Contains(s, "scope") {
|
||||
strings.HasSuffix(url, "v2/_catalog")
|
||||
strings.HasSuffix(URL, "v2/_catalog")
|
||||
scope = s
|
||||
}
|
||||
}
|
||||
@ -80,18 +83,18 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) {
|
||||
service = strings.Split(service, "\"")[1]
|
||||
scope = strings.Split(scope, "\"")[1]
|
||||
|
||||
authUrl := realm + "?service=" + service + "&scope=" + scope
|
||||
authURL := realm + "?service=" + service + "&scope=" + scope
|
||||
//skip certificate check if token service is https.
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
request, err := http.NewRequest("GET", authUrl, nil)
|
||||
request, err := http.NewRequest("GET", authURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(sessionId) > 0 {
|
||||
cookie := &http.Cookie{Name: SESSION_COOKIE, Value: sessionId, Path: "/"}
|
||||
if len(sessionID) > 0 {
|
||||
cookie := &http.Cookie{Name: sessionCookie, Value: sessionID, Path: "/"}
|
||||
request.AddCookie(cookie)
|
||||
} else {
|
||||
request.SetBasicAuth(username, password)
|
||||
@ -109,7 +112,7 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) {
|
||||
if response.StatusCode == http.StatusOK {
|
||||
tt := make(map[string]string)
|
||||
json.Unmarshal(result, &tt)
|
||||
request, err = http.NewRequest("GET", url, nil)
|
||||
request, err = http.NewRequest("GET", URL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -136,9 +139,8 @@ func HttpGet(url, sessionId, username, password string) ([]byte, error) {
|
||||
defer response.Body.Close()
|
||||
|
||||
return result, nil
|
||||
} else {
|
||||
return nil, errors.New(string(result))
|
||||
}
|
||||
return nil, errors.New(string(result))
|
||||
} else {
|
||||
return nil, errors.New(string(result))
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
@ -23,10 +24,12 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
// Repository holds information about repository
|
||||
type Repository struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// ParseBasicAuth parses the basic authorization
|
||||
func ParseBasicAuth(authorization []string) (username, password string) {
|
||||
if authorization == nil || len(authorization) == 0 {
|
||||
beego.Debug("Authorization header is not set.")
|
||||
@ -38,6 +41,7 @@ func ParseBasicAuth(authorization []string) (username, password string) {
|
||||
return pair[0], pair[1]
|
||||
}
|
||||
|
||||
// GetProject parses the repository and return the name of project.
|
||||
func (r *Repository) GetProject() string {
|
||||
if !strings.ContainsRune(r.Name, '/') {
|
||||
return ""
|
||||
@ -45,18 +49,22 @@ func (r *Repository) GetProject() string {
|
||||
return r.Name[0:strings.LastIndex(r.Name, "/")]
|
||||
}
|
||||
|
||||
// ProjectSorter holds an array of projects
|
||||
type ProjectSorter struct {
|
||||
Projects []models.Project
|
||||
}
|
||||
|
||||
// Len returns the length of array in ProjectSorter
|
||||
func (ps *ProjectSorter) Len() int {
|
||||
return len(ps.Projects)
|
||||
}
|
||||
|
||||
// Less defines the comparison rules of project
|
||||
func (ps *ProjectSorter) Less(i, j int) bool {
|
||||
return ps.Projects[i].Name < ps.Projects[j].Name
|
||||
}
|
||||
|
||||
// Swap swaps the position of i and j
|
||||
func (ps *ProjectSorter) Swap(i, j int) {
|
||||
ps.Projects[i], ps.Projects[j] = ps.Projects[j], ps.Projects[i]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user