fix(api): review security policies when creating/updating a resource control (#1964)

pull/1968/head
Anthony Lapenna 2018-06-11 17:58:46 +02:00 committed by GitHub
parent e3d564325b
commit 1e12057cdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 5 deletions

View File

@ -43,6 +43,15 @@ func (handler *Handler) resourceControlUpdate(w http.ResponseWriter, r *http.Req
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a resource control with with the specified identifier inside the database", err}
}
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
}
if !security.AuthorizedResourceControlAccess(resourceControl, securityContext) {
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the resource control", portainer.ErrResourceAccessDenied}
}
resourceControl.AdministratorsOnly = payload.AdministratorsOnly
var userAccesses = make([]portainer.UserResourceAccess, 0)
@ -65,11 +74,6 @@ func (handler *Handler) resourceControlUpdate(w http.ResponseWriter, r *http.Req
}
resourceControl.TeamAccesses = teamAccesses
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
}
if !security.AuthorizedResourceControlUpdate(resourceControl, securityContext) {
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the resource control", portainer.ErrResourceAccessDenied}
}

View File

@ -40,6 +40,43 @@ func AuthorizedResourceControlDeletion(resourceControl *portainer.ResourceContro
return false
}
// AuthorizedResourceControlAccess checks whether the user can alter an existing resource control.
func AuthorizedResourceControlAccess(resourceControl *portainer.ResourceControl, context *RestrictedRequestContext) bool {
if context.IsAdmin {
return true
}
if resourceControl.AdministratorsOnly {
return false
}
authorizedTeamAccess := false
for _, access := range resourceControl.TeamAccesses {
for _, membership := range context.UserMemberships {
if membership.TeamID == access.TeamID {
authorizedTeamAccess = true
break
}
}
}
if !authorizedTeamAccess {
return false
}
authorizedUserAccess := false
for _, access := range resourceControl.UserAccesses {
if context.UserID == access.UserID {
authorizedUserAccess = true
break
}
}
if !authorizedUserAccess {
return false
}
return true
}
// AuthorizedResourceControlUpdate ensure that the user can update a resource control object.
// It reuses the creation restrictions and adds extra checks.
// A non-administrator user cannot update a resource control where:
@ -56,7 +93,9 @@ func AuthorizedResourceControlUpdate(resourceControl *portainer.ResourceControl,
// AuthorizedResourceControlCreation ensure that the user can create a resource control object.
// A non-administrator user cannot create a resource control where:
// * the AdministratorsOnly flag is set
// * he wants to create a resource control without any user/team accesses
// * he wants to add more than one user in the user accesses
// * he wants tp add a user in the user accesses that is not corresponding to its id
// * he wants to add a team he is not a member of
func AuthorizedResourceControlCreation(resourceControl *portainer.ResourceControl, context *RestrictedRequestContext) bool {
if context.IsAdmin {
@ -69,6 +108,11 @@ func AuthorizedResourceControlCreation(resourceControl *portainer.ResourceContro
userAccessesCount := len(resourceControl.UserAccesses)
teamAccessesCount := len(resourceControl.TeamAccesses)
if userAccessesCount == 0 && teamAccessesCount == 0 {
return false
}
if userAccessesCount > 1 || (userAccessesCount == 1 && teamAccessesCount == 1) {
return false
}