Change status code for projects API

Update to projects API so it will not differentiate if a project
does not exist or the user doesn't have permission to access it.

Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
Daniel Jiang 2020-06-09 07:49:50 +08:00
parent c993103e01
commit f73aa3ce80
4 changed files with 38 additions and 24 deletions

View File

@ -84,24 +84,20 @@ func (b *BaseController) RequireAuthenticated() bool {
// HasProjectPermission returns true when the request has action permission on project subresource
func (b *BaseController) HasProjectPermission(projectIDOrName interface{}, action rbac.Action, subresource ...rbac.Resource) (bool, error) {
projectID, projectName, err := utils.ParseProjectIDOrName(projectIDOrName)
_, _, err := utils.ParseProjectIDOrName(projectIDOrName)
if err != nil {
return false, err
}
if projectName != "" {
project, err := b.ProjectMgr.Get(projectName)
if err != nil {
return false, err
}
if project == nil {
return false, errors.NotFoundError(nil).WithMessage("project %s not found", projectName)
}
projectID = project.ProjectID
project, err := b.ProjectMgr.Get(projectIDOrName)
if err != nil {
return false, err
}
if project == nil {
return false, errors.NotFoundError(fmt.Errorf("project %v not found", projectIDOrName))
}
resource := rbac.NewProjectNamespace(projectID).Resource(subresource...)
resource := rbac.NewProjectNamespace(project.ProjectID).Resource(subresource...)
if !b.SecurityCtx.Can(action, resource) {
return false, nil
}
@ -114,24 +110,42 @@ func (b *BaseController) HasProjectPermission(projectIDOrName interface{}, actio
func (b *BaseController) RequireProjectAccess(projectIDOrName interface{}, action rbac.Action, subresource ...rbac.Resource) bool {
hasPermission, err := b.HasProjectPermission(projectIDOrName, action, subresource...)
if err != nil {
b.SendError(err)
if errors.IsNotFoundErr(err) {
b.handleProjectNotFound(projectIDOrName)
} else {
b.SendError(err)
}
return false
}
if !hasPermission {
if !b.SecurityCtx.IsAuthenticated() {
b.SendError(errors.UnauthorizedError(errors.New("Unauthorized")))
} else {
b.SendError(errors.New(errors.New(b.SecurityCtx.GetUsername())).WithCode(errors.ForbiddenCode))
}
b.SendPermissionError()
return false
}
return true
}
// This should be called when a project is not found, if the caller is a system admin it returns 404.
// If it's regular user, it will render permission error
func (b *BaseController) handleProjectNotFound(projectIDOrName interface{}) {
if b.SecurityCtx.IsSysAdmin() {
b.SendNotFoundError(fmt.Errorf("project %v not found", projectIDOrName))
} else {
b.SendPermissionError()
}
}
// SendPermissionError is a shortcut for sending different http error based on authentication status.
func (b *BaseController) SendPermissionError() {
if !b.SecurityCtx.IsAuthenticated() {
b.SendUnAuthorizedError(errors.New("UnAuthorized"))
} else {
b.SendForbiddenError(errors.New(b.SecurityCtx.GetUsername()))
}
}
// WriteJSONData writes the JSON data to the client.
func (b *BaseController) WriteJSONData(object interface{}) {
b.Data["json"] = object

View File

@ -69,7 +69,7 @@ func (m *MetadataAPI) Prepare() {
}
if project == nil {
m.SendNotFoundError(fmt.Errorf("project %d not found", id))
m.handleProjectNotFound(id)
return
}

View File

@ -65,10 +65,10 @@ func TestValidateProjectMetadata(t *testing.T) {
func TestMetaAPI(t *testing.T) {
client := newHarborAPI()
// non-exist project
// non-exist project, it should return 401 if user is not logged in.
code, _, err := client.PostMeta(*unknownUsr, int64(1000), nil)
require.Nil(t, err)
assert.Equal(t, http.StatusNotFound, code)
assert.Equal(t, http.StatusUnauthorized, code)
// non-login
code, _, err = client.PostMeta(*unknownUsr, int64(1), nil)

View File

@ -79,7 +79,7 @@ func (p *ProjectAPI) Prepare() {
}
if project == nil {
p.SendNotFoundError(fmt.Errorf("project %d not found", id))
p.handleProjectNotFound(id)
return
}