]> 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;
 
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',
-  "disablelogin" boolean NOT NULL DEFAULT 'false',
   "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")
 );
 
-DROP TABLE IF EXISTS "clientcerts";
-CREATE TABLE "clientcerts" (
+DROP TABLE IF EXISTS "logincerts";
+CREATE TABLE "logincerts" (
   "id" int NOT NULL,
-  "disablelogin" boolean NOT NULL DEFAULT 'false',
 
   PRIMARY KEY ("id")
 );
@@ -374,7 +372,7 @@ CREATE TABLE "schemeVersion" (
   "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` (
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;
     }
+
+    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) {
-        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()) {
index eecb31fe786a5e7373ee7445462af5e5446661c2..0a95497d17935bc00b72a9428795daeb49b4dcc1 100644 (file)
@@ -90,6 +90,9 @@ public class CertificateIssueForm extends Form {
                         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;
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();
+        c.setLoginEnabled(true);
         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();
+        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>"));
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();
+        c.setLoginEnabled(true);
         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();
+        c.setLoginEnabled(true);
         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();
+        c.setLoginEnabled(true);
         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));
+        target2.setLoginEnabled(true);
 
         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));
+            c.setLoginEnabled(true);
             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 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;
@@ -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);
-        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 {
-        X509Certificate parsed = createCertWithValidity("&validFrom=now&validity=" + length);
+        X509Certificate parsed = createCertWithValidity("&validFrom=now&validity=" + length, false);
         if (parsed == null) {
             assertTrue( !shouldsucceed);
             return;
@@ -248,7 +249,7 @@ public class TestCertificateAdd extends ClientTest {
         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));
@@ -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"));
+        if (login) {
+            out.write(("login=1&").getBytes("UTF-8"));
+        }
         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;
     }
+
+    @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();
+            c.setLoginEnabled(true);
         } catch (IOException e) {
             throw new Error(e);
         } catch (GigiApiException e) {