mirror of
https://github.com/portainer/portainer.git
synced 2026-06-23 04:10:29 +00:00
chore(internal): export endpoints and authorizations so they can be shared between CE and EE BE-12893 (#2464)
This commit is contained in:
@@ -1,122 +1,32 @@
|
||||
package authorization
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/slicesx"
|
||||
"github.com/portainer/portainer/api/stacks/stackutils"
|
||||
"github.com/portainer/portainer/pkg/authorization"
|
||||
)
|
||||
|
||||
// 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 will create a new public resource control with the System flag set to true.
|
||||
// These kind of resource control 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 will create 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,
|
||||
}
|
||||
}
|
||||
var (
|
||||
NewAdministratorsOnlyResourceControl = authorization.NewAdministratorsOnlyResourceControl
|
||||
NewPrivateResourceControl = authorization.NewPrivateResourceControl
|
||||
NewSystemResourceControl = authorization.NewSystemResourceControl
|
||||
NewPublicResourceControl = authorization.NewPublicResourceControl
|
||||
NewRestrictedResourceControl = authorization.NewRestrictedResourceControl
|
||||
UserCanAccessResource = authorization.UserCanAccessResource
|
||||
GetResourceControlByResourceIDAndType = authorization.GetResourceControlByResourceIDAndType
|
||||
TeamIDs = authorization.TeamIDs
|
||||
)
|
||||
|
||||
func NewEmptyRestrictedResourceControl(resourceIdentifier string, resourceType portainer.ResourceControlType) *portainer.ResourceControl {
|
||||
return NewRestrictedResourceControl(resourceIdentifier, resourceType, []portainer.UserID{}, []portainer.TeamID{})
|
||||
}
|
||||
|
||||
// NewRestrictedResourceControl will create a new resource control with user and team accesses 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,
|
||||
}
|
||||
}
|
||||
|
||||
// DecorateStacks will iterate through a list of stacks, check for an associated resource control for each
|
||||
// stack and decorate the stack element if a resource control is found.
|
||||
func DecorateStacks(stacks []portainer.Stack, resourceControls []portainer.ResourceControl) []portainer.Stack {
|
||||
for idx, stack := range stacks {
|
||||
|
||||
resourceControl := GetResourceControlByResourceIDAndType(stackutils.ResourceControlID(stack.EndpointID, stack.Name), portainer.StackResourceControl, resourceControls)
|
||||
if resourceControl != nil {
|
||||
stacks[idx].ResourceControl = resourceControl
|
||||
@@ -130,7 +40,6 @@ func DecorateStacks(stacks []portainer.Stack, resourceControls []portainer.Resou
|
||||
// template and decorate the template element if a resource control is found.
|
||||
func DecorateCustomTemplates(templates []portainer.CustomTemplate, resourceControls []portainer.ResourceControl) []portainer.CustomTemplate {
|
||||
for idx, template := range templates {
|
||||
|
||||
resourceControl := GetResourceControlByResourceIDAndType(strconv.Itoa(int(template.ID)), portainer.CustomTemplateResourceControl, resourceControls)
|
||||
if resourceControl != nil {
|
||||
templates[idx].ResourceControl = resourceControl
|
||||
@@ -165,48 +74,3 @@ func FilterAuthorizedCustomTemplates(customTemplates []portainer.CustomTemplate,
|
||||
|
||||
return authorizedTemplates
|
||||
}
|
||||
|
||||
// UserCanAccessResource will valid that a user has permissions defined in the specified resource control
|
||||
// based on its identifier and the team(s) he is part of.
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,50 +2,24 @@ package endpointutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/portainer/portainer/api/dataservices"
|
||||
"github.com/portainer/portainer/api/kubernetes/cli"
|
||||
"github.com/portainer/portainer/pkg/endpoints"
|
||||
|
||||
log "github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// TODO: this file should be migrated to package/server-ce/pkg/endpoints
|
||||
|
||||
// IsLocalEndpoint returns true if this is a local environment(endpoint)
|
||||
func IsLocalEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return strings.HasPrefix(endpoint.URL, "unix://") ||
|
||||
strings.HasPrefix(endpoint.URL, "npipe://") ||
|
||||
endpoint.Type == portainer.KubernetesLocalEnvironment
|
||||
}
|
||||
|
||||
// IsKubernetesEndpoint returns true if this is a kubernetes environment(endpoint)
|
||||
func IsKubernetesEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.KubernetesLocalEnvironment ||
|
||||
endpoint.Type == portainer.AgentOnKubernetesEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment
|
||||
}
|
||||
|
||||
// IsDockerEndpoint returns true if this is a docker environment(endpoint)
|
||||
func IsDockerEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.DockerEnvironment ||
|
||||
endpoint.Type == portainer.AgentOnDockerEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnDockerEnvironment
|
||||
}
|
||||
|
||||
// IsEdgeEndpoint returns true if this is an Edge endpoint
|
||||
func IsEdgeEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.EdgeAgentOnDockerEnvironment || endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment
|
||||
}
|
||||
|
||||
// IsAgentEndpoint returns true if this is an Agent endpoint
|
||||
func IsAgentEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.AgentOnDockerEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnDockerEnvironment ||
|
||||
endpoint.Type == portainer.AgentOnKubernetesEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment
|
||||
}
|
||||
var (
|
||||
IsLocalEndpoint = endpoints.IsLocalEndpoint
|
||||
IsKubernetesEndpoint = endpoints.IsKubernetesEndpoint
|
||||
IsDockerEndpoint = endpoints.IsDockerEndpoint
|
||||
IsEdgeEndpoint = endpoints.IsEdgeEndpoint
|
||||
IsAgentEndpoint = endpoints.IsAgentEndpoint
|
||||
EndpointSet = endpoints.EndpointSet
|
||||
)
|
||||
|
||||
// EndpointPlatformType returns the type of the endpoint based on the environment and container engine
|
||||
func EndpointPlatformType(endpoint *portainer.Endpoint) portainer.PlatformType {
|
||||
@@ -85,17 +59,6 @@ func FilterByExcludeIDs(endpoints []portainer.Endpoint, excludeIds []portainer.E
|
||||
return filteredEndpoints
|
||||
}
|
||||
|
||||
// EndpointSet receives an environment(endpoint) array and returns a set
|
||||
func EndpointSet(endpointIDs []portainer.EndpointID) map[portainer.EndpointID]bool {
|
||||
set := map[portainer.EndpointID]bool{}
|
||||
|
||||
for _, endpointID := range endpointIDs {
|
||||
set[endpointID] = true
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func InitialIngressClassDetection(tx dataservices.DataStoreTx, endpoint *portainer.Endpoint, factory *cli.ClientFactory) {
|
||||
if endpoint.Kubernetes.Flags.IsServerIngressClassDetected {
|
||||
return
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
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
|
||||
})
|
||||
}
|
||||
@@ -1,11 +1,53 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
)
|
||||
|
||||
// IsLocalEndpoint returns true if this is a local environment(endpoint)
|
||||
func IsLocalEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return strings.HasPrefix(endpoint.URL, "unix://") ||
|
||||
strings.HasPrefix(endpoint.URL, "npipe://") ||
|
||||
endpoint.Type == portainer.KubernetesLocalEnvironment
|
||||
}
|
||||
|
||||
// IsKubernetesEndpoint returns true if this is a kubernetes environment(endpoint)
|
||||
func IsKubernetesEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.KubernetesLocalEnvironment ||
|
||||
endpoint.Type == portainer.AgentOnKubernetesEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment
|
||||
}
|
||||
|
||||
// IsDockerEndpoint returns true if this is a docker environment(endpoint)
|
||||
func IsDockerEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.DockerEnvironment ||
|
||||
endpoint.Type == portainer.AgentOnDockerEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnDockerEnvironment
|
||||
}
|
||||
|
||||
// IsAgentEndpoint returns true if this is an Agent endpoint
|
||||
func IsAgentEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.AgentOnDockerEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnDockerEnvironment ||
|
||||
endpoint.Type == portainer.AgentOnKubernetesEnvironment ||
|
||||
endpoint.Type == portainer.EdgeAgentOnKubernetesEnvironment
|
||||
}
|
||||
|
||||
// EndpointSet receives an environment(endpoint) array and returns a set
|
||||
func EndpointSet(endpointIDs []portainer.EndpointID) map[portainer.EndpointID]bool {
|
||||
set := map[portainer.EndpointID]bool{}
|
||||
|
||||
for _, endpointID := range endpointIDs {
|
||||
set[endpointID] = true
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
// IsRegularAgentEndpoint returns true if this is a regular agent endpoint
|
||||
func IsRegularAgentEndpoint(endpoint *portainer.Endpoint) bool {
|
||||
return endpoint.Type == portainer.AgentOnDockerEnvironment ||
|
||||
|
||||
Reference in New Issue
Block a user