2018-06-11 13:13:19 +00:00
package resourcecontrols
import (
2019-11-12 23:41:42 +00:00
"errors"
2018-06-11 13:13:19 +00:00
"net/http"
2018-09-10 10:01:38 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
2021-02-23 03:21:39 +00:00
portainer "github.com/portainer/portainer/api"
2020-07-07 21:57:52 +00:00
bolterrors "github.com/portainer/portainer/api/bolt/errors"
httperrors "github.com/portainer/portainer/api/http/errors"
2019-03-21 01:20:14 +00:00
"github.com/portainer/portainer/api/http/security"
2018-06-11 13:13:19 +00:00
)
type resourceControlUpdatePayload struct {
2021-02-23 03:21:39 +00:00
// Permit access to the associated resource to any user
Public bool ` example:"true" `
// List of user identifiers with access to the associated resource
Users [ ] int ` example:"4" `
// List of team identifiers with access to the associated resource
Teams [ ] int ` example:"7" `
// Permit access to resource only to admins
AdministratorsOnly bool ` example:"true" `
2018-06-11 13:13:19 +00:00
}
func ( payload * resourceControlUpdatePayload ) Validate ( r * http . Request ) error {
2019-11-12 23:41:42 +00:00
if len ( payload . Users ) == 0 && len ( payload . Teams ) == 0 && ! payload . Public && ! payload . AdministratorsOnly {
return errors . New ( "invalid payload: must specify Users, Teams, Public or AdministratorsOnly" )
}
if payload . Public && payload . AdministratorsOnly {
return errors . New ( "invalid payload: cannot set public and administrators only" )
2018-06-11 13:13:19 +00:00
}
return nil
}
2021-02-23 03:21:39 +00:00
// @id ResourceControlUpdate
// @summary Update a resource control
// @description Update a resource control
// @description **Access policy**: restricted
// @tags resource_controls
// @security jwt
// @accept json
// @produce json
// @param id path int true "Resource control identifier"
// @param body body resourceControlUpdatePayload true "Resource control details"
// @success 200 {object} portainer.ResourceControl "Success"
// @failure 400 "Invalid request"
// @failure 403 "Unauthorized"
// @failure 404 "Resource control not found"
// @failure 500 "Server error"
// @router /resource_controls/{id} [put]
2018-06-11 13:13:19 +00:00
func ( handler * Handler ) resourceControlUpdate ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
resourceControlID , err := request . RetrieveNumericRouteVariableValue ( r , "id" )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid resource control identifier route variable" , err }
}
var payload resourceControlUpdatePayload
err = request . DecodeAndValidateJSONPayload ( r , & payload )
if err != nil {
return & httperror . HandlerError { http . StatusBadRequest , "Invalid request payload" , err }
}
2020-05-20 05:23:15 +00:00
resourceControl , err := handler . DataStore . ResourceControl ( ) . ResourceControl ( portainer . ResourceControlID ( resourceControlID ) )
2020-07-07 21:57:52 +00:00
if err == bolterrors . ErrObjectNotFound {
2018-06-11 13:13:19 +00:00
return & httperror . HandlerError { http . StatusNotFound , "Unable to find a resource control with the specified identifier inside the database" , err }
} else if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to find a resource control with with the specified identifier inside the database" , err }
}
2018-06-11 15:58:46 +00:00
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 ) {
2020-07-07 21:57:52 +00:00
return & httperror . HandlerError { http . StatusForbidden , "Permission denied to access the resource control" , httperrors . ErrResourceAccessDenied }
2018-06-11 15:58:46 +00:00
}
2018-08-19 05:57:28 +00:00
resourceControl . Public = payload . Public
2019-11-12 23:41:42 +00:00
resourceControl . AdministratorsOnly = payload . AdministratorsOnly
2018-06-11 13:13:19 +00:00
var userAccesses = make ( [ ] portainer . UserResourceAccess , 0 )
for _ , v := range payload . Users {
userAccess := portainer . UserResourceAccess {
UserID : portainer . UserID ( v ) ,
AccessLevel : portainer . ReadWriteAccessLevel ,
}
userAccesses = append ( userAccesses , userAccess )
}
resourceControl . UserAccesses = userAccesses
var teamAccesses = make ( [ ] portainer . TeamResourceAccess , 0 )
for _ , v := range payload . Teams {
teamAccess := portainer . TeamResourceAccess {
TeamID : portainer . TeamID ( v ) ,
AccessLevel : portainer . ReadWriteAccessLevel ,
}
teamAccesses = append ( teamAccesses , teamAccess )
}
resourceControl . TeamAccesses = teamAccesses
if ! security . AuthorizedResourceControlUpdate ( resourceControl , securityContext ) {
2020-07-07 21:57:52 +00:00
return & httperror . HandlerError { http . StatusForbidden , "Permission denied to update the resource control" , httperrors . ErrResourceAccessDenied }
2018-06-11 13:13:19 +00:00
}
2020-05-20 05:23:15 +00:00
err = handler . DataStore . ResourceControl ( ) . UpdateResourceControl ( resourceControl . ID , resourceControl )
2018-06-11 13:13:19 +00:00
if err != nil {
return & httperror . HandlerError { http . StatusInternalServerError , "Unable to persist resource control changes inside the database" , err }
}
return response . JSON ( w , resourceControl )
}