mirror of https://github.com/portainer/portainer
fix(api): review security policies when creating/updating a resource control (#1964)
parent
e3d564325b
commit
1e12057cdd
|
@ -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}
|
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
|
resourceControl.AdministratorsOnly = payload.AdministratorsOnly
|
||||||
|
|
||||||
var userAccesses = make([]portainer.UserResourceAccess, 0)
|
var userAccesses = make([]portainer.UserResourceAccess, 0)
|
||||||
|
@ -65,11 +74,6 @@ func (handler *Handler) resourceControlUpdate(w http.ResponseWriter, r *http.Req
|
||||||
}
|
}
|
||||||
resourceControl.TeamAccesses = teamAccesses
|
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) {
|
if !security.AuthorizedResourceControlUpdate(resourceControl, securityContext) {
|
||||||
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the resource control", portainer.ErrResourceAccessDenied}
|
return &httperror.HandlerError{http.StatusForbidden, "Permission denied to update the resource control", portainer.ErrResourceAccessDenied}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,43 @@ func AuthorizedResourceControlDeletion(resourceControl *portainer.ResourceContro
|
||||||
return false
|
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.
|
// AuthorizedResourceControlUpdate ensure that the user can update a resource control object.
|
||||||
// It reuses the creation restrictions and adds extra checks.
|
// It reuses the creation restrictions and adds extra checks.
|
||||||
// A non-administrator user cannot update a resource control where:
|
// 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.
|
// AuthorizedResourceControlCreation ensure that the user can create a resource control object.
|
||||||
// A non-administrator user cannot create a resource control where:
|
// A non-administrator user cannot create a resource control where:
|
||||||
// * the AdministratorsOnly flag is set
|
// * 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 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
|
// * he wants to add a team he is not a member of
|
||||||
func AuthorizedResourceControlCreation(resourceControl *portainer.ResourceControl, context *RestrictedRequestContext) bool {
|
func AuthorizedResourceControlCreation(resourceControl *portainer.ResourceControl, context *RestrictedRequestContext) bool {
|
||||||
if context.IsAdmin {
|
if context.IsAdmin {
|
||||||
|
@ -69,6 +108,11 @@ func AuthorizedResourceControlCreation(resourceControl *portainer.ResourceContro
|
||||||
|
|
||||||
userAccessesCount := len(resourceControl.UserAccesses)
|
userAccessesCount := len(resourceControl.UserAccesses)
|
||||||
teamAccessesCount := len(resourceControl.TeamAccesses)
|
teamAccessesCount := len(resourceControl.TeamAccesses)
|
||||||
|
|
||||||
|
if userAccessesCount == 0 && teamAccessesCount == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if userAccessesCount > 1 || (userAccessesCount == 1 && teamAccessesCount == 1) {
|
if userAccessesCount > 1 || (userAccessesCount == 1 && teamAccessesCount == 1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue