diff --git a/internal/server/auth/common/common.go b/internal/server/auth/common/common.go index f1356e7247..e25127a015 100644 --- a/internal/server/auth/common/common.go +++ b/internal/server/auth/common/common.go @@ -1,5 +1,6 @@ package common +// RequestDetails is a type representing an authorization request. type RequestDetails struct { UserName string Protocol string @@ -9,6 +10,7 @@ type RequestDetails struct { ProjectName string } +// IsInternalOrUnix tells whether a given request has been initiated locally. func (r *RequestDetails) IsInternalOrUnix() bool { if r.Protocol == "unix" { return true @@ -21,6 +23,7 @@ func (r *RequestDetails) IsInternalOrUnix() bool { return false } +// Username extracts the request username. func (r *RequestDetails) Username() string { if r.Protocol == "cluster" && r.ForwardedUsername != "" { return r.ForwardedUsername @@ -29,6 +32,7 @@ func (r *RequestDetails) Username() string { return r.UserName } +// AuthenticationProtocol extracts the request protocol. func (r *RequestDetails) AuthenticationProtocol() string { if r.Protocol == "cluster" { return r.ForwardedProtocol diff --git a/internal/server/auth/driver_openfga.go b/internal/server/auth/driver_openfga.go index 8ca1250f91..dbdabe6bee 100644 --- a/internal/server/auth/driver_openfga.go +++ b/internal/server/auth/driver_openfga.go @@ -17,6 +17,7 @@ import ( "github.com/lxc/incus/v6/shared/logger" ) +// FGA represents an OpenFGA authorizer. type FGA struct { commonAuthorizer tls *TLS @@ -137,6 +138,7 @@ func (f *FGA) load(ctx context.Context, certificateCache *certificate.Cache, opt return nil } +// StopService stops the authorizer gracefully. func (f *FGA) StopService(ctx context.Context) error { // Cancel any background routine. f.shutdownCancel() @@ -247,6 +249,7 @@ func (f *FGA) connect(ctx context.Context, certificateCache *certificate.Cache, return nil } +// CheckPermission returns an error if the user does not have the given Entitlement on the given Object. func (f *FGA) CheckPermission(ctx context.Context, r *http.Request, object Object, entitlement Entitlement) error { logCtx := logger.Ctx{"object": object, "entitlement": entitlement, "url": r.URL.String(), "method": r.Method} ctx, cancel := context.WithTimeout(ctx, 10*time.Second) @@ -295,6 +298,7 @@ func (f *FGA) CheckPermission(ctx context.Context, r *http.Request, object Objec return nil } +// GetPermissionChecker returns a function that can be used to check whether a user has the required entitlement on an authorization object. func (f *FGA) GetPermissionChecker(ctx context.Context, r *http.Request, entitlement Entitlement, objectType ObjectType) (PermissionChecker, error) { allowFunc := func(b bool) func(Object) bool { return func(Object) bool { @@ -338,6 +342,7 @@ func (f *FGA) GetPermissionChecker(ctx context.Context, r *http.Request, entitle }, nil } +// AddProject adds a project to the authorizer. func (f *FGA) AddProject(ctx context.Context, _ int64, projectName string) error { writes := []client.ClientTupleKey{ { @@ -355,6 +360,7 @@ func (f *FGA) AddProject(ctx context.Context, _ int64, projectName string) error return f.updateTuples(ctx, writes, nil) } +// DeleteProject deletes a project from the authorizer. func (f *FGA) DeleteProject(ctx context.Context, _ int64, projectName string) error { // Only empty projects can be deleted, so we don't need to worry about any tuples with this project as a parent. deletions := []client.ClientTupleKeyWithoutCondition{ @@ -374,6 +380,7 @@ func (f *FGA) DeleteProject(ctx context.Context, _ int64, projectName string) er return f.updateTuples(ctx, nil, deletions) } +// RenameProject renames a project in the authorizer. func (f *FGA) RenameProject(ctx context.Context, _ int64, oldName string, newName string) error { writes := []client.ClientTupleKey{ { @@ -406,7 +413,7 @@ func (f *FGA) RenameProject(ctx context.Context, _ int64, oldName string, newNam return f.updateTuples(ctx, writes, deletions) } -// AddCertificate is a no-op. +// AddCertificate adds a certificate to the authorizer. func (f *FGA) AddCertificate(ctx context.Context, fingerprint string) error { writes := []client.ClientTupleKey{ { @@ -419,7 +426,7 @@ func (f *FGA) AddCertificate(ctx context.Context, fingerprint string) error { return f.updateTuples(ctx, writes, nil) } -// DeleteCertificate is a no-op. +// DeleteCertificate deletes a certificate from the authorizer. func (f *FGA) DeleteCertificate(ctx context.Context, fingerprint string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -432,7 +439,7 @@ func (f *FGA) DeleteCertificate(ctx context.Context, fingerprint string) error { return f.updateTuples(ctx, nil, deletions) } -// AddStoragePool is a no-op. +// AddStoragePool adds a storage pool to the authorizer. func (f *FGA) AddStoragePool(ctx context.Context, storagePoolName string) error { writes := []client.ClientTupleKey{ { @@ -445,7 +452,7 @@ func (f *FGA) AddStoragePool(ctx context.Context, storagePoolName string) error return f.updateTuples(ctx, writes, nil) } -// DeleteStoragePool is a no-op. +// DeleteStoragePool deletes a storage pool from the authorizer. func (f *FGA) DeleteStoragePool(ctx context.Context, storagePoolName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -458,7 +465,7 @@ func (f *FGA) DeleteStoragePool(ctx context.Context, storagePoolName string) err return f.updateTuples(ctx, nil, deletions) } -// AddImage is a no-op. +// AddImage adds an image to the authorizer. func (f *FGA) AddImage(ctx context.Context, projectName string, fingerprint string) error { writes := []client.ClientTupleKey{ { @@ -471,7 +478,7 @@ func (f *FGA) AddImage(ctx context.Context, projectName string, fingerprint stri return f.updateTuples(ctx, writes, nil) } -// DeleteImage is a no-op. +// DeleteImage deletes an image from the authorizer. func (f *FGA) DeleteImage(ctx context.Context, projectName string, fingerprint string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -484,7 +491,7 @@ func (f *FGA) DeleteImage(ctx context.Context, projectName string, fingerprint s return f.updateTuples(ctx, nil, deletions) } -// AddImageAlias is a no-op. +// AddImageAlias adds an image alias to the authorizer. func (f *FGA) AddImageAlias(ctx context.Context, projectName string, imageAliasName string) error { writes := []client.ClientTupleKey{ { @@ -497,7 +504,7 @@ func (f *FGA) AddImageAlias(ctx context.Context, projectName string, imageAliasN return f.updateTuples(ctx, writes, nil) } -// DeleteImageAlias is a no-op. +// DeleteImageAlias deletes an image alias from the authorizer. func (f *FGA) DeleteImageAlias(ctx context.Context, projectName string, imageAliasName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -510,7 +517,7 @@ func (f *FGA) DeleteImageAlias(ctx context.Context, projectName string, imageAli return f.updateTuples(ctx, nil, deletions) } -// RenameImageAlias is a no-op. +// RenameImageAlias renames an image alias in the authorizer. func (f *FGA) RenameImageAlias(ctx context.Context, projectName string, oldAliasName string, newAliasName string) error { writes := []client.ClientTupleKey{ { @@ -531,7 +538,7 @@ func (f *FGA) RenameImageAlias(ctx context.Context, projectName string, oldAlias return f.updateTuples(ctx, writes, deletions) } -// AddInstance is a no-op. +// AddInstance adds an instance to the authorizer. func (f *FGA) AddInstance(ctx context.Context, projectName string, instanceName string) error { writes := []client.ClientTupleKey{ { @@ -544,7 +551,7 @@ func (f *FGA) AddInstance(ctx context.Context, projectName string, instanceName return f.updateTuples(ctx, writes, nil) } -// DeleteInstance is a no-op. +// DeleteInstance deletes an instance from the authorizer. func (f *FGA) DeleteInstance(ctx context.Context, projectName string, instanceName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -557,7 +564,7 @@ func (f *FGA) DeleteInstance(ctx context.Context, projectName string, instanceNa return f.updateTuples(ctx, nil, deletions) } -// RenameInstance is a no-op. +// RenameInstance renames an instance in the authorizer. func (f *FGA) RenameInstance(ctx context.Context, projectName string, oldInstanceName string, newInstanceName string) error { writes := []client.ClientTupleKey{ { @@ -578,7 +585,7 @@ func (f *FGA) RenameInstance(ctx context.Context, projectName string, oldInstanc return f.updateTuples(ctx, writes, deletions) } -// AddNetwork is a no-op. +// AddNetwork adds a network to the authorizer. func (f *FGA) AddNetwork(ctx context.Context, projectName string, networkName string) error { writes := []client.ClientTupleKey{ { @@ -591,7 +598,7 @@ func (f *FGA) AddNetwork(ctx context.Context, projectName string, networkName st return f.updateTuples(ctx, writes, nil) } -// DeleteNetwork is a no-op. +// DeleteNetwork deletes a network from the authorizer. func (f *FGA) DeleteNetwork(ctx context.Context, projectName string, networkName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -604,7 +611,7 @@ func (f *FGA) DeleteNetwork(ctx context.Context, projectName string, networkName return f.updateTuples(ctx, nil, deletions) } -// RenameNetwork is a no-op. +// RenameNetwork renames a network in the authorizer. func (f *FGA) RenameNetwork(ctx context.Context, projectName string, oldNetworkName string, newNetworkName string) error { writes := []client.ClientTupleKey{ { @@ -625,7 +632,7 @@ func (f *FGA) RenameNetwork(ctx context.Context, projectName string, oldNetworkN return f.updateTuples(ctx, writes, deletions) } -// AddNetworkZone is a no-op. +// AddNetworkZone adds a network zone in the authorizer. func (f *FGA) AddNetworkZone(ctx context.Context, projectName string, networkZoneName string) error { writes := []client.ClientTupleKey{ { @@ -638,7 +645,7 @@ func (f *FGA) AddNetworkZone(ctx context.Context, projectName string, networkZon return f.updateTuples(ctx, writes, nil) } -// DeleteNetworkZone is a no-op. +// DeleteNetworkZone deletes a network zone from the authorizer. func (f *FGA) DeleteNetworkZone(ctx context.Context, projectName string, networkZoneName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -651,7 +658,7 @@ func (f *FGA) DeleteNetworkZone(ctx context.Context, projectName string, network return f.updateTuples(ctx, nil, deletions) } -// AddNetworkIntegration is a no-op. +// AddNetworkIntegration adds a network integration to the authorizer. func (f *FGA) AddNetworkIntegration(ctx context.Context, networkIntegrationName string) error { writes := []client.ClientTupleKey{ { @@ -664,7 +671,7 @@ func (f *FGA) AddNetworkIntegration(ctx context.Context, networkIntegrationName return f.updateTuples(ctx, writes, nil) } -// DeleteNetworkIntegration is a no-op. +// DeleteNetworkIntegration deletes a network integration from the authorizer. func (f *FGA) DeleteNetworkIntegration(ctx context.Context, networkIntegrationName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -677,7 +684,7 @@ func (f *FGA) DeleteNetworkIntegration(ctx context.Context, networkIntegrationNa return f.updateTuples(ctx, nil, deletions) } -// RenameNetworkIntegration is a no-op. +// RenameNetworkIntegration renames a network integration in the authorizer. func (f *FGA) RenameNetworkIntegration(ctx context.Context, oldNetworkIntegrationName string, newNetworkIntegrationName string) error { writes := []client.ClientTupleKey{ { @@ -698,7 +705,7 @@ func (f *FGA) RenameNetworkIntegration(ctx context.Context, oldNetworkIntegratio return f.updateTuples(ctx, writes, deletions) } -// AddNetworkACL is a no-op. +// AddNetworkACL adds a network ACL in the authorizer. func (f *FGA) AddNetworkACL(ctx context.Context, projectName string, networkACLName string) error { writes := []client.ClientTupleKey{ { @@ -711,7 +718,7 @@ func (f *FGA) AddNetworkACL(ctx context.Context, projectName string, networkACLN return f.updateTuples(ctx, writes, nil) } -// DeleteNetworkACL is a no-op. +// DeleteNetworkACL deletes a network ACL from the authorizer. func (f *FGA) DeleteNetworkACL(ctx context.Context, projectName string, networkACLName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -724,7 +731,7 @@ func (f *FGA) DeleteNetworkACL(ctx context.Context, projectName string, networkA return f.updateTuples(ctx, nil, deletions) } -// RenameNetworkACL is a no-op. +// RenameNetworkACL renames a network ACL in the authorizer. func (f *FGA) RenameNetworkACL(ctx context.Context, projectName string, oldNetworkACLName string, newNetworkACLName string) error { writes := []client.ClientTupleKey{ { @@ -745,7 +752,7 @@ func (f *FGA) RenameNetworkACL(ctx context.Context, projectName string, oldNetwo return f.updateTuples(ctx, writes, deletions) } -// AddProfile is a no-op. +// AddProfile adds a profile in the authorizer. func (f *FGA) AddProfile(ctx context.Context, projectName string, profileName string) error { writes := []client.ClientTupleKey{ { @@ -758,7 +765,7 @@ func (f *FGA) AddProfile(ctx context.Context, projectName string, profileName st return f.updateTuples(ctx, writes, nil) } -// DeleteProfile is a no-op. +// DeleteProfile deletes a profile from the authorizer. func (f *FGA) DeleteProfile(ctx context.Context, projectName string, profileName string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -771,7 +778,7 @@ func (f *FGA) DeleteProfile(ctx context.Context, projectName string, profileName return f.updateTuples(ctx, nil, deletions) } -// RenameProfile is a no-op. +// RenameProfile renames a profile in the authorizer. func (f *FGA) RenameProfile(ctx context.Context, projectName string, oldProfileName string, newProfileName string) error { writes := []client.ClientTupleKey{ { @@ -792,7 +799,7 @@ func (f *FGA) RenameProfile(ctx context.Context, projectName string, oldProfileN return f.updateTuples(ctx, writes, deletions) } -// AddStoragePoolVolume is a no-op. +// AddStoragePoolVolume adds a storage volume to the authorizer. func (f *FGA) AddStoragePoolVolume(ctx context.Context, projectName string, storagePoolName string, storageVolumeType string, storageVolumeName string, storageVolumeLocation string) error { writes := []client.ClientTupleKey{ { @@ -805,7 +812,7 @@ func (f *FGA) AddStoragePoolVolume(ctx context.Context, projectName string, stor return f.updateTuples(ctx, writes, nil) } -// DeleteStoragePoolVolume is a no-op. +// DeleteStoragePoolVolume deletes a storage volume from the authorizer. func (f *FGA) DeleteStoragePoolVolume(ctx context.Context, projectName string, storagePoolName string, storageVolumeType string, storageVolumeName string, storageVolumeLocation string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { @@ -818,7 +825,7 @@ func (f *FGA) DeleteStoragePoolVolume(ctx context.Context, projectName string, s return f.updateTuples(ctx, nil, deletions) } -// RenameStoragePoolVolume is a no-op. +// RenameStoragePoolVolume renames a storage volume in the authorizer. func (f *FGA) RenameStoragePoolVolume(ctx context.Context, projectName string, storagePoolName string, storageVolumeType string, oldStorageVolumeName string, newStorageVolumeName string, storageVolumeLocation string) error { writes := []client.ClientTupleKey{ { @@ -839,7 +846,7 @@ func (f *FGA) RenameStoragePoolVolume(ctx context.Context, projectName string, s return f.updateTuples(ctx, writes, deletions) } -// AddStorageBucket is a no-op. +// AddStorageBucket adds a storage bucket to the authorizer. func (f *FGA) AddStorageBucket(ctx context.Context, projectName string, storagePoolName string, storageBucketName string, storageBucketLocation string) error { writes := []client.ClientTupleKey{ { @@ -852,7 +859,7 @@ func (f *FGA) AddStorageBucket(ctx context.Context, projectName string, storageP return f.updateTuples(ctx, writes, nil) } -// DeleteStorageBucket is a no-op. +// DeleteStorageBucket deletes a storage bucket from the authorizer. func (f *FGA) DeleteStorageBucket(ctx context.Context, projectName string, storagePoolName string, storageBucketName string, storageBucketLocation string) error { deletions := []client.ClientTupleKeyWithoutCondition{ { diff --git a/internal/server/auth/driver_scriptlet.go b/internal/server/auth/driver_scriptlet.go index 4998d83417..cbc7dc2829 100644 --- a/internal/server/auth/driver_scriptlet.go +++ b/internal/server/auth/driver_scriptlet.go @@ -10,10 +10,12 @@ import ( "github.com/lxc/incus/v6/shared/logger" ) +// Scriptlet represents a scriptlet authorizer. type Scriptlet struct { commonAuthorizer } +// CheckPermission returns an error if the user does not have the given Entitlement on the given Object. func (s *Scriptlet) CheckPermission(ctx context.Context, r *http.Request, object Object, entitlement Entitlement) error { details, err := s.requestDetails(r) if err != nil { @@ -36,10 +38,12 @@ func (s *Scriptlet) CheckPermission(ctx context.Context, r *http.Request, object return api.StatusErrorf(http.StatusForbidden, "Permission denied") } +// GetInstanceAccess returns the list of entities who have access to the instance. func (s *Scriptlet) GetInstanceAccess(ctx context.Context, projectName string, instanceName string) (*api.Access, error) { return &api.Access{}, nil } +// GetPermissionChecker returns a function that can be used to check whether a user has the required entitlement on an authorization object. func (s *Scriptlet) GetPermissionChecker(ctx context.Context, r *http.Request, entitlement Entitlement, objectType ObjectType) (PermissionChecker, error) { allowFunc := func(b bool) func(Object) bool { return func(Object) bool { @@ -69,6 +73,7 @@ func (s *Scriptlet) GetPermissionChecker(ctx context.Context, r *http.Request, e return permissionChecker, nil } +// GetProjectAccess returns the list of entities who have access to the project. func (s *Scriptlet) GetProjectAccess(ctx context.Context, projectName string) (*api.Access, error) { return &api.Access{}, nil } diff --git a/internal/server/auth/driver_tls.go b/internal/server/auth/driver_tls.go index fce42645a8..3bb45d4575 100644 --- a/internal/server/auth/driver_tls.go +++ b/internal/server/auth/driver_tls.go @@ -13,6 +13,7 @@ import ( "github.com/lxc/incus/v6/shared/util" ) +// TLS represents a TLS authorizer. type TLS struct { commonAuthorizer certificates *certificate.Cache