1410 lines
54 KiB
Go
1410 lines
54 KiB
Go
package authorization
|
|
|
|
import (
|
|
portainer "github.com/portainer/portainer/api"
|
|
)
|
|
|
|
// Service represents a service used to
|
|
// update authorizations associated to a user or team.
|
|
type (
|
|
Service struct {
|
|
dataStore portainer.DataStore
|
|
authEventHandlers map[string]portainer.AuthEventHandler
|
|
}
|
|
)
|
|
|
|
// NewService returns a point to a new Service instance.
|
|
func NewService(dataStore portainer.DataStore) *Service {
|
|
return &Service{
|
|
dataStore: dataStore,
|
|
authEventHandlers: make(map[string]portainer.AuthEventHandler),
|
|
}
|
|
}
|
|
|
|
// DefaultEndpointAuthorizationsForEndpointAdministratorRole returns the default endpoint authorizations
|
|
// associated to the endpoint administrator role.
|
|
func DefaultEndpointAuthorizationsForEndpointAdministratorRole() portainer.Authorizations {
|
|
return unionAuthorizations(map[portainer.Authorization]bool{
|
|
portainer.OperationDockerContainerArchiveInfo: true,
|
|
portainer.OperationDockerContainerList: true,
|
|
portainer.OperationDockerContainerExport: true,
|
|
portainer.OperationDockerContainerChanges: true,
|
|
portainer.OperationDockerContainerInspect: true,
|
|
portainer.OperationDockerContainerTop: true,
|
|
portainer.OperationDockerContainerLogs: true,
|
|
portainer.OperationDockerContainerStats: true,
|
|
portainer.OperationDockerContainerAttachWebsocket: true,
|
|
portainer.OperationDockerContainerArchive: true,
|
|
portainer.OperationDockerContainerCreate: true,
|
|
portainer.OperationDockerContainerPrune: true,
|
|
portainer.OperationDockerContainerKill: true,
|
|
portainer.OperationDockerContainerPause: true,
|
|
portainer.OperationDockerContainerUnpause: true,
|
|
portainer.OperationDockerContainerRestart: true,
|
|
portainer.OperationDockerContainerStart: true,
|
|
portainer.OperationDockerContainerStop: true,
|
|
portainer.OperationDockerContainerWait: true,
|
|
portainer.OperationDockerContainerResize: true,
|
|
portainer.OperationDockerContainerAttach: true,
|
|
portainer.OperationDockerContainerExec: true,
|
|
portainer.OperationDockerContainerRename: true,
|
|
portainer.OperationDockerContainerUpdate: true,
|
|
portainer.OperationDockerContainerPutContainerArchive: true,
|
|
portainer.OperationDockerContainerDelete: true,
|
|
portainer.OperationDockerImageList: true,
|
|
portainer.OperationDockerImageSearch: true,
|
|
portainer.OperationDockerImageGetAll: true,
|
|
portainer.OperationDockerImageGet: true,
|
|
portainer.OperationDockerImageHistory: true,
|
|
portainer.OperationDockerImageInspect: true,
|
|
portainer.OperationDockerImageLoad: true,
|
|
portainer.OperationDockerImageCreate: true,
|
|
portainer.OperationDockerImagePrune: true,
|
|
portainer.OperationDockerImagePush: true,
|
|
portainer.OperationDockerImageTag: true,
|
|
portainer.OperationDockerImageDelete: true,
|
|
portainer.OperationDockerImageCommit: true,
|
|
portainer.OperationDockerImageBuild: true,
|
|
portainer.OperationDockerNetworkList: true,
|
|
portainer.OperationDockerNetworkInspect: true,
|
|
portainer.OperationDockerNetworkCreate: true,
|
|
portainer.OperationDockerNetworkConnect: true,
|
|
portainer.OperationDockerNetworkDisconnect: true,
|
|
portainer.OperationDockerNetworkPrune: true,
|
|
portainer.OperationDockerNetworkDelete: true,
|
|
portainer.OperationDockerVolumeList: true,
|
|
portainer.OperationDockerVolumeInspect: true,
|
|
portainer.OperationDockerVolumeCreate: true,
|
|
portainer.OperationDockerVolumePrune: true,
|
|
portainer.OperationDockerVolumeDelete: true,
|
|
portainer.OperationDockerExecInspect: true,
|
|
portainer.OperationDockerExecStart: true,
|
|
portainer.OperationDockerExecResize: true,
|
|
portainer.OperationDockerSwarmInspect: true,
|
|
portainer.OperationDockerSwarmUnlockKey: true,
|
|
portainer.OperationDockerSwarmInit: true,
|
|
portainer.OperationDockerSwarmJoin: true,
|
|
portainer.OperationDockerSwarmLeave: true,
|
|
portainer.OperationDockerSwarmUpdate: true,
|
|
portainer.OperationDockerSwarmUnlock: true,
|
|
portainer.OperationDockerNodeList: true,
|
|
portainer.OperationDockerNodeInspect: true,
|
|
portainer.OperationDockerNodeUpdate: true,
|
|
portainer.OperationDockerNodeDelete: true,
|
|
portainer.OperationDockerServiceList: true,
|
|
portainer.OperationDockerServiceInspect: true,
|
|
portainer.OperationDockerServiceLogs: true,
|
|
portainer.OperationDockerServiceCreate: true,
|
|
portainer.OperationDockerServiceUpdate: true,
|
|
portainer.OperationDockerServiceForceUpdateService: true,
|
|
portainer.OperationDockerServiceDelete: true,
|
|
portainer.OperationDockerSecretList: true,
|
|
portainer.OperationDockerSecretInspect: true,
|
|
portainer.OperationDockerSecretCreate: true,
|
|
portainer.OperationDockerSecretUpdate: true,
|
|
portainer.OperationDockerSecretDelete: true,
|
|
portainer.OperationDockerConfigList: true,
|
|
portainer.OperationDockerConfigInspect: true,
|
|
portainer.OperationDockerConfigCreate: true,
|
|
portainer.OperationDockerConfigUpdate: true,
|
|
portainer.OperationDockerConfigDelete: true,
|
|
portainer.OperationDockerTaskList: true,
|
|
portainer.OperationDockerTaskInspect: true,
|
|
portainer.OperationDockerTaskLogs: true,
|
|
portainer.OperationDockerPluginList: true,
|
|
portainer.OperationDockerPluginPrivileges: true,
|
|
portainer.OperationDockerPluginInspect: true,
|
|
portainer.OperationDockerPluginPull: true,
|
|
portainer.OperationDockerPluginCreate: true,
|
|
portainer.OperationDockerPluginEnable: true,
|
|
portainer.OperationDockerPluginDisable: true,
|
|
portainer.OperationDockerPluginPush: true,
|
|
portainer.OperationDockerPluginUpgrade: true,
|
|
portainer.OperationDockerPluginSet: true,
|
|
portainer.OperationDockerPluginDelete: true,
|
|
portainer.OperationDockerSessionStart: true,
|
|
portainer.OperationDockerDistributionInspect: true,
|
|
portainer.OperationDockerBuildPrune: true,
|
|
portainer.OperationDockerBuildCancel: true,
|
|
portainer.OperationDockerPing: true,
|
|
portainer.OperationDockerInfo: true,
|
|
portainer.OperationDockerVersion: true,
|
|
portainer.OperationDockerEvents: true,
|
|
portainer.OperationDockerSystem: true,
|
|
portainer.OperationDockerUndefined: true,
|
|
portainer.OperationDockerAgentPing: true,
|
|
portainer.OperationDockerAgentList: true,
|
|
portainer.OperationDockerAgentHostInfo: true,
|
|
portainer.OperationDockerAgentBrowseDelete: true,
|
|
portainer.OperationDockerAgentBrowseGet: true,
|
|
portainer.OperationDockerAgentBrowseList: true,
|
|
portainer.OperationDockerAgentBrowsePut: true,
|
|
portainer.OperationDockerAgentBrowseRename: true,
|
|
portainer.OperationDockerAgentUndefined: true,
|
|
portainer.OperationPortainerResourceControlCreate: true,
|
|
portainer.OperationPortainerResourceControlUpdate: true,
|
|
portainer.OperationPortainerStackList: true,
|
|
portainer.OperationPortainerStackInspect: true,
|
|
portainer.OperationPortainerStackFile: true,
|
|
portainer.OperationPortainerStackCreate: true,
|
|
portainer.OperationPortainerStackMigrate: true,
|
|
portainer.OperationPortainerStackUpdate: true,
|
|
portainer.OperationPortainerStackDelete: true,
|
|
portainer.OperationPortainerWebsocketExec: true,
|
|
portainer.OperationPortainerWebhookList: true,
|
|
portainer.OperationPortainerWebhookCreate: true,
|
|
portainer.OperationPortainerWebhookDelete: true,
|
|
portainer.OperationPortainerEndpointUpdateSettings: true,
|
|
portainer.OperationIntegrationStoridgeAdmin: true,
|
|
portainer.EndpointResourcesAccess: true,
|
|
},
|
|
DefaultK8sClusterAuthorizations()[portainer.RoleIDEndpointAdmin],
|
|
DefaultAzureAuthorizations()[portainer.RoleIDEndpointAdmin],
|
|
)
|
|
}
|
|
|
|
// DefaultEndpointAuthorizationsForHelpDeskRole returns the default endpoint authorizations
|
|
// associated to the helpdesk role.
|
|
func DefaultEndpointAuthorizationsForHelpDeskRole() portainer.Authorizations {
|
|
authorizations := unionAuthorizations(map[portainer.Authorization]bool{
|
|
portainer.OperationDockerContainerArchiveInfo: true,
|
|
portainer.OperationDockerContainerList: true,
|
|
portainer.OperationDockerContainerChanges: true,
|
|
portainer.OperationDockerContainerInspect: true,
|
|
portainer.OperationDockerContainerTop: true,
|
|
portainer.OperationDockerContainerLogs: true,
|
|
portainer.OperationDockerContainerStats: true,
|
|
portainer.OperationDockerImageList: true,
|
|
portainer.OperationDockerImageSearch: true,
|
|
portainer.OperationDockerImageGetAll: true,
|
|
portainer.OperationDockerImageGet: true,
|
|
portainer.OperationDockerImageHistory: true,
|
|
portainer.OperationDockerImageInspect: true,
|
|
portainer.OperationDockerNetworkList: true,
|
|
portainer.OperationDockerNetworkInspect: true,
|
|
portainer.OperationDockerVolumeList: true,
|
|
portainer.OperationDockerVolumeInspect: true,
|
|
portainer.OperationDockerSwarmInspect: true,
|
|
portainer.OperationDockerNodeList: true,
|
|
portainer.OperationDockerNodeInspect: true,
|
|
portainer.OperationDockerServiceList: true,
|
|
portainer.OperationDockerServiceInspect: true,
|
|
portainer.OperationDockerServiceLogs: true,
|
|
portainer.OperationDockerSecretList: true,
|
|
portainer.OperationDockerSecretInspect: true,
|
|
portainer.OperationDockerConfigList: true,
|
|
portainer.OperationDockerConfigInspect: true,
|
|
portainer.OperationDockerTaskList: true,
|
|
portainer.OperationDockerTaskInspect: true,
|
|
portainer.OperationDockerTaskLogs: true,
|
|
portainer.OperationDockerPluginList: true,
|
|
portainer.OperationDockerDistributionInspect: true,
|
|
portainer.OperationDockerPing: true,
|
|
portainer.OperationDockerInfo: true,
|
|
portainer.OperationDockerVersion: true,
|
|
portainer.OperationDockerEvents: true,
|
|
portainer.OperationDockerSystem: true,
|
|
portainer.OperationDockerAgentPing: true,
|
|
portainer.OperationDockerAgentList: true,
|
|
portainer.OperationDockerAgentHostInfo: true,
|
|
portainer.OperationPortainerStackList: true,
|
|
portainer.OperationPortainerStackInspect: true,
|
|
portainer.OperationPortainerStackFile: true,
|
|
portainer.OperationPortainerWebhookList: true,
|
|
portainer.EndpointResourcesAccess: true,
|
|
},
|
|
DefaultK8sClusterAuthorizations()[portainer.RoleIDHelpdesk],
|
|
DefaultAzureAuthorizations()[portainer.RoleIDHelpdesk],
|
|
)
|
|
|
|
return authorizations
|
|
}
|
|
|
|
// DefaultEndpointAuthorizationsForOperatorRole returns the default endpoint authorizations
|
|
// associated to the Operator role.
|
|
func DefaultEndpointAuthorizationsForOperatorRole() portainer.Authorizations {
|
|
authorizations := unionAuthorizations(map[portainer.Authorization]bool{
|
|
portainer.OperationDockerContainerArchiveInfo: true,
|
|
portainer.OperationDockerContainerList: true,
|
|
portainer.OperationDockerContainerChanges: true,
|
|
portainer.OperationDockerContainerInspect: true,
|
|
portainer.OperationDockerContainerTop: true,
|
|
portainer.OperationDockerContainerLogs: true,
|
|
portainer.OperationDockerContainerStats: true,
|
|
portainer.OperationDockerContainerKill: true,
|
|
portainer.OperationDockerContainerPause: true,
|
|
portainer.OperationDockerContainerUnpause: true,
|
|
portainer.OperationDockerContainerRestart: true,
|
|
portainer.OperationDockerContainerStart: true,
|
|
portainer.OperationDockerContainerStop: true,
|
|
portainer.OperationDockerContainerAttach: true,
|
|
portainer.OperationDockerContainerExec: true,
|
|
portainer.OperationDockerContainerResize: true,
|
|
portainer.OperationDockerImageList: true,
|
|
portainer.OperationDockerImageSearch: true,
|
|
portainer.OperationDockerImageGetAll: true,
|
|
portainer.OperationDockerImageGet: true,
|
|
portainer.OperationDockerImageHistory: true,
|
|
portainer.OperationDockerImageInspect: true,
|
|
portainer.OperationDockerNetworkList: true,
|
|
portainer.OperationDockerNetworkInspect: true,
|
|
portainer.OperationDockerVolumeList: true,
|
|
portainer.OperationDockerVolumeInspect: true,
|
|
portainer.OperationDockerExecStart: true,
|
|
portainer.OperationDockerExecResize: true,
|
|
portainer.OperationDockerSwarmInspect: true,
|
|
portainer.OperationDockerNodeList: true,
|
|
portainer.OperationDockerNodeInspect: true,
|
|
portainer.OperationDockerServiceList: true,
|
|
portainer.OperationDockerServiceInspect: true,
|
|
portainer.OperationDockerServiceLogs: true,
|
|
portainer.OperationDockerServiceForceUpdateService: true,
|
|
portainer.OperationDockerSecretList: true,
|
|
portainer.OperationDockerSecretInspect: true,
|
|
portainer.OperationDockerConfigList: true,
|
|
portainer.OperationDockerConfigInspect: true,
|
|
portainer.OperationDockerTaskList: true,
|
|
portainer.OperationDockerTaskInspect: true,
|
|
portainer.OperationDockerTaskLogs: true,
|
|
portainer.OperationDockerPluginList: true,
|
|
portainer.OperationDockerDistributionInspect: true,
|
|
portainer.OperationDockerPing: true,
|
|
portainer.OperationDockerInfo: true,
|
|
portainer.OperationDockerVersion: true,
|
|
portainer.OperationDockerEvents: true,
|
|
portainer.OperationDockerSystem: true,
|
|
portainer.OperationDockerAgentPing: true,
|
|
portainer.OperationDockerAgentList: true,
|
|
portainer.OperationDockerAgentHostInfo: true,
|
|
portainer.OperationPortainerStackList: true,
|
|
portainer.OperationPortainerStackInspect: true,
|
|
portainer.OperationPortainerStackFile: true,
|
|
portainer.OperationPortainerWebsocketExec: true,
|
|
portainer.OperationPortainerWebhookList: true,
|
|
portainer.EndpointResourcesAccess: true,
|
|
},
|
|
DefaultK8sClusterAuthorizations()[portainer.RoleIDOperator],
|
|
DefaultAzureAuthorizations()[portainer.RoleIDOperator],
|
|
)
|
|
|
|
return authorizations
|
|
}
|
|
|
|
// DefaultEndpointAuthorizationsForStandardUserRole returns the default endpoint authorizations
|
|
// associated to the standard user role.
|
|
func DefaultEndpointAuthorizationsForStandardUserRole() portainer.Authorizations {
|
|
authorizations := unionAuthorizations(map[portainer.Authorization]bool{
|
|
portainer.OperationDockerContainerArchiveInfo: true,
|
|
portainer.OperationDockerContainerList: true,
|
|
portainer.OperationDockerContainerExport: true,
|
|
portainer.OperationDockerContainerChanges: true,
|
|
portainer.OperationDockerContainerInspect: true,
|
|
portainer.OperationDockerContainerTop: true,
|
|
portainer.OperationDockerContainerLogs: true,
|
|
portainer.OperationDockerContainerStats: true,
|
|
portainer.OperationDockerContainerAttachWebsocket: true,
|
|
portainer.OperationDockerContainerArchive: true,
|
|
portainer.OperationDockerContainerCreate: true,
|
|
portainer.OperationDockerContainerKill: true,
|
|
portainer.OperationDockerContainerPause: true,
|
|
portainer.OperationDockerContainerUnpause: true,
|
|
portainer.OperationDockerContainerRestart: true,
|
|
portainer.OperationDockerContainerStart: true,
|
|
portainer.OperationDockerContainerStop: true,
|
|
portainer.OperationDockerContainerWait: true,
|
|
portainer.OperationDockerContainerResize: true,
|
|
portainer.OperationDockerContainerAttach: true,
|
|
portainer.OperationDockerContainerExec: true,
|
|
portainer.OperationDockerContainerRename: true,
|
|
portainer.OperationDockerContainerUpdate: true,
|
|
portainer.OperationDockerContainerPutContainerArchive: true,
|
|
portainer.OperationDockerContainerDelete: true,
|
|
portainer.OperationDockerImageList: true,
|
|
portainer.OperationDockerImageSearch: true,
|
|
portainer.OperationDockerImageGetAll: true,
|
|
portainer.OperationDockerImageGet: true,
|
|
portainer.OperationDockerImageHistory: true,
|
|
portainer.OperationDockerImageInspect: true,
|
|
portainer.OperationDockerImageLoad: true,
|
|
portainer.OperationDockerImageCreate: true,
|
|
portainer.OperationDockerImagePush: true,
|
|
portainer.OperationDockerImageTag: true,
|
|
portainer.OperationDockerImageDelete: true,
|
|
portainer.OperationDockerImageCommit: true,
|
|
portainer.OperationDockerImageBuild: true,
|
|
portainer.OperationDockerNetworkList: true,
|
|
portainer.OperationDockerNetworkInspect: true,
|
|
portainer.OperationDockerNetworkCreate: true,
|
|
portainer.OperationDockerNetworkConnect: true,
|
|
portainer.OperationDockerNetworkDisconnect: true,
|
|
portainer.OperationDockerNetworkDelete: true,
|
|
portainer.OperationDockerVolumeList: true,
|
|
portainer.OperationDockerVolumeInspect: true,
|
|
portainer.OperationDockerVolumeCreate: true,
|
|
portainer.OperationDockerVolumeDelete: true,
|
|
portainer.OperationDockerExecInspect: true,
|
|
portainer.OperationDockerExecStart: true,
|
|
portainer.OperationDockerExecResize: true,
|
|
portainer.OperationDockerSwarmInspect: true,
|
|
portainer.OperationDockerSwarmUnlockKey: true,
|
|
portainer.OperationDockerSwarmInit: true,
|
|
portainer.OperationDockerSwarmJoin: true,
|
|
portainer.OperationDockerSwarmLeave: true,
|
|
portainer.OperationDockerSwarmUpdate: true,
|
|
portainer.OperationDockerSwarmUnlock: true,
|
|
portainer.OperationDockerNodeList: true,
|
|
portainer.OperationDockerNodeInspect: true,
|
|
portainer.OperationDockerNodeUpdate: true,
|
|
portainer.OperationDockerNodeDelete: true,
|
|
portainer.OperationDockerServiceList: true,
|
|
portainer.OperationDockerServiceInspect: true,
|
|
portainer.OperationDockerServiceLogs: true,
|
|
portainer.OperationDockerServiceCreate: true,
|
|
portainer.OperationDockerServiceUpdate: true,
|
|
portainer.OperationDockerServiceForceUpdateService: true,
|
|
portainer.OperationDockerServiceDelete: true,
|
|
portainer.OperationDockerSecretList: true,
|
|
portainer.OperationDockerSecretInspect: true,
|
|
portainer.OperationDockerSecretCreate: true,
|
|
portainer.OperationDockerSecretUpdate: true,
|
|
portainer.OperationDockerSecretDelete: true,
|
|
portainer.OperationDockerConfigList: true,
|
|
portainer.OperationDockerConfigInspect: true,
|
|
portainer.OperationDockerConfigCreate: true,
|
|
portainer.OperationDockerConfigUpdate: true,
|
|
portainer.OperationDockerConfigDelete: true,
|
|
portainer.OperationDockerTaskList: true,
|
|
portainer.OperationDockerTaskInspect: true,
|
|
portainer.OperationDockerTaskLogs: true,
|
|
portainer.OperationDockerPluginList: true,
|
|
portainer.OperationDockerPluginPrivileges: true,
|
|
portainer.OperationDockerPluginInspect: true,
|
|
portainer.OperationDockerPluginPull: true,
|
|
portainer.OperationDockerPluginCreate: true,
|
|
portainer.OperationDockerPluginEnable: true,
|
|
portainer.OperationDockerPluginDisable: true,
|
|
portainer.OperationDockerPluginPush: true,
|
|
portainer.OperationDockerPluginUpgrade: true,
|
|
portainer.OperationDockerPluginSet: true,
|
|
portainer.OperationDockerPluginDelete: true,
|
|
portainer.OperationDockerSessionStart: true,
|
|
portainer.OperationDockerDistributionInspect: true,
|
|
portainer.OperationDockerBuildPrune: true,
|
|
portainer.OperationDockerBuildCancel: true,
|
|
portainer.OperationDockerPing: true,
|
|
portainer.OperationDockerInfo: true,
|
|
portainer.OperationDockerVersion: true,
|
|
portainer.OperationDockerEvents: true,
|
|
portainer.OperationDockerSystem: true,
|
|
portainer.OperationDockerUndefined: true,
|
|
portainer.OperationDockerAgentPing: true,
|
|
portainer.OperationDockerAgentList: true,
|
|
portainer.OperationDockerAgentHostInfo: true,
|
|
portainer.OperationDockerAgentUndefined: true,
|
|
portainer.OperationPortainerResourceControlUpdate: true,
|
|
portainer.OperationPortainerStackList: true,
|
|
portainer.OperationPortainerStackInspect: true,
|
|
portainer.OperationPortainerStackFile: true,
|
|
portainer.OperationPortainerStackCreate: true,
|
|
portainer.OperationPortainerStackMigrate: true,
|
|
portainer.OperationPortainerStackUpdate: true,
|
|
portainer.OperationPortainerStackDelete: true,
|
|
portainer.OperationPortainerWebsocketExec: true,
|
|
portainer.OperationPortainerWebhookList: true,
|
|
portainer.OperationPortainerWebhookCreate: true,
|
|
},
|
|
DefaultK8sClusterAuthorizations()[portainer.RoleIDStandardUser],
|
|
DefaultAzureAuthorizations()[portainer.RoleIDStandardUser],
|
|
)
|
|
|
|
return authorizations
|
|
}
|
|
|
|
// DefaultEndpointAuthorizationsForReadOnlyUserRole returns the default endpoint authorizations
|
|
// associated to the readonly user role.
|
|
func DefaultEndpointAuthorizationsForReadOnlyUserRole() portainer.Authorizations {
|
|
authorizations := unionAuthorizations(map[portainer.Authorization]bool{
|
|
portainer.OperationDockerContainerArchiveInfo: true,
|
|
portainer.OperationDockerContainerList: true,
|
|
portainer.OperationDockerContainerChanges: true,
|
|
portainer.OperationDockerContainerInspect: true,
|
|
portainer.OperationDockerContainerTop: true,
|
|
portainer.OperationDockerContainerLogs: true,
|
|
portainer.OperationDockerContainerStats: true,
|
|
portainer.OperationDockerImageList: true,
|
|
portainer.OperationDockerImageSearch: true,
|
|
portainer.OperationDockerImageGetAll: true,
|
|
portainer.OperationDockerImageGet: true,
|
|
portainer.OperationDockerImageHistory: true,
|
|
portainer.OperationDockerImageInspect: true,
|
|
portainer.OperationDockerNetworkList: true,
|
|
portainer.OperationDockerNetworkInspect: true,
|
|
portainer.OperationDockerVolumeList: true,
|
|
portainer.OperationDockerVolumeInspect: true,
|
|
portainer.OperationDockerSwarmInspect: true,
|
|
portainer.OperationDockerNodeList: true,
|
|
portainer.OperationDockerNodeInspect: true,
|
|
portainer.OperationDockerServiceList: true,
|
|
portainer.OperationDockerServiceInspect: true,
|
|
portainer.OperationDockerServiceLogs: true,
|
|
portainer.OperationDockerSecretList: true,
|
|
portainer.OperationDockerSecretInspect: true,
|
|
portainer.OperationDockerConfigList: true,
|
|
portainer.OperationDockerConfigInspect: true,
|
|
portainer.OperationDockerTaskList: true,
|
|
portainer.OperationDockerTaskInspect: true,
|
|
portainer.OperationDockerTaskLogs: true,
|
|
portainer.OperationDockerPluginList: true,
|
|
portainer.OperationDockerDistributionInspect: true,
|
|
portainer.OperationDockerPing: true,
|
|
portainer.OperationDockerInfo: true,
|
|
portainer.OperationDockerVersion: true,
|
|
portainer.OperationDockerEvents: true,
|
|
portainer.OperationDockerSystem: true,
|
|
portainer.OperationDockerAgentPing: true,
|
|
portainer.OperationDockerAgentList: true,
|
|
portainer.OperationDockerAgentHostInfo: true,
|
|
portainer.OperationPortainerStackList: true,
|
|
portainer.OperationPortainerStackInspect: true,
|
|
portainer.OperationPortainerStackFile: true,
|
|
portainer.OperationPortainerWebhookList: true,
|
|
},
|
|
DefaultK8sClusterAuthorizations()[portainer.RoleIDReadonly],
|
|
DefaultAzureAuthorizations()[portainer.RoleIDReadonly],
|
|
)
|
|
|
|
return authorizations
|
|
}
|
|
|
|
// DefaultPortainerAuthorizations returns the default Portainer authorizations used by non-admin users.
|
|
func DefaultPortainerAuthorizations() portainer.Authorizations {
|
|
return map[portainer.Authorization]bool{
|
|
portainer.OperationPortainerEndpointGroupInspect: true,
|
|
portainer.OperationPortainerEndpointGroupList: true,
|
|
portainer.OperationPortainerDockerHubInspect: true,
|
|
portainer.OperationPortainerEndpointList: true,
|
|
portainer.OperationPortainerEndpointInspect: true,
|
|
portainer.OperationPortainerEndpointExtensionAdd: true,
|
|
portainer.OperationPortainerEndpointExtensionRemove: true,
|
|
portainer.OperationPortainerMOTD: true,
|
|
portainer.OperationPortainerRoleList: true,
|
|
portainer.OperationPortainerRegistryList: true,
|
|
portainer.OperationPortainerRegistryInspect: true,
|
|
portainer.OperationPortainerTeamList: true,
|
|
portainer.OperationPortainerTemplateList: true,
|
|
portainer.OperationPortainerTemplateInspect: true,
|
|
portainer.OperationPortainerUserList: true,
|
|
portainer.OperationPortainerUserInspect: true,
|
|
portainer.OperationPortainerUserMemberships: true,
|
|
}
|
|
}
|
|
|
|
// RegisterEventHandler upserts event handler by id
|
|
func (service *Service) RegisterEventHandler(id string, handler portainer.AuthEventHandler) {
|
|
service.authEventHandlers[id] = handler
|
|
}
|
|
|
|
// TriggerEndpointAuthUpdate triggers endpoint auth update event on the registered
|
|
// event handlers (e.g. token cache manager)
|
|
func (service *Service) TriggerEndpointAuthUpdate(endpointID int) {
|
|
for _, handler := range service.authEventHandlers {
|
|
handler.HandleEndpointAuthUpdate(endpointID)
|
|
}
|
|
}
|
|
|
|
// TriggerUserAuthUpdate triggers all users auth update event on the registered
|
|
// event handlers (e.g. token cache manager)
|
|
func (service *Service) TriggerUsersAuthUpdate() {
|
|
for _, handler := range service.authEventHandlers {
|
|
handler.HandleUsersAuthUpdate()
|
|
}
|
|
}
|
|
|
|
// TriggerUserAuthUpdate triggers single user auth update event on the registered
|
|
// event handlers (e.g. token cache manager)
|
|
func (service *Service) TriggerUserAuthUpdate(userID int) {
|
|
for _, handler := range service.authEventHandlers {
|
|
handler.HandleUserAuthDelete(userID)
|
|
}
|
|
}
|
|
|
|
func populateVolumeBrowsingAuthorizations(rolePointer *portainer.Role) portainer.Role {
|
|
role := *rolePointer
|
|
|
|
role.Authorizations[portainer.OperationDockerAgentBrowseGet] = true
|
|
role.Authorizations[portainer.OperationDockerAgentBrowseList] = true
|
|
|
|
if role.ID == portainer.RoleIDStandardUser {
|
|
role.Authorizations[portainer.OperationDockerAgentBrowseDelete] = true
|
|
role.Authorizations[portainer.OperationDockerAgentBrowsePut] = true
|
|
role.Authorizations[portainer.OperationDockerAgentBrowseRename] = true
|
|
}
|
|
|
|
return role
|
|
}
|
|
|
|
// RemoveTeamAccessPolicies will remove all existing access policies associated to the specified team
|
|
func (service *Service) RemoveTeamAccessPolicies(teamID portainer.TeamID) error {
|
|
endpoints, err := service.dataStore.Endpoint().Endpoints()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, endpoint := range endpoints {
|
|
for policyTeamID := range endpoint.TeamAccessPolicies {
|
|
if policyTeamID == teamID {
|
|
delete(endpoint.TeamAccessPolicies, policyTeamID)
|
|
|
|
err := service.dataStore.Endpoint().UpdateEndpoint(endpoint.ID, &endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
endpointGroups, err := service.dataStore.EndpointGroup().EndpointGroups()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, endpointGroup := range endpointGroups {
|
|
for policyTeamID := range endpointGroup.TeamAccessPolicies {
|
|
if policyTeamID == teamID {
|
|
delete(endpointGroup.TeamAccessPolicies, policyTeamID)
|
|
|
|
err := service.dataStore.EndpointGroup().UpdateEndpointGroup(endpointGroup.ID, &endpointGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
registries, err := service.dataStore.Registry().Registries()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, registry := range registries {
|
|
for policyTeamID := range registry.TeamAccessPolicies {
|
|
if policyTeamID == teamID {
|
|
delete(registry.TeamAccessPolicies, policyTeamID)
|
|
|
|
err := service.dataStore.Registry().UpdateRegistry(registry.ID, ®istry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return service.UpdateUsersAuthorizations()
|
|
}
|
|
|
|
// RemoveUserAccessPolicies will remove all existing access policies associated to the specified user
|
|
func (service *Service) RemoveUserAccessPolicies(userID portainer.UserID) error {
|
|
endpoints, err := service.dataStore.Endpoint().Endpoints()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, endpoint := range endpoints {
|
|
for policyUserID := range endpoint.UserAccessPolicies {
|
|
if policyUserID == userID {
|
|
delete(endpoint.UserAccessPolicies, policyUserID)
|
|
|
|
err := service.dataStore.Endpoint().UpdateEndpoint(endpoint.ID, &endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
endpointGroups, err := service.dataStore.EndpointGroup().EndpointGroups()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, endpointGroup := range endpointGroups {
|
|
for policyUserID := range endpointGroup.UserAccessPolicies {
|
|
if policyUserID == userID {
|
|
delete(endpointGroup.UserAccessPolicies, policyUserID)
|
|
|
|
err := service.dataStore.EndpointGroup().UpdateEndpointGroup(endpointGroup.ID, &endpointGroup)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
registries, err := service.dataStore.Registry().Registries()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, registry := range registries {
|
|
for policyUserID := range registry.UserAccessPolicies {
|
|
if policyUserID == userID {
|
|
delete(registry.UserAccessPolicies, policyUserID)
|
|
|
|
err := service.dataStore.Registry().UpdateRegistry(registry.ID, ®istry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
service.TriggerUserAuthUpdate(int(userID))
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdateUsersAuthorizations will trigger an update of the authorizations for all the users.
|
|
func (service *Service) UpdateUsersAuthorizations() error {
|
|
users, err := service.dataStore.User().Users()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, user := range users {
|
|
err := service.updateUserAuthorizations(user.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
service.TriggerUsersAuthUpdate()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (service *Service) updateUserAuthorizations(userID portainer.UserID) error {
|
|
user, err := service.dataStore.User().User(userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
endpointAuthorizations, err := service.getAuthorizations(user)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
user.EndpointAuthorizations = endpointAuthorizations
|
|
|
|
return service.dataStore.User().UpdateUser(userID, user)
|
|
}
|
|
|
|
func (service *Service) getAuthorizations(user *portainer.User) (portainer.EndpointAuthorizations, error) {
|
|
endpointAuthorizations := portainer.EndpointAuthorizations{}
|
|
if user.Role == portainer.AdministratorRole {
|
|
return endpointAuthorizations, nil
|
|
}
|
|
|
|
userMemberships, err := service.dataStore.TeamMembership().TeamMembershipsByUserID(user.ID)
|
|
if err != nil {
|
|
return endpointAuthorizations, err
|
|
}
|
|
|
|
endpoints, err := service.dataStore.Endpoint().Endpoints()
|
|
if err != nil {
|
|
return endpointAuthorizations, err
|
|
}
|
|
|
|
endpointGroups, err := service.dataStore.EndpointGroup().EndpointGroups()
|
|
if err != nil {
|
|
return endpointAuthorizations, err
|
|
}
|
|
|
|
roles, err := service.dataStore.Role().Roles()
|
|
if err != nil {
|
|
return endpointAuthorizations, err
|
|
}
|
|
|
|
endpointAuthorizations = getUserEndpointAuthorizations(user, endpoints, endpointGroups, roles, userMemberships)
|
|
|
|
return endpointAuthorizations, nil
|
|
}
|
|
|
|
func getUserEndpointAuthorizations(user *portainer.User, endpoints []portainer.Endpoint,
|
|
endpointGroups []portainer.EndpointGroup, roles []portainer.Role,
|
|
userMemberships []portainer.TeamMembership) portainer.EndpointAuthorizations {
|
|
|
|
endpointAuthorizations := make(portainer.EndpointAuthorizations)
|
|
for endpointID, role := range getUserEndpointRoles(user, endpoints,
|
|
endpointGroups, roles, userMemberships) {
|
|
endpointAuthorizations[endpointID] = role.Authorizations
|
|
}
|
|
|
|
return endpointAuthorizations
|
|
}
|
|
|
|
// get the user and team policies from the endpoint group definitions
|
|
func getGroupPolicies(endpointGroups []portainer.EndpointGroup) (
|
|
map[portainer.EndpointGroupID]portainer.UserAccessPolicies,
|
|
map[portainer.EndpointGroupID]portainer.TeamAccessPolicies,
|
|
) {
|
|
groupUserAccessPolicies := map[portainer.EndpointGroupID]portainer.UserAccessPolicies{}
|
|
groupTeamAccessPolicies := map[portainer.EndpointGroupID]portainer.TeamAccessPolicies{}
|
|
for _, endpointGroup := range endpointGroups {
|
|
groupUserAccessPolicies[endpointGroup.ID] = endpointGroup.UserAccessPolicies
|
|
groupTeamAccessPolicies[endpointGroup.ID] = endpointGroup.TeamAccessPolicies
|
|
}
|
|
return groupUserAccessPolicies, groupTeamAccessPolicies
|
|
}
|
|
|
|
// UpdateUserNamespaceAccessPolicies takes an input accessPolicies
|
|
// and updates it with the user and his team's endpoint roles.
|
|
// Returns the updated policies and whether there is any update.
|
|
func (service *Service) UpdateUserNamespaceAccessPolicies(
|
|
userID int, endpoint *portainer.Endpoint,
|
|
policiesToUpdate map[string]portainer.K8sNamespaceAccessPolicy,
|
|
) (map[string]portainer.K8sNamespaceAccessPolicy, bool, error) {
|
|
endpointID := int(endpoint.ID)
|
|
restrictDefaultNamespace := endpoint.Kubernetes.Configuration.RestrictDefaultNamespace
|
|
|
|
userRole, err := service.GetUserEndpointRole(userID, endpointID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
usersEndpointRole := make(map[int]int)
|
|
teamsEndpointRole := make(map[int]int)
|
|
if userRole != nil {
|
|
usersEndpointRole[userID] = int(userRole.ID)
|
|
} else {
|
|
usersEndpointRole[userID] = -1
|
|
}
|
|
|
|
userMemberships, err := service.dataStore.TeamMembership().
|
|
TeamMembershipsByUserID(portainer.UserID(userID))
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
teamIDs := make([]int, 0)
|
|
for _, membership := range userMemberships {
|
|
teamRole, err := service.GetTeamEndpointRole(int(membership.TeamID), endpointID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if teamRole != nil {
|
|
teamsEndpointRole[int(membership.TeamID)] = int(teamRole.ID)
|
|
teamIDs = append(teamIDs, int(membership.TeamID))
|
|
}
|
|
}
|
|
return service.updateNamespaceAccessPolicies(userID, teamIDs, usersEndpointRole, teamsEndpointRole,
|
|
policiesToUpdate, restrictDefaultNamespace)
|
|
}
|
|
|
|
// updateNamespaceAccessPolicies takes an input accessPolicies
|
|
// and updates it with the endpoint users/teams roles.
|
|
func (service *Service) updateNamespaceAccessPolicies(
|
|
selectedUserID int, selectedTeamIDs []int,
|
|
usersEndpointRole map[int]int, teamsEndpointRole map[int]int,
|
|
policiesToUpdate map[string]portainer.K8sNamespaceAccessPolicy,
|
|
restrictDefaultNamespace bool,
|
|
) (map[string]portainer.K8sNamespaceAccessPolicy, bool, error) {
|
|
hasChange := false
|
|
if !restrictDefaultNamespace {
|
|
delete(policiesToUpdate, "default")
|
|
hasChange = true
|
|
}
|
|
for ns, nsPolicies := range policiesToUpdate {
|
|
for userID, policy := range nsPolicies.UserAccessPolicies {
|
|
if int(userID) == selectedUserID {
|
|
iRoleID, ok := usersEndpointRole[int(userID)]
|
|
if !ok {
|
|
delete(nsPolicies.UserAccessPolicies, userID)
|
|
hasChange = true
|
|
} else if int(policy.RoleID) != iRoleID {
|
|
nsPolicies.UserAccessPolicies[userID] = portainer.AccessPolicy{
|
|
RoleID: portainer.RoleID(iRoleID),
|
|
}
|
|
hasChange = true
|
|
}
|
|
}
|
|
}
|
|
for teamID, policy := range nsPolicies.TeamAccessPolicies {
|
|
for _, selectedTeamID := range selectedTeamIDs {
|
|
if int(teamID) == selectedTeamID {
|
|
iRoleID, ok := teamsEndpointRole[int(teamID)]
|
|
if !ok {
|
|
delete(nsPolicies.TeamAccessPolicies, teamID)
|
|
hasChange = true
|
|
} else if int(policy.RoleID) != iRoleID {
|
|
nsPolicies.TeamAccessPolicies[teamID] = portainer.AccessPolicy{
|
|
RoleID: portainer.RoleID(iRoleID),
|
|
}
|
|
hasChange = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
policiesToUpdate[ns] = nsPolicies
|
|
}
|
|
return policiesToUpdate, hasChange, nil
|
|
}
|
|
|
|
// RemoveUserNamespaceAccessPolicies takes an input accessPolicies
|
|
// and remove users/teams in it.
|
|
// Returns the updated policies and whether there is any update.
|
|
func (service *Service) RemoveUserNamespaceAccessPolicies(
|
|
userID int, endpointID int,
|
|
policiesToUpdate map[string]portainer.K8sNamespaceAccessPolicy,
|
|
) (map[string]portainer.K8sNamespaceAccessPolicy, bool, error) {
|
|
userRole, err := service.GetUserEndpointRole(userID, endpointID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
usersEndpointRole := make(map[int]int)
|
|
if userRole != nil {
|
|
usersEndpointRole[userID] = int(userRole.ID)
|
|
}
|
|
return service.removeUserInNamespaceAccessPolicies(usersEndpointRole, policiesToUpdate)
|
|
}
|
|
|
|
// removeUserInNamespaceAccessPolicies takes an input accessPolicies
|
|
// and remove users/teams in it.
|
|
func (service *Service) removeUserInNamespaceAccessPolicies(
|
|
usersEndpointRole map[int]int,
|
|
policiesToUpdate map[string]portainer.K8sNamespaceAccessPolicy,
|
|
) (map[string]portainer.K8sNamespaceAccessPolicy, bool, error) {
|
|
hasChange := false
|
|
for ns, nsPolicies := range policiesToUpdate {
|
|
for userID := range nsPolicies.UserAccessPolicies {
|
|
_, ok := usersEndpointRole[int(userID)]
|
|
if ok {
|
|
delete(nsPolicies.UserAccessPolicies, userID)
|
|
hasChange = true
|
|
}
|
|
}
|
|
if len(nsPolicies.UserAccessPolicies) == 0 && len(nsPolicies.TeamAccessPolicies) == 0 {
|
|
delete(policiesToUpdate, ns)
|
|
} else {
|
|
policiesToUpdate[ns] = nsPolicies
|
|
}
|
|
}
|
|
return policiesToUpdate, hasChange, nil
|
|
}
|
|
|
|
// RemoveTeamsNamespaceAccessPolicies takes an input accessPolicies
|
|
// and remove teams in it.
|
|
// Returns the updated policies and whether there is any update.
|
|
func (service *Service) RemoveTeamNamespaceAccessPolicies(
|
|
teamID int, endpointID int,
|
|
policiesToUpdate map[string]portainer.K8sNamespaceAccessPolicy,
|
|
) (map[string]portainer.K8sNamespaceAccessPolicy, bool, error) {
|
|
teamRole, err := service.GetTeamEndpointRole(teamID, endpointID)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if teamRole == nil {
|
|
return nil, false, nil
|
|
}
|
|
teamsEndpointRole := make(map[int]int)
|
|
teamsEndpointRole[teamID] = int(teamRole.ID)
|
|
|
|
hasChange := false
|
|
for ns, nsPolicies := range policiesToUpdate {
|
|
for teamID := range nsPolicies.TeamAccessPolicies {
|
|
_, ok := teamsEndpointRole[int(teamID)]
|
|
if ok {
|
|
delete(nsPolicies.TeamAccessPolicies, teamID)
|
|
hasChange = true
|
|
}
|
|
}
|
|
if len(nsPolicies.UserAccessPolicies) == 0 && len(nsPolicies.TeamAccessPolicies) == 0 {
|
|
delete(policiesToUpdate, ns)
|
|
} else {
|
|
policiesToUpdate[ns] = nsPolicies
|
|
}
|
|
}
|
|
return policiesToUpdate, hasChange, nil
|
|
}
|
|
|
|
// GetUserEndpointRole returns the endpoint role of the user.
|
|
// It returns nil if there is no role assigned to the user at the endpoint.
|
|
func (service *Service) GetUserEndpointRole(
|
|
userID int,
|
|
endpointID int,
|
|
) (*portainer.Role, error) {
|
|
user, err := service.dataStore.User().User(portainer.UserID(userID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
userMemberships, err := service.dataStore.TeamMembership().TeamMembershipsByUserID(user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpoint, err := service.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpointGroups, err := service.dataStore.EndpointGroup().EndpointGroups()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
roles, err := service.dataStore.Role().Roles()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
groupUserAccessPolicies, groupTeamAccessPolicies := getGroupPolicies(endpointGroups)
|
|
|
|
return getUserEndpointRole(user, *endpoint, groupUserAccessPolicies,
|
|
groupTeamAccessPolicies, roles, userMemberships), nil
|
|
}
|
|
|
|
func (service *Service) GetNamespaceAuthorizations(
|
|
userID int,
|
|
endpoint portainer.Endpoint,
|
|
kcl portainer.KubeClient,
|
|
) (map[string]portainer.Authorizations, error) {
|
|
namespaceAuthorizations := make(map[string]portainer.Authorizations)
|
|
|
|
// skip non k8s endpoints
|
|
if endpoint.Type != portainer.KubernetesLocalEnvironment &&
|
|
endpoint.Type != portainer.AgentOnKubernetesEnvironment &&
|
|
endpoint.Type != portainer.EdgeAgentOnKubernetesEnvironment {
|
|
return namespaceAuthorizations, nil
|
|
}
|
|
|
|
endpointRole, err := service.GetUserEndpointRole(userID, int(endpoint.ID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// no endpoint role for the user, continue
|
|
if endpointRole == nil {
|
|
return namespaceAuthorizations, nil
|
|
}
|
|
|
|
namespaces, err := kcl.GetNamespaces()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
accessPolicies, err := kcl.GetNamespaceAccessPolicies()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// update the namespace access policies based on user's role, also in configmap.
|
|
accessPolicies, hasChange, err := service.UpdateUserNamespaceAccessPolicies(
|
|
userID, &endpoint, accessPolicies,
|
|
)
|
|
if hasChange {
|
|
err = kcl.UpdateNamespaceAccessPolicies(accessPolicies)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
namespaceAuthorizations, err = service.GetUserNamespaceAuthorizations(
|
|
userID, int(endpointRole.ID), int(endpoint.ID), accessPolicies, namespaces, endpointRole.Authorizations,
|
|
endpoint.Kubernetes.Configuration,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return namespaceAuthorizations, nil
|
|
}
|
|
|
|
// GetUserNamespaceAuthorizations returns authorizations of a user's namespaces
|
|
func (service *Service) GetUserNamespaceAuthorizations(
|
|
userID int,
|
|
userEndpointRoleID int,
|
|
endpointID int,
|
|
accessPolicies map[string]portainer.K8sNamespaceAccessPolicy,
|
|
namespaces map[string]portainer.K8sNamespaceInfo,
|
|
endpointAuthorizations portainer.Authorizations,
|
|
endpointConfiguration portainer.KubernetesConfiguration,
|
|
) (map[string]portainer.Authorizations, error) {
|
|
namespaceRoles, err := service.GetUserNamespaceRoles(userID, userEndpointRoleID, endpointID,
|
|
accessPolicies, namespaces, endpointAuthorizations, endpointConfiguration)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defaultAuthorizations := DefaultK8sNamespaceAuthorizations()
|
|
|
|
namespaceAuthorizations := make(map[string]portainer.Authorizations)
|
|
for namespace, role := range namespaceRoles {
|
|
namespaceAuthorizations[namespace] = defaultAuthorizations[role.ID]
|
|
}
|
|
|
|
return namespaceAuthorizations, nil
|
|
}
|
|
|
|
// GetUserNamespaceRoles returns the endpoint role of the user.
|
|
func (service *Service) GetUserNamespaceRoles(
|
|
userID int,
|
|
userEndpointRoleID int,
|
|
endpointID int,
|
|
accessPolicies map[string]portainer.K8sNamespaceAccessPolicy,
|
|
namespaces map[string]portainer.K8sNamespaceInfo,
|
|
endpointAuthorizations portainer.Authorizations,
|
|
endpointConfiguration portainer.KubernetesConfiguration,
|
|
) (map[string]portainer.Role, error) {
|
|
|
|
// does an early check if user can access all namespaces to skip db calls
|
|
accessAllNamespaces := endpointAuthorizations[portainer.OperationK8sAccessAllNamespaces]
|
|
if accessAllNamespaces {
|
|
return make(map[string]portainer.Role), nil
|
|
}
|
|
|
|
user, err := service.dataStore.User().User(portainer.UserID(userID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
userMemberships, err := service.dataStore.TeamMembership().TeamMembershipsByUserID(user.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
roles, err := service.dataStore.Role().Roles()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
accessSystemNamespaces := endpointAuthorizations[portainer.OperationK8sAccessSystemNamespaces]
|
|
accessUserNamespaces := endpointAuthorizations[portainer.OperationK8sAccessUserNamespaces]
|
|
|
|
return getUserNamespaceRoles(user, userEndpointRoleID, roles, userMemberships,
|
|
accessPolicies, namespaces, accessAllNamespaces, accessSystemNamespaces,
|
|
accessUserNamespaces, endpointConfiguration.RestrictDefaultNamespace)
|
|
}
|
|
|
|
func getUserNamespaceRoles(
|
|
user *portainer.User,
|
|
userEndpointRoleID int,
|
|
roles []portainer.Role,
|
|
userMemberships []portainer.TeamMembership,
|
|
accessPolicies map[string]portainer.K8sNamespaceAccessPolicy,
|
|
namespaces map[string]portainer.K8sNamespaceInfo,
|
|
accessAllNamespaces bool,
|
|
accessSystemNamespaces bool,
|
|
accessUserNamespaces bool,
|
|
restrictDefaultNamespace bool,
|
|
) (map[string]portainer.Role, error) {
|
|
rolesMap := make(map[int]portainer.Role)
|
|
for _, role := range roles {
|
|
rolesMap[int(role.ID)] = role
|
|
}
|
|
results := make(map[string]portainer.Role)
|
|
|
|
for namespace, info := range namespaces {
|
|
// user can access everything
|
|
if accessAllNamespaces {
|
|
results[namespace] = rolesMap[userEndpointRoleID]
|
|
}
|
|
|
|
// skip default namespace or system namespace (when user don't have access)
|
|
if !accessSystemNamespaces && info.IsSystem {
|
|
continue
|
|
}
|
|
|
|
// default namespace doesn't allow permission management so no role
|
|
// aggregation needed
|
|
if !restrictDefaultNamespace && info.IsDefault {
|
|
results[namespace] = rolesMap[userEndpointRoleID]
|
|
}
|
|
|
|
// user can access user namespaces
|
|
if accessUserNamespaces && !info.IsSystem && !info.IsDefault {
|
|
results[namespace] = rolesMap[userEndpointRoleID]
|
|
}
|
|
|
|
// if there is an access policy for the current namespace
|
|
if policies, ok := accessPolicies[namespace]; ok {
|
|
role := getUserNamespaceRole(
|
|
user,
|
|
policies.UserAccessPolicies,
|
|
policies.TeamAccessPolicies,
|
|
roles,
|
|
userMemberships,
|
|
)
|
|
if role != nil {
|
|
results[namespace] = *role
|
|
}
|
|
}
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// For each namespace, first calculate the role(s) of a user
|
|
// based on the sequence of searching:
|
|
// - His namespace role (single)
|
|
// - His teams namespace role (multiple, 1 user has n teams)
|
|
//
|
|
// If roles are found in any of the step, the search stops.
|
|
// Then the role with the hightest priority is returned.
|
|
func getUserNamespaceRole(
|
|
user *portainer.User,
|
|
userAccessPolicies portainer.UserAccessPolicies,
|
|
teamAccessPolicies portainer.TeamAccessPolicies,
|
|
roles []portainer.Role,
|
|
userMemberships []portainer.TeamMembership,
|
|
) *portainer.Role {
|
|
|
|
role := getRoleFromUserAccessPolicies(user, userAccessPolicies, roles)
|
|
if role != nil {
|
|
return role
|
|
}
|
|
|
|
role = getRoleFromTeamAccessPolicies(userMemberships, teamAccessPolicies, roles)
|
|
return role
|
|
}
|
|
|
|
// For each endpoint, first calculate the role(s) of a team
|
|
// based on the sequence of searching:
|
|
// - Team's endpoint role (multiple, 1 user has n teams)
|
|
// - Team's roles in all the assigned endpoint groups (multiple, 1 user has n teams, 1 team has 1 endpoint group)
|
|
//
|
|
// If roles are found in any of the step, the search stops.
|
|
// Then the role with the hightest priority is returned.
|
|
func (service *Service) GetTeamEndpointRole(
|
|
teamID int, endpointID int,
|
|
) (*portainer.Role, error) {
|
|
|
|
memberships, err := service.dataStore.TeamMembership().TeamMembershipsByTeamID(portainer.TeamID(teamID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpoint, err := service.dataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpointGroups, err := service.dataStore.EndpointGroup().EndpointGroups()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
roles, err := service.dataStore.Role().Roles()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, groupTeamAccessPolicies := getGroupPolicies(endpointGroups)
|
|
|
|
role := getRoleFromTeamAccessPolicies(memberships,
|
|
endpoint.TeamAccessPolicies, roles)
|
|
if role != nil {
|
|
return role, nil
|
|
}
|
|
|
|
role = getRoleFromTeamEndpointGroupPolicies(memberships, endpoint,
|
|
roles, groupTeamAccessPolicies)
|
|
return role, nil
|
|
}
|
|
|
|
// For each endpoint, first calculate the role(s) of a user
|
|
// based on the sequence of searching:
|
|
// - His endpoint role (single)
|
|
// - His endpoint group role (single, 1 endpoint has 1 endpoint group)
|
|
// - His teams endpoint role (multiple, 1 user has n teams)
|
|
// - His teams roles in all the assigned endpoint groups (multiple, 1 user has n teams, 1 team has 1 endpoint group)
|
|
//
|
|
// If roles are found in any of the step, the search stops.
|
|
// Then the role with the hightest priority is returned.
|
|
func getUserEndpointRole(user *portainer.User, endpoint portainer.Endpoint,
|
|
groupUserAccessPolicies map[portainer.EndpointGroupID]portainer.UserAccessPolicies,
|
|
groupTeamAccessPolicies map[portainer.EndpointGroupID]portainer.TeamAccessPolicies,
|
|
roles []portainer.Role,
|
|
userMemberships []portainer.TeamMembership,
|
|
) *portainer.Role {
|
|
|
|
role := getRoleFromUserAccessPolicies(user, endpoint.UserAccessPolicies, roles)
|
|
if role == nil {
|
|
role = getRoleFromUserEndpointGroupPolicy(user, &endpoint, roles, groupUserAccessPolicies)
|
|
}
|
|
if role == nil {
|
|
role = getRoleFromTeamAccessPolicies(userMemberships, endpoint.TeamAccessPolicies, roles)
|
|
}
|
|
if role == nil {
|
|
role = getRoleFromTeamEndpointGroupPolicies(userMemberships, &endpoint, roles, groupTeamAccessPolicies)
|
|
}
|
|
|
|
if role != nil && endpoint.SecuritySettings.AllowVolumeBrowserForRegularUsers {
|
|
newRole := populateVolumeBrowsingAuthorizations(role)
|
|
role = &newRole
|
|
}
|
|
|
|
return role
|
|
}
|
|
|
|
func getUserEndpointRoles(user *portainer.User, endpoints []portainer.Endpoint,
|
|
endpointGroups []portainer.EndpointGroup, roles []portainer.Role,
|
|
userMemberships []portainer.TeamMembership) map[portainer.EndpointID]portainer.Role {
|
|
results := make(map[portainer.EndpointID]portainer.Role)
|
|
|
|
groupUserAccessPolicies, groupTeamAccessPolicies := getGroupPolicies(endpointGroups)
|
|
|
|
for _, endpoint := range endpoints {
|
|
role := getUserEndpointRole(user, endpoint, groupUserAccessPolicies,
|
|
groupTeamAccessPolicies, roles, userMemberships)
|
|
if role != nil {
|
|
results[endpoint.ID] = *role
|
|
continue
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
// A user may have 1 role in each assigned Endpoints.
|
|
func getRoleFromUserAccessPolicies(
|
|
user *portainer.User,
|
|
userAccessPolicies portainer.UserAccessPolicies,
|
|
roles []portainer.Role,
|
|
) *portainer.Role {
|
|
policyRoles := make([]portainer.RoleID, 0)
|
|
|
|
policy, ok := userAccessPolicies[user.ID]
|
|
if ok {
|
|
policyRoles = append(policyRoles, policy.RoleID)
|
|
}
|
|
if len(policyRoles) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return getKeyRole(policyRoles, roles)
|
|
}
|
|
|
|
// An endpoint can only have 1 EndpointGroup.
|
|
//
|
|
// A user may have 1 role in each assigned EndpointGroups.
|
|
func getRoleFromUserEndpointGroupPolicy(user *portainer.User,
|
|
endpoint *portainer.Endpoint, roles []portainer.Role,
|
|
groupAccessPolicies map[portainer.EndpointGroupID]portainer.UserAccessPolicies) *portainer.Role {
|
|
policyRoles := make([]portainer.RoleID, 0)
|
|
|
|
policy, ok := groupAccessPolicies[endpoint.GroupID][user.ID]
|
|
if ok {
|
|
policyRoles = append(policyRoles, policy.RoleID)
|
|
}
|
|
if len(policyRoles) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return getKeyRole(policyRoles, roles)
|
|
}
|
|
|
|
// A team may have 1 role in each assigned Endpoints
|
|
func getRoleFromTeamAccessPolicies(
|
|
memberships []portainer.TeamMembership,
|
|
teamAccessPolicies portainer.TeamAccessPolicies,
|
|
roles []portainer.Role,
|
|
) *portainer.Role {
|
|
policyRoles := make([]portainer.RoleID, 0)
|
|
|
|
for _, membership := range memberships {
|
|
policy, ok := teamAccessPolicies[membership.TeamID]
|
|
if ok {
|
|
policyRoles = append(policyRoles, policy.RoleID)
|
|
}
|
|
}
|
|
if len(policyRoles) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return getKeyRole(policyRoles, roles)
|
|
}
|
|
|
|
// An endpoint can only have 1 EndpointGroup.
|
|
//
|
|
// A team may have 1 role in each assigned EndpointGroups.
|
|
func getRoleFromTeamEndpointGroupPolicies(memberships []portainer.TeamMembership,
|
|
endpoint *portainer.Endpoint, roles []portainer.Role,
|
|
groupTeamAccessPolicies map[portainer.EndpointGroupID]portainer.TeamAccessPolicies) *portainer.Role {
|
|
policyRoles := make([]portainer.RoleID, 0)
|
|
|
|
for _, membership := range memberships {
|
|
policy, ok := groupTeamAccessPolicies[endpoint.GroupID][membership.TeamID]
|
|
if ok {
|
|
policyRoles = append(policyRoles, policy.RoleID)
|
|
}
|
|
}
|
|
if len(policyRoles) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return getKeyRole(policyRoles, roles)
|
|
}
|
|
|
|
// for each role in the roleIdentifiers,
|
|
// find the highest priority role and returns its authorizations
|
|
func getAuthorizationsFromRoles(roleIdentifiers []portainer.RoleID, roles []portainer.Role) portainer.Authorizations {
|
|
keyRole := getKeyRole(roleIdentifiers, roles)
|
|
|
|
if keyRole == nil {
|
|
return portainer.Authorizations{}
|
|
}
|
|
|
|
return keyRole.Authorizations
|
|
}
|
|
|
|
// for each role in the roleIdentifiers,
|
|
// find the highest priority role
|
|
func getKeyRole(roleIdentifiers []portainer.RoleID, roles []portainer.Role) *portainer.Role {
|
|
var associatedRoles []portainer.Role
|
|
|
|
for _, id := range roleIdentifiers {
|
|
for _, role := range roles {
|
|
if role.ID == id {
|
|
associatedRoles = append(associatedRoles, role)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
result := &portainer.Role{}
|
|
for _, role := range associatedRoles {
|
|
if role.Priority > result.Priority {
|
|
result = &role
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// unionAuthorizations returns a union of all the input authorizations
|
|
// using the "or" operator.
|
|
func unionAuthorizations(auths ...portainer.Authorizations) portainer.Authorizations {
|
|
authorizations := make(portainer.Authorizations)
|
|
|
|
for _, auth := range auths {
|
|
for authKey, authVal := range auth {
|
|
if val, ok := authorizations[authKey]; ok {
|
|
authorizations[authKey] = val || authVal
|
|
} else {
|
|
authorizations[authKey] = authVal
|
|
}
|
|
}
|
|
}
|
|
|
|
return authorizations
|
|
}
|