From da41dbb79a8451a23f826334d6c4ad9b86533470 Mon Sep 17 00:00:00 2001 From: cong meng Date: Wed, 20 Jan 2021 15:19:35 +1300 Subject: [PATCH] fix(stack): stacks created via API are incorrectly marked as private with no owner (#3721) (#4725) Co-authored-by: Simon Meng --- api/http/handler/stacks/handler.go | 11 +++++++++++ api/http/handler/stacks/stack_create.go | 15 +++++++++++++-- api/internal/authorization/access_control.go | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/api/http/handler/stacks/handler.go b/api/http/handler/stacks/handler.go index c706afbfd..aafaca323 100644 --- a/api/http/handler/stacks/handler.go +++ b/api/http/handler/stacks/handler.go @@ -78,6 +78,17 @@ func (handler *Handler) userCanAccessStack(securityContext *security.RestrictedR return handler.userIsAdminOrEndpointAdmin(user, endpointID) } +func (handler *Handler) userIsAdmin(userID portainer.UserID) (bool, error) { + user, err := handler.DataStore.User().User(userID) + if err != nil { + return false, err + } + + isAdmin := user.Role == portainer.AdministratorRole + + return isAdmin, nil +} + func (handler *Handler) userIsAdminOrEndpointAdmin(user *portainer.User, endpointID portainer.EndpointID) (bool, error) { isAdmin := user.Role == portainer.AdministratorRole diff --git a/api/http/handler/stacks/stack_create.go b/api/http/handler/stacks/stack_create.go index c9f115ad1..a9fdf2f36 100644 --- a/api/http/handler/stacks/stack_create.go +++ b/api/http/handler/stacks/stack_create.go @@ -183,9 +183,20 @@ func (handler *Handler) isValidStackFile(stackFileContent []byte, settings *port } func (handler *Handler) decorateStackResponse(w http.ResponseWriter, stack *portainer.Stack, userID portainer.UserID) *httperror.HandlerError { - resourceControl := authorization.NewPrivateResourceControl(stack.Name, portainer.StackResourceControl, userID) + var resourceControl *portainer.ResourceControl - err := handler.DataStore.ResourceControl().CreateResourceControl(resourceControl) + isAdmin, err := handler.userIsAdmin(userID) + if err != nil { + return &httperror.HandlerError{http.StatusInternalServerError, "Unable to load user information from the database", err} + } + + if isAdmin { + resourceControl = authorization.NewAdministratorsOnlyResourceControl(stack.Name, portainer.StackResourceControl) + } else { + resourceControl = authorization.NewPrivateResourceControl(stack.Name, portainer.StackResourceControl, userID) + } + + err = handler.DataStore.ResourceControl().CreateResourceControl(resourceControl) if err != nil { return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist resource control inside the database", err} } diff --git a/api/internal/authorization/access_control.go b/api/internal/authorization/access_control.go index 0e2d91ab7..eab0a3b16 100644 --- a/api/internal/authorization/access_control.go +++ b/api/internal/authorization/access_control.go @@ -6,6 +6,21 @@ import ( "github.com/portainer/portainer/api" ) +// NewAdministratorsOnlyResourceControl will create a new administrators only resource control associated to the resource specified by the +// identifier and type parameters. +func NewAdministratorsOnlyResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType) *portainer.ResourceControl { + return &portainer.ResourceControl{ + Type: resourceType, + ResourceID: resourceIdentifier, + SubResourceIDs: []string{}, + UserAccesses: []portainer.UserResourceAccess{}, + TeamAccesses: []portainer.TeamResourceAccess{}, + AdministratorsOnly: true, + Public: false, + System: false, + } +} + // NewPrivateResourceControl will create a new private resource control associated to the resource specified by the // identifier and type parameters. It automatically assigns it to the user specified by the userID parameter. func NewPrivateResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userID portainer.UserID) *portainer.ResourceControl {