diff --git a/cmd/incusd/daemon.go b/cmd/incusd/daemon.go index b464da6874d..d3aae4bad1c 100644 --- a/cmd/incusd/daemon.go +++ b/cmd/incusd/daemon.go @@ -54,6 +54,7 @@ import ( "github.com/lxc/incus/internal/server/loki" networkZone "github.com/lxc/incus/internal/server/network/zone" "github.com/lxc/incus/internal/server/node" + "github.com/lxc/incus/internal/server/project" "github.com/lxc/incus/internal/server/request" "github.com/lxc/incus/internal/server/response" scriptletLoad "github.com/lxc/incus/internal/server/scriptlet/load" @@ -254,7 +255,7 @@ func allowAuthenticated(d *Daemon, r *http.Request) response.Response { func allowPermission(objectType auth.ObjectType, entitlement auth.Entitlement, muxVars ...string) func(d *Daemon, r *http.Request) response.Response { return func(d *Daemon, r *http.Request) response.Response { // Expansion function to deal with partial fingerprints. - expander := func(projectName string, fingerprint string) string { + expandFingerprint := func(projectName string, fingerprint string) string { if objectType == auth.ObjectTypeImage { _, imgInfo, err := d.db.Cluster.GetImage(fingerprint, dbCluster.ImageFilter{Project: &projectName}) if err != nil { @@ -281,7 +282,55 @@ func allowPermission(objectType auth.ObjectType, entitlement auth.Entitlement, m return fingerprint } - objectName, err := auth.ObjectFromRequest(r, objectType, expander, muxVars...) + // Expansion function to deal with project inheritance. + expandProject := func(projectName string) string { + // Object types that aren't part of projects. + if util.ValueInSlice(objectType, []auth.ObjectType{auth.ObjectTypeUser, auth.ObjectTypeServer, auth.ObjectTypeCertificate, auth.ObjectTypeStoragePool}) { + return projectName + } + + // Load the project. + var p *api.Project + err := d.db.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { + dbProject, err := dbCluster.GetProject(ctx, tx.Tx(), projectName) + if err != nil { + return err + } + + p, err = dbProject.ToAPI(ctx, tx.Tx()) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return projectName + } + + if objectType == auth.ObjectTypeProfile { + projectName = project.ProfileProjectFromRecord(p) + } else if objectType == auth.ObjectTypeStorageBucket { + projectName = project.StorageBucketProjectFromRecord(p) + } else if objectType == auth.ObjectTypeStorageVolume { + dbVolType, err := storagePools.VolumeTypeNameToDBType(muxVars[1]) + if err != nil { + return projectName + } + + projectName = project.StorageVolumeProjectFromRecord(p, dbVolType) + } else if objectType == auth.ObjectTypeNetworkZone { + projectName = project.NetworkZoneProjectFromRecord(p) + } else if util.ValueInSlice(objectType, []auth.ObjectType{auth.ObjectTypeImage, auth.ObjectTypeImageAlias}) { + projectName = project.ImageProjectFromRecord(p) + } else if util.ValueInSlice(objectType, []auth.ObjectType{auth.ObjectTypeNetwork, auth.ObjectTypeNetworkACL}) { + projectName = project.NetworkProjectFromRecord(p) + } + + return projectName + } + + objectName, err := auth.ObjectFromRequest(r, objectType, expandProject, expandFingerprint, muxVars...) if err != nil { return response.InternalError(fmt.Errorf("Failed to create authentication object: %w", err)) } diff --git a/internal/server/auth/authorization_objects.go b/internal/server/auth/authorization_objects.go index 8405f3a21e4..794a2df9ed5 100644 --- a/internal/server/auth/authorization_objects.go +++ b/internal/server/auth/authorization_objects.go @@ -167,7 +167,7 @@ func NewObject(objectType ObjectType, projectName string, identifierElements ... // Mux vars must be provided in the order that they are found in the endpoint path. If the object // requires a project name, this is taken from the project query parameter unless the URL begins // with /1.0/projects. -func ObjectFromRequest(r *http.Request, objectType ObjectType, expand func(string, string) string, muxVars ...string) (Object, error) { +func ObjectFromRequest(r *http.Request, objectType ObjectType, expandProject func(string) string, expandFingerprint func(string, string) string, muxVars ...string) (Object, error) { // Shortcut for server objects which don't require any arguments. if objectType == ObjectTypeServer { return ObjectServer(), nil @@ -181,6 +181,8 @@ func ObjectFromRequest(r *http.Request, objectType ObjectType, expand func(strin projectName := values.Get("project") if projectName == "" { projectName = "default" + } else if projectName != "default" { + projectName = expandProject(projectName) } location := values.Get("target") @@ -210,7 +212,7 @@ func ObjectFromRequest(r *http.Request, objectType ObjectType, expand func(strin // Expand fingerprints. if muxVar == "fingerprint" { - muxValue = expand(projectName, muxValue) + muxValue = expandFingerprint(projectName, muxValue) } }