153 lines
5.4 KiB
Go
153 lines
5.4 KiB
Go
package authorization
|
|
|
|
import (
|
|
"slices"
|
|
|
|
portainer "github.com/portainer/portainer/api"
|
|
"github.com/portainer/portainer/api/slicesx"
|
|
)
|
|
|
|
// 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 {
|
|
return &portainer.ResourceControl{
|
|
Type: resourceType,
|
|
ResourceID: resourceIdentifier,
|
|
SubResourceIDs: []string{},
|
|
UserAccesses: []portainer.UserResourceAccess{
|
|
{
|
|
UserID: userID,
|
|
AccessLevel: portainer.ReadWriteAccessLevel,
|
|
},
|
|
},
|
|
TeamAccesses: []portainer.TeamResourceAccess{},
|
|
AdministratorsOnly: false,
|
|
Public: false,
|
|
System: false,
|
|
}
|
|
}
|
|
|
|
// NewSystemResourceControl creates a new public resource control with the System flag set to true.
|
|
// These resource controls are not persisted and are created on the fly by the Portainer API.
|
|
func NewSystemResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType) *portainer.ResourceControl {
|
|
return &portainer.ResourceControl{
|
|
Type: resourceType,
|
|
ResourceID: resourceIdentifier,
|
|
SubResourceIDs: []string{},
|
|
UserAccesses: []portainer.UserResourceAccess{},
|
|
TeamAccesses: []portainer.TeamResourceAccess{},
|
|
AdministratorsOnly: false,
|
|
Public: true,
|
|
System: true,
|
|
}
|
|
}
|
|
|
|
// NewPublicResourceControl creates a new public resource control.
|
|
func NewPublicResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType) *portainer.ResourceControl {
|
|
return &portainer.ResourceControl{
|
|
Type: resourceType,
|
|
ResourceID: resourceIdentifier,
|
|
SubResourceIDs: []string{},
|
|
UserAccesses: []portainer.UserResourceAccess{},
|
|
TeamAccesses: []portainer.TeamResourceAccess{},
|
|
AdministratorsOnly: false,
|
|
Public: true,
|
|
System: false,
|
|
}
|
|
}
|
|
|
|
// NewRestrictedResourceControl creates a new resource control with user and team access restrictions.
|
|
func NewRestrictedResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType, userIDs []portainer.UserID, teamIDs []portainer.TeamID) *portainer.ResourceControl {
|
|
userAccesses := make([]portainer.UserResourceAccess, 0)
|
|
teamAccesses := make([]portainer.TeamResourceAccess, 0)
|
|
|
|
for _, id := range userIDs {
|
|
access := portainer.UserResourceAccess{
|
|
UserID: id,
|
|
AccessLevel: portainer.ReadWriteAccessLevel,
|
|
}
|
|
|
|
userAccesses = append(userAccesses, access)
|
|
}
|
|
|
|
for _, id := range teamIDs {
|
|
access := portainer.TeamResourceAccess{
|
|
TeamID: id,
|
|
AccessLevel: portainer.ReadWriteAccessLevel,
|
|
}
|
|
|
|
teamAccesses = append(teamAccesses, access)
|
|
}
|
|
|
|
return &portainer.ResourceControl{
|
|
Type: resourceType,
|
|
ResourceID: resourceIdentifier,
|
|
SubResourceIDs: []string{},
|
|
UserAccesses: userAccesses,
|
|
TeamAccesses: teamAccesses,
|
|
AdministratorsOnly: false,
|
|
Public: false,
|
|
System: false,
|
|
}
|
|
}
|
|
|
|
// UserCanAccessResource validates that a user has permissions defined in the specified resource control
|
|
// based on their identifier and the team(s) they belong to.
|
|
func UserCanAccessResource(userID portainer.UserID, userTeamIDs []portainer.TeamID, resourceControl *portainer.ResourceControl) bool {
|
|
if resourceControl == nil {
|
|
return false
|
|
}
|
|
|
|
for _, authorizedUserAccess := range resourceControl.UserAccesses {
|
|
if userID == authorizedUserAccess.UserID {
|
|
return true
|
|
}
|
|
}
|
|
|
|
for _, authorizedTeamAccess := range resourceControl.TeamAccesses {
|
|
if slices.Contains(userTeamIDs, authorizedTeamAccess.TeamID) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return resourceControl.Public
|
|
}
|
|
|
|
// GetResourceControlByResourceIDAndType retrieves the first matching resource control in a set of resource controls
|
|
// based on the specified id and resource type parameters.
|
|
func GetResourceControlByResourceIDAndType(resourceID string, resourceType portainer.ResourceControlType, resourceControls []portainer.ResourceControl) *portainer.ResourceControl {
|
|
for i := range resourceControls {
|
|
if resourceID == resourceControls[i].ResourceID && resourceType == resourceControls[i].Type {
|
|
return &resourceControls[i]
|
|
}
|
|
|
|
if slices.Contains(resourceControls[i].SubResourceIDs, resourceID) {
|
|
return &resourceControls[i]
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// TeamIDs extracts the TeamID from each membership.
|
|
func TeamIDs(memberships []portainer.TeamMembership) []portainer.TeamID {
|
|
return slicesx.Map(memberships, func(m portainer.TeamMembership) portainer.TeamID {
|
|
return m.TeamID
|
|
})
|
|
}
|