chg: make description work for certificate, save and display description
authorINOPIAE <m.maengel@inopiae.de>
Wed, 27 Dec 2017 07:14:13 +0000 (08:14 +0100)
committerINOPIAE <m.maengel@inopiae.de>
Tue, 9 Jan 2018 20:57:22 +0000 (21:57 +0100)
fixes issue #53

Change-Id: Ib21db362fd593428731269661fd01417d95114d3

src/club/wpia/gigi/dbObjects/Certificate.java
src/club/wpia/gigi/output/CertificateIterable.java
src/club/wpia/gigi/output/CertificateTable.templ
src/club/wpia/gigi/pages/account/certs/CertificateIssueForm.java
src/club/wpia/gigi/pages/account/certs/CertificateIssueForm.templ
tests/club/wpia/gigi/TestCertificate.java
tests/club/wpia/gigi/pages/account/TestCertificateAdd.java

index 51bf41b..825b339 100644 (file)
@@ -162,6 +162,8 @@ public class Certificate implements IdCachable {
 
     private CACertificate ca;
 
+    private String description = "";
+
     /**
      * Creates a new Certificate. WARNING: this is an internal API. Creating
      * certificates for users must be done using the {@link CertificateRequest}
@@ -244,6 +246,7 @@ public class Certificate implements IdCachable {
         owner = CertificateOwner.getById(rs.getInt("memid"));
         profile = CertificateProfile.getById(rs.getInt("profile"));
         this.serial = rs.getString("serial");
+        this.description = rs.getString("description");
 
         try (GigiPreparedStatement ps2 = new GigiPreparedStatement("SELECT `contents`, `type` FROM `subjectAlternativeNames` WHERE `certId`=?")) {
             ps2.setInt(1, id);
@@ -408,7 +411,7 @@ public class Certificate implements IdCachable {
         if (serial == null || "".equals(serial)) {
             return null;
         }
-        try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT certs.id, " + CONCAT + " as `subject`, `md`,`memid`, `profile`, `certs`.`serial` FROM `certs` LEFT JOIN `certAvas` ON `certAvas`.`certId`=`certs`.`id` WHERE `serial`=? GROUP BY `certs`.`id`")) {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT certs.id, " + CONCAT + " as `subject`, `md`,`memid`, `profile`, `certs`.`serial`, `certs`.`description` FROM `certs` LEFT JOIN `certAvas` ON `certAvas`.`certId`=`certs`.`id` WHERE `serial`=? GROUP BY `certs`.`id`")) {
             ps.setString(1, serial);
             GigiResultSet rs = ps.executeQuery();
             if ( !rs.next()) {
@@ -434,7 +437,7 @@ public class Certificate implements IdCachable {
         }
 
         try {
-            try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT certs.id, " + CONCAT + " as subject, md, memid, profile, certs.serial FROM `certs` LEFT JOIN `certAvas` ON `certAvas`.`certId`=certs.id WHERE certs.id=? GROUP BY certs.id")) {
+            try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT certs.id, " + CONCAT + " as subject, md, memid, profile, certs.serial, description FROM `certs` LEFT JOIN `certAvas` ON `certAvas`.`certId`=certs.id WHERE certs.id=? GROUP BY certs.id")) {
                 ps.setInt(1, id);
                 GigiResultSet rs = ps.executeQuery();
                 if ( !rs.next()) {
@@ -566,4 +569,17 @@ public class Certificate implements IdCachable {
             return s;
         }
     }
+
+    public void setDescription(String description) {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `certs` SET `description`=? WHERE `id`=?")) {
+            ps.setString(1, description);
+            ps.setInt(2, id);
+            ps.execute();
+        }
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
 }
index cb4b352..0932dfa 100644 (file)
@@ -36,6 +36,7 @@ public class CertificateIterable implements IterableDataset {
         vars.put("serial", c.getSerial());
         vars.put("digest", c.getMessageDigest());
         vars.put("profile", c.getProfile().getVisibleName());
+        vars.put("description", c.getDescription());
         CertificateStatus st = c.getStatus();
         vars.put("revokable", st != CertificateStatus.REVOKED && st == CertificateStatus.ISSUED);
         String issuedWarning = "";
index 539ac1e..edf01eb 100644 (file)
@@ -10,6 +10,7 @@
 <th><?=_Revoked?></th>
 <th><?=_Expires?></th>
 <th><?=_Login?></th>
+<th><?=_Description?></th>
 </tr></thead>
 <tbody>
 <? foreach($certs) {?>
@@ -26,6 +27,7 @@
        <td><?=$revoked?></td>
        <td class="<?=$classExpired?>"><?=$expire?></td>
        <td><?=$login?></td>
+       <td><?=$description?></td>
 </tr>
 <? } ?>
 </tbody>
index 86056df..8192571 100644 (file)
@@ -99,6 +99,13 @@ public class CertificateIssueForm extends Form {
                 if (login) {
                     result.setLoginEnabled(true);
                 }
+                if (req.getParameter("description") != null) {
+                    String description = req.getParameter("description").trim();
+                    if (description.length() > 100) {
+                        throw new GigiApiException("Submitted description is longer than 100 characters.");
+                    }
+                    result.setDescription(description);
+                }
                 result.issue(issueDate.getFrom(), issueDate.getTo(), c.getActor()).waitFor(60000);
                 this.result = result;
                 Certificate c = result;
index 494a7ff..68b8713 100644 (file)
@@ -97,7 +97,7 @@
   </tr>
   <tr>
     <td colspan="2">
-      <label for="description"><?=_Optional comment, only used in the certificate overview?></label><br />
+      <label for="description"><?=_Optional description (max. 100 characters), only used in the certificate overview?></label><br />
       <input class="form-control" type="text" id="description" name="description" maxlength="100" size="100" />
     </td>
   </tr>
index 058c029..d76c514 100644 (file)
@@ -25,6 +25,7 @@ import club.wpia.gigi.dbObjects.User;
 import club.wpia.gigi.pages.account.certs.Certificates;
 import club.wpia.gigi.testUtils.IOUtils;
 import club.wpia.gigi.testUtils.ManagedTest;
+import club.wpia.gigi.util.RandomToken;
 import sun.security.x509.GeneralNameInterface;
 
 public class TestCertificate extends ManagedTest {
@@ -159,4 +160,22 @@ public class TestCertificate extends ManagedTest {
             }
         }
     }
+
+    @Test
+    public void testClientCertDescription() throws IOException, GeneralSecurityException, SQLException, InterruptedException, GigiApiException {
+        KeyPair kp = generateKeypair();
+        String key1 = generatePEMCSR(kp, "CN=testmail@example.com");
+        Certificate c = new Certificate(u, u, Certificate.buildDN("CN", "testmail@example.com"), Digest.SHA256, key1, CSRType.CSR, getClientProfile());
+        await(c.issue(null, "2y", u));
+        String description = RandomToken.generateToken(95) + DIFFICULT_CHARS;
+        c.setDescription(description);
+        assertEquals(description, c.getDescription());
+
+        // test that description is entered to db
+        int cid = c.getId();
+        clearCaches();
+        Certificate cn = Certificate.getById(cid);
+        assertEquals(description, cn.getDescription());
+
+    }
 }
index bac6217..949085c 100644 (file)
@@ -1,6 +1,7 @@
 package club.wpia.gigi.pages.account;
 
 import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.*;
 
 import java.io.ByteArrayInputStream;
@@ -37,9 +38,11 @@ import club.wpia.gigi.dbObjects.CertificateOwner;
 import club.wpia.gigi.dbObjects.Digest;
 import club.wpia.gigi.pages.account.certs.CertificateAdd;
 import club.wpia.gigi.pages.account.certs.CertificateRequest;
+import club.wpia.gigi.pages.account.certs.Certificates;
 import club.wpia.gigi.testUtils.ClientTest;
 import club.wpia.gigi.testUtils.IOUtils;
 import club.wpia.gigi.util.PEM;
+import club.wpia.gigi.util.RandomToken;
 import sun.security.pkcs.PKCS7;
 import sun.security.pkcs.PKCS9Attribute;
 import sun.security.pkcs10.PKCS10Attribute;
@@ -130,24 +133,7 @@ public class TestCertificateAdd extends ClientTest {
 
     @Test
     public void testIssue() throws IOException, GeneralSecurityException {
-        PKCS10Attributes atts = buildAtts(new ObjectIdentifier[] {
-                CertificateRequest.OID_KEY_USAGE_SSL_CLIENT
-        }, new RFC822Name(email));
-
-        String pem = generatePEMCSR(kp, "CN=a b,email=" + email, atts, "SHA512WithRSA");
-
-        String[] res = fillOutForm("CSR=" + URLEncoder.encode(pem, "UTF-8"));
-        assertArrayEquals(new String[] {
-                "client", "a b", "email:" + email + "\n", Digest.SHA512.toString()
-        }, res);
-
-        HttpURLConnection huc = (HttpURLConnection) ncert.openConnection();
-        huc.setRequestProperty("Cookie", cookie);
-        huc.setDoOutput(true);
-        OutputStream out = huc.getOutputStream();
-        out.write(("csrf=" + URLEncoder.encode(csrf, "UTF-8")).getBytes("UTF-8"));
-        out.write(("&CN=" + URLEncoder.encode(CertificateRequest.DEFAULT_CN, "UTF-8") + "&profile=client&SANs=" + URLEncoder.encode("email:" + email + "\n", "UTF-8")).getBytes("UTF-8"));
-        out.write(("&hash_alg=SHA512").getBytes("UTF-8"));
+        HttpURLConnection huc = sendCertificateForm("description");
         URLConnection uc = authenticate(new URL(huc.getHeaderField("Location") + ".crt"));
         String crt = IOUtils.readURL(new InputStreamReader(uc.getInputStream(), "UTF-8"));
 
@@ -174,7 +160,48 @@ public class TestCertificateAdd extends ClientTest {
         assertThat(gui, containsString("CN=" + CertificateRequest.DEFAULT_CN));
         assertThat(gui, containsString("SHA512withRSA"));
         assertThat(gui, containsString("RFC822Name: " + email));
+    }
+
+    @Test
+    public void testIssueWithDescription() throws IOException, GeneralSecurityException {
+        String description = "Just a new comment." + RandomToken.generateToken(32);
+        HttpURLConnection huc = sendCertificateForm(description);
+        assertEquals(302, huc.getResponseCode());
+
+        URLConnection uc = get(Certificates.PATH);
+        assertThat(IOUtils.readURL(uc), containsString(description));
+
+        description = "Just a new comment." + RandomToken.generateToken(100);
+        huc = sendCertificateForm(description);
+        assertThat(fetchStartErrorMessage(IOUtils.readURL(huc)), containsString("Submitted description is longer than 100 characters."));
+    }
+
+    private HttpURLConnection sendCertificateForm(String description) throws IOException, GeneralSecurityException {
+        HttpURLConnection huc = openCertificateForm();
+        OutputStream out = huc.getOutputStream();
+        out.write(("csrf=" + URLEncoder.encode(csrf, "UTF-8")).getBytes("UTF-8"));
+        out.write(("&CN=" + URLEncoder.encode(CertificateRequest.DEFAULT_CN, "UTF-8") + "&profile=client&SANs=" + URLEncoder.encode("email:" + email + "\n", "UTF-8")).getBytes("UTF-8"));
+        out.write(("&hash_alg=SHA512").getBytes("UTF-8"));
+        out.write(("&description=" + URLEncoder.encode(description, "UTF-8")).getBytes("UTF-8"));
+        return huc;
+    }
+
+    private HttpURLConnection openCertificateForm() throws IOException, GeneralSecurityException, UnsupportedEncodingException {
+        PKCS10Attributes atts = buildAtts(new ObjectIdentifier[] {
+                CertificateRequest.OID_KEY_USAGE_SSL_CLIENT
+        }, new RFC822Name(email));
+
+        String pem = generatePEMCSR(kp, "CN=a b,email=" + email, atts, "SHA512WithRSA");
+
+        String[] res = fillOutForm("CSR=" + URLEncoder.encode(pem, "UTF-8"));
+        assertArrayEquals(new String[] {
+                "client", "a b", "email:" + email + "\n", Digest.SHA512.toString()
+        }, res);
 
+        HttpURLConnection huc = (HttpURLConnection) ncert.openConnection();
+        huc.setRequestProperty("Cookie", cookie);
+        huc.setDoOutput(true);
+        return huc;
     }
 
     private byte[] verifyChain(X509Certificate[] x509Certificates) throws GeneralSecurityException {
@@ -257,16 +284,7 @@ public class TestCertificateAdd extends ClientTest {
     }
 
     private X509Certificate createCertWithValidity(String validity, boolean login) throws IOException, GeneralSecurityException, UnsupportedEncodingException, MalformedURLException, CertificateException {
-        PKCS10Attributes atts = buildAtts(new ObjectIdentifier[] {
-                CertificateRequest.OID_KEY_USAGE_SSL_CLIENT
-        }, new RFC822Name(email));
-
-        String pem = generatePEMCSR(kp, "CN=a b", atts, "SHA512WithRSA");
-        fillOutForm("CSR=" + URLEncoder.encode(pem, "UTF-8"));
-
-        HttpURLConnection huc = (HttpURLConnection) ncert.openConnection();
-        huc.setRequestProperty("Cookie", cookie);
-        huc.setDoOutput(true);
+        HttpURLConnection huc = openCertificateForm();
         OutputStream out = huc.getOutputStream();
         out.write(("csrf=" + URLEncoder.encode(csrf, "UTF-8")).getBytes("UTF-8"));
         out.write(("&profile=client&CN=" + CertificateRequest.DEFAULT_CN + "&SANs=" + URLEncoder.encode("email:" + email + "\n", "UTF-8")).getBytes("UTF-8"));