[lxc-devel] [lxd/master] Certificate updates

stgraber on Github lxc-bot at linuxcontainers.org
Fri Oct 14 21:38:16 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161014/ff12847f/attachment.bin>
-------------- next part --------------
From 553c967a4eccc5ac413db851263a74489a5af0d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 14 Oct 2016 17:01:28 -0400
Subject: [PATCH 1/2] Export all documented certificate fields
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/certificates.go | 1 +
 shared/cert.go      | 1 +
 2 files changed, 2 insertions(+)

diff --git a/lxd/certificates.go b/lxd/certificates.go
index 5dddd0d..236e34a 100644
--- a/lxd/certificates.go
+++ b/lxd/certificates.go
@@ -181,6 +181,7 @@ func doCertificateGet(d *Daemon, fingerprint string) (shared.CertInfo, error) {
 
 	resp.Fingerprint = dbCertInfo.Fingerprint
 	resp.Certificate = dbCertInfo.Certificate
+	resp.Name = dbCertInfo.Name
 	if dbCertInfo.Type == 1 {
 		resp.Type = "client"
 	} else {
diff --git a/shared/cert.go b/shared/cert.go
index 998f85e..ebd5604 100644
--- a/shared/cert.go
+++ b/shared/cert.go
@@ -26,6 +26,7 @@ import (
 type CertInfo struct {
 	Certificate string `json:"certificate"`
 	Fingerprint string `json:"fingerprint"`
+	Name        string `json:"name"`
 	Type        string `json:"type"`
 }
 

From 3764dbe60c4d31fc571eeb0a2c868ddbe2b18093 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Fri, 14 Oct 2016 17:37:02 -0400
Subject: [PATCH 2/2] Add support for PUT/PATCH of certificates
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #2496

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 doc/api-extensions.md  |  6 ++++
 doc/rest-api.md        | 28 +++++++++++++++++++
 lxd/api_1.0.go         |  1 +
 lxd/certificates.go    | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--
 lxd/db_certificates.go | 17 ++++++++++++
 5 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index fc08905..c835832 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -135,3 +135,9 @@ The URL to the recorded output is included in the operation metadata
 once the command is done running.
 
 That output will expire similarly to other log files, typically after 48 hours.
+
+## certificate\_update
+Adds the following to the REST API:
+ * ETag header on GET of a certificate
+ * PUT of certificate entries
+ * PATCH of certificate entries
diff --git a/doc/rest-api.md b/doc/rest-api.md
index b79dbb0..a8f5946 100644
--- a/doc/rest-api.md
+++ b/doc/rest-api.md
@@ -330,6 +330,34 @@ Output:
         "fingerprint": "SHA256 Hash of the raw certificate"
     }
 
+### PUT (ETag supported)
+ * Description: Replaces the certificate properties
+ * Introduced: with API extension "certificate\_update"
+ * Authentication: trusted
+ * Operation: sync
+ * Return: standard return value or standard error
+
+Input:
+
+    {
+        "type": "client",
+        "name": "bar"
+    }
+
+### PATCH (ETag supported)
+ * Description: Updates the certificate properties
+ * Introduced: with API extension "certificate\_update"
+ * Authentication: trusted
+ * Operation: sync
+ * Return: standard return value or standard error
+
+Input:
+
+    {
+        "name": "baz"
+    }
+
+
 ### DELETE
  * Description: Remove a trusted certificate
  * Authentication: trusted
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index b436239..3065ce6 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -73,6 +73,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
 			"profile_usedby",
 			"container_push",
 			"container_exec_recording",
+			"certificate_update",
 		},
 
 		"api_status":  "stable",
diff --git a/lxd/certificates.go b/lxd/certificates.go
index 236e34a..ed832c1 100644
--- a/lxd/certificates.go
+++ b/lxd/certificates.go
@@ -4,6 +4,7 @@ import (
 	"crypto/sha256"
 	"crypto/x509"
 	"encoding/base64"
+	"encoding/json"
 	"encoding/pem"
 	"fmt"
 	"net"
@@ -168,7 +169,7 @@ func certificateFingerprintGet(d *Daemon, r *http.Request) Response {
 		return SmartError(err)
 	}
 
-	return SyncResponse(true, cert)
+	return SyncResponseETag(true, cert, cert)
 }
 
 func doCertificateGet(d *Daemon, fingerprint string) (shared.CertInfo, error) {
@@ -191,6 +192,76 @@ func doCertificateGet(d *Daemon, fingerprint string) (shared.CertInfo, error) {
 	return resp, nil
 }
 
+func certificateFingerprintPut(d *Daemon, r *http.Request) Response {
+	fingerprint := mux.Vars(r)["fingerprint"]
+
+	oldEntry, err := doCertificateGet(d, fingerprint)
+	if err != nil {
+		return SmartError(err)
+	}
+	fingerprint = oldEntry.Fingerprint
+
+	err = etagCheck(r, oldEntry)
+	if err != nil {
+		return PreconditionFailed(err)
+	}
+
+	req := shared.CertInfo{}
+	if err := shared.ReadToJSON(r.Body, &req); err != nil {
+		return BadRequest(err)
+	}
+
+	return doCertificateUpdate(d, fingerprint, req)
+}
+
+func certificateFingerprintPatch(d *Daemon, r *http.Request) Response {
+	fingerprint := mux.Vars(r)["fingerprint"]
+
+	oldEntry, err := doCertificateGet(d, fingerprint)
+	if err != nil {
+		return SmartError(err)
+	}
+	fingerprint = oldEntry.Fingerprint
+
+	err = etagCheck(r, oldEntry)
+	if err != nil {
+		return PreconditionFailed(err)
+	}
+
+	req := oldEntry
+	reqRaw := shared.Jmap{}
+	if err := json.NewDecoder(r.Body).Decode(&reqRaw); err != nil {
+		return BadRequest(err)
+	}
+
+	// Get name
+	value, err := reqRaw.GetString("name")
+	if err == nil {
+		req.Name = value
+	}
+
+	// Get type
+	value, err = reqRaw.GetString("type")
+	if err == nil {
+		req.Type = value
+	}
+
+	return doCertificateUpdate(d, fingerprint, req)
+}
+
+func doCertificateUpdate(d *Daemon, fingerprint string, req shared.CertInfo) Response {
+	if req.Type != "client" {
+		return BadRequest(fmt.Errorf("Unknown request type %s", req.Type))
+	}
+
+	err := dbCertUpdate(d.db, fingerprint, req.Name, 1)
+	if err != nil {
+		return InternalError(err)
+	}
+
+	return EmptySyncResponse
+}
+
 func certificateFingerprintDelete(d *Daemon, r *http.Request) Response {
 	fingerprint := mux.Vars(r)["fingerprint"]
 
@@ -208,4 +279,4 @@ func certificateFingerprintDelete(d *Daemon, r *http.Request) Response {
 	return EmptySyncResponse
 }
 
-var certificateFingerprintCmd = Command{name: "certificates/{fingerprint}", get: certificateFingerprintGet, delete: certificateFingerprintDelete}
+var certificateFingerprintCmd = Command{name: "certificates/{fingerprint}", get: certificateFingerprintGet, delete: certificateFingerprintDelete, put: certificateFingerprintPut, patch: certificateFingerprintPatch}
diff --git a/lxd/db_certificates.go b/lxd/db_certificates.go
index a194627..09baed4 100644
--- a/lxd/db_certificates.go
+++ b/lxd/db_certificates.go
@@ -118,3 +118,20 @@ func dbCertDelete(db *sql.DB, fingerprint string) error {
 
 	return err
 }
+
+func dbCertUpdate(db *sql.DB, fingerprint string, certName string, certType int) error {
+	tx, err := dbBegin(db)
+	if err != nil {
+		return err
+	}
+
+	_, err = tx.Exec("UPDATE certificates SET name=?, type=? WHERE fingerprint=?", certName, certType, fingerprint)
+	if err != nil {
+		tx.Rollback()
+		return err
+	}
+
+	err = txCommit(tx)
+
+	return err
+}


More information about the lxc-devel mailing list