Skip to content

Commit

Permalink
incusd: Add expansion of project names for inheritance
Browse files Browse the repository at this point in the history
Closes #251

Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
  • Loading branch information
stgraber committed Dec 5, 2023
1 parent 0e1e62d commit 07ddd28
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 4 deletions.
53 changes: 51 additions & 2 deletions cmd/incusd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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))
}
Expand Down
6 changes: 4 additions & 2 deletions internal/server/auth/authorization_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -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)
}
}

Expand Down

0 comments on commit 07ddd28

Please sign in to comment.