]> WPIA git - gigi.git/commitdiff
add: store value for login-enabled for clientCertificates
authorFelix Dörre <felix@dogcraft.de>
Sat, 6 Aug 2016 17:50:52 +0000 (19:50 +0200)
committerFelix Dörre <felix@dogcraft.de>
Sat, 6 Aug 2016 21:41:11 +0000 (23:41 +0200)
Change-Id: If857b9b97ad07923d53cc695d0dd6cf750d484ef

14 files changed:
src/org/cacert/gigi/database/DatabaseConnection.java
src/org/cacert/gigi/database/tableStructure.sql
src/org/cacert/gigi/database/upgrade/from_20.sql [new file with mode: 0644]
src/org/cacert/gigi/dbObjects/Certificate.java
src/org/cacert/gigi/dbObjects/CertificateOwner.java
src/org/cacert/gigi/pages/account/certs/CertificateIssueForm.java
tests/org/cacert/gigi/TestCertificate.java
tests/org/cacert/gigi/TestCrossDomainAccess.java
tests/org/cacert/gigi/TestSeparateSessionScope.java
tests/org/cacert/gigi/api/ImportCATSResult.java
tests/org/cacert/gigi/api/IssueCert.java
tests/org/cacert/gigi/dbObjects/TestCertificate.java [new file with mode: 0644]
tests/org/cacert/gigi/pages/account/TestCertificateAdd.java
tests/org/cacert/gigi/testUtils/RestrictedApiTest.java

index e7c9848812f7637ced866d04942703cd7386fddb..80f96e8d68504701987761e129729561c013f82f 100644 (file)
@@ -122,7 +122,7 @@ public class DatabaseConnection {
 
     }
 
 
     }
 
-    public static final int CURRENT_SCHEMA_VERSION = 20;
+    public static final int CURRENT_SCHEMA_VERSION = 21;
 
     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
 
 
     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
 
index 9bd231e8c5f2efd7451beb730b85f9da5de8347c..f9010ccb296774c4b61062a0b51c90b3d435e4d8 100644 (file)
@@ -160,7 +160,6 @@ CREATE TABLE "certs" (
   "revoked" timestamp NULL DEFAULT NULL,
   "expire" timestamp NULL DEFAULT NULL,
   "renewed" boolean NOT NULL DEFAULT 'false',
   "revoked" timestamp NULL DEFAULT NULL,
   "expire" timestamp NULL DEFAULT NULL,
   "renewed" boolean NOT NULL DEFAULT 'false',
-  "disablelogin" boolean NOT NULL DEFAULT 'false',
   "pkhash" char(40) DEFAULT NULL,
   "certhash" char(40) DEFAULT NULL,
   "description" varchar(100) NOT NULL DEFAULT '',
   "pkhash" char(40) DEFAULT NULL,
   "certhash" char(40) DEFAULT NULL,
   "description" varchar(100) NOT NULL DEFAULT '',
@@ -185,10 +184,9 @@ CREATE TABLE "certAvas" (
   PRIMARY KEY ("certId", "name")
 );
 
   PRIMARY KEY ("certId", "name")
 );
 
-DROP TABLE IF EXISTS "clientcerts";
-CREATE TABLE "clientcerts" (
+DROP TABLE IF EXISTS "logincerts";
+CREATE TABLE "logincerts" (
   "id" int NOT NULL,
   "id" int NOT NULL,
-  "disablelogin" boolean NOT NULL DEFAULT 'false',
 
   PRIMARY KEY ("id")
 );
 
   PRIMARY KEY ("id")
 );
@@ -374,7 +372,7 @@ CREATE TABLE "schemeVersion" (
   "version" smallint NOT NULL,
   PRIMARY KEY ("version")
 );
   "version" smallint NOT NULL,
   PRIMARY KEY ("version")
 );
-INSERT INTO "schemeVersion" (version)  VALUES(20);
+INSERT INTO "schemeVersion" (version)  VALUES(21);
 
 DROP TABLE IF EXISTS `passwordResetTickets`;
 CREATE TABLE `passwordResetTickets` (
 
 DROP TABLE IF EXISTS `passwordResetTickets`;
 CREATE TABLE `passwordResetTickets` (
diff --git a/src/org/cacert/gigi/database/upgrade/from_20.sql b/src/org/cacert/gigi/database/upgrade/from_20.sql
new file mode 100644 (file)
index 0000000..ff2c839
--- /dev/null
@@ -0,0 +1,6 @@
+ALTER TABLE "certs" DROP "disablelogin";
+
+
+ALTER TABLE "clientcerts" RENAME TO "logincerts";
+DELETE FROM "logincerts" WHERE "disablelogin" = 'true';
+ALTER TABLE "logincerts" DROP "disablelogin";
index 2e35c33e48a9f8580b8e1db1096a487ba4c5c6f5..9f3ca3bd92d7c1a760f244c44dc73c69abc1b8f2 100644 (file)
@@ -443,4 +443,28 @@ public class Certificate implements IdCachable {
         }
         return null;
     }
         }
         return null;
     }
+
+    public void setLoginEnabled(boolean activate) {
+        if (activate) {
+            if ( !isLoginEnabled()) {
+                try (GigiPreparedStatement prep = new GigiPreparedStatement("INSERT INTO `logincerts` SET `id`=?")) {
+                    prep.setInt(1, id);
+                    prep.execute();
+                }
+            }
+        } else {
+            try (GigiPreparedStatement prep = new GigiPreparedStatement("DELETE FROM `logincerts` WHERE `id`=?")) {
+                prep.setInt(1, id);
+                prep.execute();
+            }
+        }
+    }
+
+    public boolean isLoginEnabled() {
+        try (GigiPreparedStatement prep = new GigiPreparedStatement("SELECT 1 FROM `logincerts` WHERE `id`=?")) {
+            prep.setInt(1, id);
+            GigiResultSet res = prep.executeQuery();
+            return res.next();
+        }
+    }
 }
 }
index 3ca821f354f64b39efa0eef14537af8205bb1752..e1a9cca02a978abd041b148f95d0b3c84bc0ce0a 100644 (file)
@@ -116,7 +116,7 @@ public abstract class CertificateOwner implements IdCachable {
     }
 
     public static CertificateOwner getByEnabledSerial(String serial) {
     }
 
     public static CertificateOwner getByEnabledSerial(String serial) {
-        try (GigiPreparedStatement prep = new GigiPreparedStatement("SELECT `memid` FROM `certs` WHERE serial=? AND `disablelogin`='f' AND `revoked` is NULL")) {
+        try (GigiPreparedStatement prep = new GigiPreparedStatement("SELECT `memid` FROM `certs` INNER JOIN `logincerts` ON `logincerts`.`id`=`certs`.`id` WHERE serial=? AND `revoked` is NULL")) {
             prep.setString(1, serial.toLowerCase());
             GigiResultSet res = prep.executeQuery();
             if (res.next()) {
             prep.setString(1, serial.toLowerCase());
             GigiResultSet res = prep.executeQuery();
             if (res.next()) {
index eecb31fe786a5e7373ee7445462af5e5446661c2..0a95497d17935bc00b72a9428795daeb49b4dcc1 100644 (file)
@@ -90,6 +90,9 @@ public class CertificateIssueForm extends Form {
                         error.format(out, Page.getLanguage(req));
                         return false;
                     }
                         error.format(out, Page.getLanguage(req));
                         return false;
                     }
+                    if (login) {
+                        result.setLoginEnabled(true);
+                    }
                     result.issue(issueDate.getFrom(), issueDate.getTo(), c.getActor()).waitFor(60000);
                     this.result = result;
                     return true;
                     result.issue(issueDate.getFrom(), issueDate.getTo(), c.getActor()).waitFor(60000);
                     this.result = result;
                     return true;
index b12d3a9e5ff24a3cce7134835ad5847ca75d31b3..b885881f28b7e6fb9133b4587953badb20387a86 100644 (file)
@@ -38,6 +38,7 @@ public class TestCertificate extends ManagedTest {
         final PrivateKey pk = kp.getPrivate();
         await(c.issue(null, "2y", u));
         final X509Certificate ce = c.cert();
         final PrivateKey pk = kp.getPrivate();
         await(c.issue(null, "2y", u));
         final X509Certificate ce = c.cert();
+        c.setLoginEnabled(true);
         assertNotNull(login(pk, ce));
     }
 
         assertNotNull(login(pk, ce));
     }
 
@@ -106,6 +107,7 @@ public class TestCertificate extends ManagedTest {
         String cookie = login(u.getEmail(), TEST_PASSWORD);
         testFails(CertificateStatus.ISSUED, c);
         X509Certificate cert = c.cert();
         String cookie = login(u.getEmail(), TEST_PASSWORD);
         testFails(CertificateStatus.ISSUED, c);
         X509Certificate cert = c.cert();
+        c.setLoginEnabled(true);
         assertNotNull(login(pk, cert));
         assertEquals(1, countRegex(IOUtils.readURL(get(cookie, Certificates.PATH)), "<td>(?:REVOKED|ISSUED)</td>"));
         assertEquals(1, countRegex(IOUtils.readURL(get(cookie, Certificates.PATH + "?withRevoked")), "<td>(?:REVOKED|ISSUED)</td>"));
         assertNotNull(login(pk, cert));
         assertEquals(1, countRegex(IOUtils.readURL(get(cookie, Certificates.PATH)), "<td>(?:REVOKED|ISSUED)</td>"));
         assertEquals(1, countRegex(IOUtils.readURL(get(cookie, Certificates.PATH + "?withRevoked")), "<td>(?:REVOKED|ISSUED)</td>"));
index e04235e532ad972e9dfdd420dd6b3c1d457ab7ae..0ddf10e1053d7599a80227e183824f9976824b9e 100644 (file)
@@ -51,6 +51,7 @@ public class TestCrossDomainAccess extends ManagedTest {
         String key = generatePEMCSR(kp, "CN=testmail@example.com");
         Certificate c = new Certificate(u, u, Certificate.buildDN("CN", "testmail@example.com"), Digest.SHA256, key, CSRType.CSR, CertificateProfile.getById(1));
         final PrivateKey pk = kp.getPrivate();
         String key = generatePEMCSR(kp, "CN=testmail@example.com");
         Certificate c = new Certificate(u, u, Certificate.buildDN("CN", "testmail@example.com"), Digest.SHA256, key, CSRType.CSR, CertificateProfile.getById(1));
         final PrivateKey pk = kp.getPrivate();
+        c.setLoginEnabled(true);
         await(c.issue(null, "2y", u));
 
         URLConnection con = new URL("https://" + ServerConstants.getSecureHostNamePort()).openConnection();
         await(c.issue(null, "2y", u));
 
         URLConnection con = new URL("https://" + ServerConstants.getSecureHostNamePort()).openConnection();
index 1bce90968f7d50549fee2cff4d9c976d0bd78f51..c5979acf3de3e09984ba769e82e6159497049f91 100644 (file)
@@ -36,6 +36,7 @@ public class TestSeparateSessionScope extends ManagedTest {
         final PrivateKey pk = kp.getPrivate();
         await(c.issue(null, "2y", u));
         final X509Certificate ce = c.cert();
         final PrivateKey pk = kp.getPrivate();
         await(c.issue(null, "2y", u));
         final X509Certificate ce = c.cert();
+        c.setLoginEnabled(true);
         String scookie = login(pk, ce);
 
         assertTrue(isLoggedin(cookie));
         String scookie = login(pk, ce);
 
         assertTrue(isLoggedin(cookie));
@@ -59,6 +60,7 @@ public class TestSeparateSessionScope extends ManagedTest {
         await(c2.issue(null, "2y", u));
         await(j1);
         final X509Certificate ce = c.cert();
         await(c2.issue(null, "2y", u));
         await(j1);
         final X509Certificate ce = c.cert();
+        c.setLoginEnabled(true);
         String scookie = login(pk, ce);
 
         checkCertLogin(c, pk, scookie, 200);
         String scookie = login(pk, ce);
 
         checkCertLogin(c, pk, scookie, 200);
index e16657a08523859cf0819988f39c9b7d774116c4..6d0ad9940df9008f405b6701a4d217dafd384694 100644 (file)
@@ -29,6 +29,7 @@ public class ImportCATSResult extends RestrictedApiTest {
     public void testLookupSerial() throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
         Certificate target2 = new Certificate(u, u, Certificate.buildDN("EMAIL", u.getEmail()), Digest.SHA256, generatePEMCSR(generateKeypair(), "EMAIL=" + u.getEmail()), CSRType.CSR, CertificateProfile.getByName("client"), new Certificate.SubjectAlternateName(SANType.EMAIL, "cats@cacert.org"));
         await(target2.issue(null, "2y", u));
     public void testLookupSerial() throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
         Certificate target2 = new Certificate(u, u, Certificate.buildDN("EMAIL", u.getEmail()), Digest.SHA256, generatePEMCSR(generateKeypair(), "EMAIL=" + u.getEmail()), CSRType.CSR, CertificateProfile.getByName("client"), new Certificate.SubjectAlternateName(SANType.EMAIL, "cats@cacert.org"));
         await(target2.issue(null, "2y", u));
+        target2.setLoginEnabled(true);
 
         assertEquals(u.getId(), Integer.parseInt(apiLookup(target2)));
     }
 
         assertEquals(u.getId(), Integer.parseInt(apiLookup(target2)));
     }
index f6040008fd718b9e0f423c5e45b5a2a90dd7a1ab..5211ec4ce5655e749caadbd4b6c9ad5065817c56 100644 (file)
@@ -44,6 +44,7 @@ public class IssueCert extends ClientTest {
             kp = generateKeypair();
             String key1 = generatePEMCSR(kp, "EMAIL=testmail@example.com");
             c = new Certificate(u, u, Certificate.buildDN("EMAIL", "testmail@example.com"), Digest.SHA256, key1, CSRType.CSR, CertificateProfile.getById(1));
             kp = generateKeypair();
             String key1 = generatePEMCSR(kp, "EMAIL=testmail@example.com");
             c = new Certificate(u, u, Certificate.buildDN("EMAIL", "testmail@example.com"), Digest.SHA256, key1, CSRType.CSR, CertificateProfile.getById(1));
+            c.setLoginEnabled(true);
             pk = kp.getPrivate();
             await(c.issue(null, "2y", u));
             ce = c.cert();
             pk = kp.getPrivate();
             await(c.issue(null, "2y", u));
             ce = c.cert();
diff --git a/tests/org/cacert/gigi/dbObjects/TestCertificate.java b/tests/org/cacert/gigi/dbObjects/TestCertificate.java
new file mode 100644 (file)
index 0000000..8e7f8ef
--- /dev/null
@@ -0,0 +1,32 @@
+package org.cacert.gigi.dbObjects;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+
+import org.cacert.gigi.GigiApiException;
+import org.cacert.gigi.dbObjects.Certificate.CSRType;
+import org.cacert.gigi.testUtils.ClientBusinessTest;
+import org.junit.Test;
+
+public class TestCertificate extends ClientBusinessTest {
+
+    @Test
+    public void testSetLoginEnabled() throws GeneralSecurityException, IOException, GigiApiException {
+        KeyPair kp = generateKeypair();
+        String key = generatePEMCSR(kp, "CN=testmail@example.com");
+        Certificate c = new Certificate(u, u, Certificate.buildDN("CN", "testmail@example.com"), Digest.SHA256, key, CSRType.CSR, CertificateProfile.getById(1));
+
+        assertFalse(c.isLoginEnabled());
+        c.setLoginEnabled(true);
+        assertTrue(c.isLoginEnabled());
+        c.setLoginEnabled(true);
+        assertTrue(c.isLoginEnabled());
+        c.setLoginEnabled(false);
+        assertFalse(c.isLoginEnabled());
+        c.setLoginEnabled(false);
+        assertFalse(c.isLoginEnabled());
+    }
+}
index 5aebe2d87698d1fdc769f61b34075805c23a64a1..6f7c8be43ae602c774074644bb3cf1c97ef1f634 100644 (file)
@@ -31,6 +31,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.cacert.gigi.crypto.SPKAC;
 import java.util.regex.Pattern;
 
 import org.cacert.gigi.crypto.SPKAC;
+import org.cacert.gigi.dbObjects.CertificateOwner;
 import org.cacert.gigi.dbObjects.Digest;
 import org.cacert.gigi.pages.account.certs.CertificateAdd;
 import org.cacert.gigi.pages.account.certs.CertificateRequest;
 import org.cacert.gigi.dbObjects.Digest;
 import org.cacert.gigi.pages.account.certs.CertificateAdd;
 import org.cacert.gigi.pages.account.certs.CertificateRequest;
@@ -222,14 +223,14 @@ public class TestCertificateAdd extends ClientTest {
         Date start = new Date(now);
         Date end = new Date(now + MS_PER_DAY * 10);
         String validity = "&validFrom=" + sdf.format(start) + "&validity=" + sdf.format(end);
         Date start = new Date(now);
         Date end = new Date(now + MS_PER_DAY * 10);
         String validity = "&validFrom=" + sdf.format(start) + "&validity=" + sdf.format(end);
-        X509Certificate res = createCertWithValidity(validity);
+        X509Certificate res = createCertWithValidity(validity, false);
         assertNotNull(validity, res);
         assertEquals(start, res.getNotBefore());
         assertEquals(end, res.getNotAfter());
     }
 
     private void testCertificateValidityRelative(int field, int amount, String length, boolean shouldsucceed) throws IOException, GeneralSecurityException, UnsupportedEncodingException, MalformedURLException, CertificateException {
         assertNotNull(validity, res);
         assertEquals(start, res.getNotBefore());
         assertEquals(end, res.getNotAfter());
     }
 
     private void testCertificateValidityRelative(int field, int amount, String length, boolean shouldsucceed) throws IOException, GeneralSecurityException, UnsupportedEncodingException, MalformedURLException, CertificateException {
-        X509Certificate parsed = createCertWithValidity("&validFrom=now&validity=" + length);
+        X509Certificate parsed = createCertWithValidity("&validFrom=now&validity=" + length, false);
         if (parsed == null) {
             assertTrue( !shouldsucceed);
             return;
         if (parsed == null) {
             assertTrue( !shouldsucceed);
             return;
@@ -248,7 +249,7 @@ public class TestCertificateAdd extends ClientTest {
         assertEquals(c.getTime(), end);
     }
 
         assertEquals(c.getTime(), end);
     }
 
-    private X509Certificate createCertWithValidity(String validity) throws IOException, GeneralSecurityException, UnsupportedEncodingException, MalformedURLException, CertificateException {
+    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));
         PKCS10Attributes atts = buildAtts(new ObjectIdentifier[] {
                 CertificateRequest.OID_KEY_USAGE_SSL_CLIENT
         }, new RFC822Name(email));
@@ -263,6 +264,9 @@ public class TestCertificateAdd extends ClientTest {
         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"));
         out.write(("&hash_alg=SHA512&").getBytes("UTF-8"));
         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"));
         out.write(("&hash_alg=SHA512&").getBytes("UTF-8"));
+        if (login) {
+            out.write(("login=1&").getBytes("UTF-8"));
+        }
         out.write(validity.getBytes("UTF-8"));
 
         String certurl = huc.getHeaderField("Location");
         out.write(validity.getBytes("UTF-8"));
 
         String certurl = huc.getHeaderField("Location");
@@ -368,4 +372,13 @@ public class TestCertificateAdd extends ClientTest {
         String resultingCN = m.group(1);
         return resultingCN;
     }
         String resultingCN = m.group(1);
         return resultingCN;
     }
+
+    @Test
+    public void testSetLoginEnabled() throws IOException, GeneralSecurityException {
+        X509Certificate parsedLoginNotEnabled = createCertWithValidity("&validFrom=now&validity=1m", false);
+        assertNull(CertificateOwner.getByEnabledSerial(parsedLoginNotEnabled.getSerialNumber().toString(16)));
+
+        X509Certificate parsedLoginEnabled = createCertWithValidity("&validFrom=now&validity=1m", true);
+        assertEquals(u, CertificateOwner.getByEnabledSerial(parsedLoginEnabled.getSerialNumber().toString(16)));
+    }
 }
 }
index e9fbcb6712afe5dfe05b5309ddbe34a5a199d83c..e0f2947a97aaf76fb936b48b660723f66d762f56 100644 (file)
@@ -48,6 +48,7 @@ public class RestrictedApiTest extends ClientTest {
             pk = kp.getPrivate();
             await(c.issue(null, "2y", u));
             ce = c.cert();
             pk = kp.getPrivate();
             await(c.issue(null, "2y", u));
             ce = c.cert();
+            c.setLoginEnabled(true);
         } catch (IOException e) {
             throw new Error(e);
         } catch (GigiApiException e) {
         } catch (IOException e) {
             throw new Error(e);
         } catch (GigiApiException e) {