From 0e1e62d336d0adbe2c57b758a671c9a1a89d1204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Mon, 4 Dec 2023 16:35:00 -0500 Subject: [PATCH] incusd: Add expansion of image and certificate fingerprints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #249 Signed-off-by: Stéphane Graber --- cmd/incusd/daemon.go | 30 ++++++++++++++++++- internal/server/auth/authorization_objects.go | 7 ++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/cmd/incusd/daemon.go b/cmd/incusd/daemon.go index 1e8c4e24c77..b464da6874d 100644 --- a/cmd/incusd/daemon.go +++ b/cmd/incusd/daemon.go @@ -253,7 +253,35 @@ func allowAuthenticated(d *Daemon, r *http.Request) response.Response { // Mux vars should always be passed in with the same order they appear in the API route. 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 { - objectName, err := auth.ObjectFromRequest(r, objectType, muxVars...) + // Expansion function to deal with partial fingerprints. + expander := func(projectName string, fingerprint string) string { + if objectType == auth.ObjectTypeImage { + _, imgInfo, err := d.db.Cluster.GetImage(fingerprint, dbCluster.ImageFilter{Project: &projectName}) + if err != nil { + return fingerprint + } + + fingerprint = imgInfo.Fingerprint + } else if objectType == auth.ObjectTypeCertificate { + err := d.db.Cluster.Transaction(r.Context(), func(ctx context.Context, tx *db.ClusterTx) error { + dbCertInfo, err := dbCluster.GetCertificateByFingerprintPrefix(ctx, tx.Tx(), fingerprint) + if err != nil { + return err + } + + fingerprint = dbCertInfo.Fingerprint + return nil + }) + if err != nil { + return fingerprint + } + } + + // Fallback to no expansion. + return fingerprint + } + + objectName, err := auth.ObjectFromRequest(r, objectType, expander, 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 1eafbe14ea4..8405f3a21e4 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, muxVars ...string) (Object, error) { +func ObjectFromRequest(r *http.Request, objectType ObjectType, expand func(string, string) string, muxVars ...string) (Object, error) { // Shortcut for server objects which don't require any arguments. if objectType == ObjectTypeServer { return ObjectServer(), nil @@ -207,6 +207,11 @@ func ObjectFromRequest(r *http.Request, objectType ObjectType, muxVars ...string if muxValue == "" { return "", fmt.Errorf("Mux var %q not found for object type %q", muxVar, objectType) } + + // Expand fingerprints. + if muxVar == "fingerprint" { + muxValue = expand(projectName, muxValue) + } } muxValues = append(muxValues, muxValue)