]> WPIA git - gigi.git/commitdiff
add: cert-profile loading from config
authorFelix Dörre <felix@dogcraft.de>
Thu, 14 May 2015 22:10:41 +0000 (00:10 +0200)
committerFelix Dörre <felix@dogcraft.de>
Thu, 14 May 2015 23:16:34 +0000 (01:16 +0200)
src/org/cacert/gigi/database/DatabaseConnection.java
src/org/cacert/gigi/database/tableStructure.sql
src/org/cacert/gigi/database/upgrade/from_3.sql [new file with mode: 0644]
src/org/cacert/gigi/dbObjects/Certificate.java
src/org/cacert/gigi/dbObjects/CertificateProfile.java
src/org/cacert/gigi/dbObjects/User.java
src/org/cacert/gigi/pages/account/certs/CertificateIssueForm.java
src/org/cacert/gigi/pages/account/certs/CertificateRequest.java

index 0d7e22b4f0e8461431d3819f533f264ade0fcdba..8e20f2a712004a4f41e2bcb169cde9a469889636 100644 (file)
@@ -15,7 +15,7 @@ import org.cacert.gigi.database.SQLFileManager.ImportType;
 
 public class DatabaseConnection {
 
-    public static final int CURRENT_SCHEMA_VERSION = 3;
+    public static final int CURRENT_SCHEMA_VERSION = 4;
 
     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
 
index e41bce894f377fe53208e498b3594eb03b21dd4d..234ecc06e5a394656d4142976ef1c9d33f02605f 100644 (file)
@@ -189,32 +189,13 @@ DROP TABLE IF EXISTS `profiles`;
 CREATE TABLE `profiles` (
   `id` int(3) NOT NULL AUTO_INCREMENT,
   `keyname` varchar(60) NOT NULL,
-  `keyUsage` varchar(100) NOT NULL,
-  `extendedKeyUsage` varchar(100) NOT NULL,
-  `rootcert` int(2) NOT NULL DEFAULT '1',
+  `include` varchar(200) NOT NULL,
+  `requires` varchar(200) NOT NULL,
   `name` varchar(100) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE (`keyname`)
 ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
 
-INSERT INTO `profiles` SET rootcert=0, keyname='client', name='ssl-client (unassured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='clientAuth';
-INSERT INTO `profiles` SET rootcert=0, keyname='mail',  name='mail (unassured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='emailProtection';
-INSERT INTO `profiles` SET rootcert=0, keyname='client-mail', name='ssl-client + mail (unassured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='clientAuth, emailProtection';
-INSERT INTO `profiles` SET rootcert=0, keyname='server', name='ssl-server (unassured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='serverAuth';
-
-INSERT INTO `profiles` SET rootcert=1, keyname='client-a', name='ssl-client (assured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='clientAuth';
-INSERT INTO `profiles` SET rootcert=1, keyname='mail-a',  name='mail (assured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='emailProtection';
-INSERT INTO `profiles` SET rootcert=1, keyname='client-mail-a', name='ssl-client + mail(assured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='clientAuth, emailProtection';
-INSERT INTO `profiles` SET rootcert=1, keyname='server-a', name='ssl-server (assured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='serverAuth';
-INSERT INTO `profiles` SET rootcert=2, keyname='code-a', name='codesign (assured)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='codeSigning, msCodeInd, msCodeCom';
-
-INSERT INTO `profiles` SET rootcert=3, keyname='client-orga', name='ssl-client (orga)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='clientAuth';
-INSERT INTO `profiles` SET rootcert=3, keyname='mail-orga',  name='mail (orga)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='emailProtection';
-INSERT INTO `profiles` SET rootcert=3, keyname='client-mail-orga', name='ssl-client + mail(orga)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='clientAuth, emailProtection';
-INSERT INTO `profiles` SET rootcert=3, keyname='server-orga', name='ssl-server (orga)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='serverAuth';
-INSERT INTO `profiles` SET rootcert=4, keyname='code-orga', name='codesign (orga)', keyUsage='digitalSignature, keyEncipherment, keyAgreement', extendedKeyUsage='codeSigning, msCodeInd, msCodeCom';
-
--- 0=unassured, 1=assured, 2=codesign, 3=orga, 4=orga-sign
 DROP TABLE IF EXISTS `subjectAlternativeNames`;
 CREATE TABLE `subjectAlternativeNames` (
   `certId` int(11) NOT NULL,
@@ -347,4 +328,4 @@ CREATE TABLE `schemeVersion` (
   `version` int(5) NOT NULL,
   PRIMARY KEY (`version`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-INSERT INTO schemeVersion(version)  VALUES(3);
+INSERT INTO schemeVersion(version)  VALUES(4);
diff --git a/src/org/cacert/gigi/database/upgrade/from_3.sql b/src/org/cacert/gigi/database/upgrade/from_3.sql
new file mode 100644 (file)
index 0000000..f6c3c08
--- /dev/null
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS `profiles`;
+CREATE TABLE `profiles` (
+  `id` int(3) NOT NULL AUTO_INCREMENT,
+  `keyname` varchar(60) NOT NULL,
+  `include` varchar(200) NOT NULL,
+  `requires` varchar(200) NOT NULL,
+  `name` varchar(100) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE (`keyname`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
index 479a183ae82a5c59d80c9ca4ae1649627572ed82..ed3d5b4a244b0bb9e28b1c9a7e5486933b0c3682 100644 (file)
@@ -135,7 +135,7 @@ public class Certificate {
     private CACertificate ca;
 
     public Certificate(User owner, HashMap<String, String> dn, String md, String csr, CSRType csrType, CertificateProfile profile, SubjectAlternateName... sans) throws GigiApiException {
-        if ( !owner.canIssue(profile)) {
+        if ( !profile.canBeIssuedBy(owner)) {
             throw new GigiApiException("You are not allowed to issue these certificates.");
         }
         this.owner = owner;
index 0aa45512708391d41fa833f1c35e634de7bf1959..7ee206074e58536287d86c27828e640fc03e2279 100644 (file)
@@ -1,6 +1,15 @@
 package org.cacert.gigi.dbObjects;
 
+import java.awt.Desktop;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Properties;
+import java.util.TreeSet;
 
 import org.cacert.gigi.database.DatabaseConnection;
 import org.cacert.gigi.database.GigiPreparedStatement;
@@ -14,17 +23,122 @@ public class CertificateProfile {
 
     private final String visibleName;
 
-    private final int caId;
-
     private static HashMap<String, CertificateProfile> byName = new HashMap<>();
 
     private static HashMap<Integer, CertificateProfile> byId = new HashMap<>();
 
-    private CertificateProfile(int id, String keyName, String visibleName, int caId) {
+    private final PropertyTemplate[] pt;
+
+    private final String[] req;
+
+    private CertificateProfile(int id, String keyName, String visibleName, String requires, String include) {
         this.id = id;
         this.keyName = keyName;
         this.visibleName = visibleName;
-        this.caId = caId;
+        req = parseConditions(requires);
+        pt = parsePropertyTemplates(include);
+    }
+
+    private static class PropertyTemplate implements Comparable<PropertyTemplate> {
+
+        boolean required = true;
+
+        boolean multiple = false;
+
+        private String inc;
+
+        public PropertyTemplate(String inc) {
+            if (inc.endsWith("?") || inc.endsWith("*") || inc.endsWith("+")) {
+                char sfx = inc.charAt(inc.length() - 1);
+                if (sfx == '?') {
+                    required = false;
+                } else if (sfx == '*') {
+                    multiple = true;
+                    required = false;
+                } else {
+                    multiple = true;
+                }
+                inc = inc.substring(0, inc.length() - 1);
+            }
+            this.inc = inc;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((inc == null) ? 0 : inc.hashCode());
+            result = prime * result + (multiple ? 1231 : 1237);
+            result = prime * result + (required ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            PropertyTemplate other = (PropertyTemplate) obj;
+            if (inc == null) {
+                if (other.inc != null) {
+                    return false;
+                }
+            } else if ( !inc.equals(other.inc)) {
+                return false;
+            }
+            if (multiple != other.multiple) {
+                return false;
+            }
+            if (required != other.required) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return inc + (multiple ? (required ? "+" : "*") : (required ? "" : "?"));
+        }
+
+        @Override
+        public int compareTo(PropertyTemplate o) {
+            return toString().compareTo(o.toString());
+        }
+
+    }
+
+    private CertificateProfile(File f) throws IOException {
+        Properties p = new Properties();
+        p.load(new FileInputStream(f));
+        String[] parts = f.getName().split("\\.")[0].split("-", 2);
+        id = Integer.parseInt(parts[0]);
+        keyName = parts[1];
+        visibleName = "";
+        pt = parsePropertyTemplates(p.getProperty("include"));
+        req = parseConditions(p.getProperty("requires", ""));
+    }
+
+    private String[] parseConditions(String property) {
+        String[] split2 = property.split(",");
+        if (split2.length == 1 && split2[0].equals("")) {
+            split2 = new String[0];
+        }
+        return split2;
+    }
+
+    private PropertyTemplate[] parsePropertyTemplates(String property) {
+        String[] split = property.split(",");
+        PropertyTemplate[] pt = new PropertyTemplate[split.length];
+        for (int i = 0; i < split.length; i++) {
+            pt[i] = new PropertyTemplate(split[i]);
+        }
+        return pt;
     }
 
     public int getId() {
@@ -39,15 +153,44 @@ public class CertificateProfile {
         return visibleName;
     }
 
-    public int getCAId() {
-        return caId;
-    }
-
     static {
-        GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id, keyname, name, rootcert FROM `profiles`");
+        for (File f : new File("config/profiles").listFiles()) {
+            Properties p = new Properties();
+            try {
+                p.load(new FileInputStream(f));
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            String[] parts = f.getName().split("\\.")[0].split("-", 2);
+            GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT keyname, include, requires, name FROM `profiles` WHERE id=?");
+            ps.setInt(1, Integer.parseInt(parts[0]));
+            GigiResultSet rs = ps.executeQuery();
+
+            if (rs.next()) {
+                if ( !rs.getString("keyname").equals(parts[1])) {
+                    throw new Error("Config error. Certificate Profile mismatch");
+                }
+                if ( !rs.getString("include").equals(p.getProperty("include"))) {
+                    throw new Error("Config error. Certificate Profile mismatch");
+                }
+                if ( !rs.getString("requires").equals(p.getProperty("requires", ""))) {
+                    throw new Error("Config error. Certificate Profile mismatch");
+                }
+            } else {
+                GigiPreparedStatement insert = DatabaseConnection.getInstance().prepare("INSERT INTO `profiles` SET keyname=?, include=?, requires=?, name=?, id=?");
+                insert.setString(1, parts[1]);
+                insert.setString(2, p.getProperty("include"));
+                insert.setString(3, p.getProperty("requires", ""));
+                insert.setString(4, p.getProperty("name"));
+                insert.setInt(5, Integer.parseInt(parts[0]));
+                insert.execute();
+            }
+
+        }
+        GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id, keyname, name, requires, include FROM `profiles`");
         GigiResultSet rs = ps.executeQuery();
         while (rs.next()) {
-            CertificateProfile cp = new CertificateProfile(rs.getInt("id"), rs.getString("keyName"), rs.getString("name"), rs.getInt("rootcert"));
+            CertificateProfile cp = new CertificateProfile(rs.getInt("id"), rs.getString("keyName"), rs.getString("name"), rs.getString("requires"), rs.getString("include"));
             byId.put(cp.getId(), cp);
             byName.put(cp.getKeyName(), cp);
         }
@@ -66,4 +209,82 @@ public class CertificateProfile {
         return byId.values().toArray(new CertificateProfile[byId.size()]);
     }
 
+    public static void main(String[] args) throws IOException {
+        TreeSet<String> pt = new TreeSet<>();
+        TreeSet<String> req = new TreeSet<>();
+        LinkedList<CertificateProfile> cps = new LinkedList<>();
+        for (CertificateProfile cp : byId.values()) {
+            cps.add(cp);
+            for (PropertyTemplate p : cp.pt) {
+                pt.add(p.inc);
+            }
+            req.addAll(Arrays.asList(cp.req));
+        }
+        PrintWriter pw = new PrintWriter("profiles.html");
+        pw.println("<!DOCTYPE html><html><head><title>Profiles</title>");
+        pw.println("<style>.split{background-color:#000;margin:0;cell-spacing:0}td{text-align:center}</style>");
+        pw.println("</head>");
+        pw.println("<body><table border='1'>");
+        pw.println("<tr><td>id</td><td> </td>");
+        for (String p : pt) {
+            pw.println("<th>" + p + "</th>");
+        }
+        pw.println("<th class='split'></th>");
+        for (String p : req) {
+            pw.println("<th class='req'>" + p + "</th>");
+        }
+        pw.println("</tr>");
+        for (CertificateProfile certificateProfile : cps) {
+            pw.println("<tr>");
+            pw.println("<td>" + certificateProfile.id + "</td>");
+            pw.println("<td>" + certificateProfile.keyName + "</td>");
+            outer:
+            for (String p : pt) {
+                for (PropertyTemplate t : certificateProfile.pt) {
+                    if (t.inc.equals(p)) {
+                        pw.println("<td>" + (t.required ? (t.multiple ? "+" : "y") : (t.multiple ? "*" : "?")) + "</td>");
+                        continue outer;
+                    }
+                }
+                pw.println("<td></td>");
+            }
+            pw.println("<td class='split'></td>");
+            outer:
+            for (String p : req) {
+                for (String t : certificateProfile.req) {
+                    if (t.equals(p)) {
+                        pw.println("<td class='req'>y</td>");
+                        continue outer;
+                    }
+                }
+                pw.println("<td></td>");
+            }
+            pw.println("</tr>");
+        }
+        pw.println("</table></body></html>");
+        Desktop.getDesktop().browse(new File("profiles.html").toURI());
+        pw.close();
+    }
+
+    public boolean canBeIssuedBy(User u) {
+        for (String s : req) {
+            if (s.equals("points>=50")) {
+                if (u.getAssurancePoints() < 50) {
+                    return false;
+                }
+            } else if (s.equals("points>=100")) {
+                if (u.getAssurancePoints() < 100) {
+                    return false;
+                }
+            } else if (s.equals("codesign")) {
+                if (u.isInGroup(Group.CODESIGNING)) {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+
+        }
+        return true;
+    }
 }
index f6b22909d70a729bceec72470b14fef4412d497d..1d7526677eef692edbab3f0407b1467f29b1da14 100644 (file)
@@ -441,21 +441,4 @@ public class User extends CertificateOwner {
         }
     }
 
-    public boolean canIssue(CertificateProfile p) {
-        // FIXME: Use descriptive constants
-        switch (p.getCAId()) {
-        case 0:
-            return true;
-        case 1:
-            return getAssurancePoints() > 50;
-        case 2:
-            return getAssurancePoints() > 50 && isInGroup(Group.getByString("codesigning"));
-        case 3:
-        case 4:
-            return getOrganisations().size() > 0;
-        default:
-            return false;
-        }
-    }
-
 }
index 8a3107f0ed5a03bd8ec582d98d9807fc1b6ec29c..dadd4e88fbe74513ac54b7fd0e23c52e65e028a1 100644 (file)
@@ -160,7 +160,7 @@ public class CertificateIssueForm extends Form {
                     if (cp == null) {
                         return false;
                     }
-                } while ( !u.canIssue(cp));
+                } while ( !cp.canBeIssuedBy(u));
 
                 if (cp.getId() == cr.getProfile().getId()) {
                     vars.put("selected", " selected");
index f066cc3d8ec151f78ae180c64941667f208b613d..9eee2940b980b9150974155decb64170a2b13359 100644 (file)
@@ -342,7 +342,7 @@ public class CertificateRequest {
     public Certificate draft() throws GigiApiException {
 
         GigiApiException error = new GigiApiException();
-        if ( !u.canIssue(this.profile)) {
+        if ( !this.profile.canBeIssuedBy(u)) {
             this.profile = CertificateProfile.getById(1);
             error.mergeInto(new GigiApiException("Certificate Profile is invalid."));
             throw error;