chg: enforce email address for certificate was pinged within 6 months
authorINOPIAE <m.maengel@inopiae.de>
Mon, 5 Feb 2018 09:43:51 +0000 (10:43 +0100)
committerINOPIAE <m.maengel@inopiae.de>
Tue, 6 Feb 2018 21:38:53 +0000 (22:38 +0100)
fixes issue #5

Change-Id: I612adef8c99c8eb1cdb6e5c7fa4cf56c34e66f34

src/club/wpia/gigi/dbObjects/EmailAddress.java
src/club/wpia/gigi/pages/account/certs/CertificateRequest.java
tests/club/wpia/gigi/pages/account/TestCertificateRequest.java

index 319e415..7d4c984 100644 (file)
@@ -13,6 +13,7 @@ import club.wpia.gigi.email.MailProbe;
 import club.wpia.gigi.localisation.Language;
 import club.wpia.gigi.output.template.SprintfCommand;
 import club.wpia.gigi.util.RandomToken;
+import club.wpia.gigi.util.TimeConditions;
 
 public class EmailAddress implements IdCachable, Verifyable {
 
@@ -122,9 +123,10 @@ public class EmailAddress implements IdCachable, Verifyable {
     }
 
     public boolean isVerified() {
-        try (GigiPreparedStatement statmt = new GigiPreparedStatement("SELECT 1 FROM `emailPinglog` WHERE `email`=? AND `uid`=? AND `type`='active' AND `status`='success'")) {
+        try (GigiPreparedStatement statmt = new GigiPreparedStatement("SELECT 1 FROM `emailPinglog` WHERE `email`=? AND `uid`=? AND `type`='active' AND `status`='success' AND `when` > (now() - interval '1 months' * ?::INTEGER)")) {
             statmt.setString(1, address);
             statmt.setInt(2, owner.getId());
+            statmt.setInt(3, TimeConditions.getInstance().getEmailPingMonths());
             GigiResultSet e = statmt.executeQuery();
             return e.next();
         }
index 8a1bc59..cdf4dd4 100644 (file)
@@ -35,6 +35,7 @@ import club.wpia.gigi.util.DomainAssessment;
 import club.wpia.gigi.util.PEM;
 import club.wpia.gigi.util.RateLimit;
 import club.wpia.gigi.util.ServerConstants;
+import club.wpia.gigi.util.TimeConditions;
 import sun.security.pkcs.PKCS9Attribute;
 import sun.security.pkcs10.PKCS10;
 import sun.security.pkcs10.PKCS10Attribute;
@@ -356,8 +357,8 @@ public class CertificateRequest {
                         valid = false;
                     }
                 }
-            } else if (san.getType() == SANType.EMAIL) {
-                if (emailTemp != null && owner.isValidEmail(san.getName())) {
+            } else if (san.getType() == SANType.EMAIL && emailTemp != null) {
+                if (owner.isValidEmail(san.getName())) {
                     if (pMail != null && !emailTemp.isMultiple()) {
                         // remove
                     } else {
@@ -367,6 +368,11 @@ public class CertificateRequest {
                         filteredSANs.add(san);
                         continue;
                     }
+                } else {
+                    // remove
+                    error.mergeInto(new GigiApiException(SprintfCommand.createSimple(//
+                            "The requested subject alternate name email address \"{0}\" needs an email ping within the past {1} months.", san.getType().toString().toLowerCase() + ":" + san.getName(), TimeConditions.getInstance().getEmailPingMonths())));
+                    break;
                 }
             }
             error.mergeInto(new GigiApiException(SprintfCommand.createSimple(//
index 79edd93..da580cc 100644 (file)
@@ -6,14 +6,19 @@ import static org.junit.Assert.*;
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
+import java.util.Locale;
 
 import org.junit.Test;
 
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.database.GigiPreparedStatement;
+import club.wpia.gigi.dbObjects.EmailAddress;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.pages.account.certs.CertificateRequest;
 import club.wpia.gigi.testUtils.ClientTest;
+import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
 import club.wpia.gigi.util.AuthorizationContext;
+import club.wpia.gigi.util.TimeConditions;
 
 public class TestCertificateRequest extends ClientTest {
 
@@ -85,4 +90,50 @@ public class TestCertificateRequest extends ClientTest {
         }
 
     }
+
+    @Test
+    public void testPingPeriodOneAddress() throws IOException, GeneralSecurityException, GigiApiException {
+        // get new email address with last ping in past
+        String furtherEmail = createUniqueName() + "@example.org";
+        EmailAddress ea = new EmailAddress(u, furtherEmail, Locale.ENGLISH);
+        TestMail mail = getMailReceiver().receive(furtherEmail);
+        try (GigiPreparedStatement stmt = new GigiPreparedStatement("UPDATE `emailPinglog` SET `status`='success'::`pingState`, `when` = (now() - interval '1 months' * ?::INTEGER) WHERE `email`=? ")) {
+            stmt.setInt(1, TimeConditions.getInstance().getEmailPingMonths());
+            stmt.setString(2, furtherEmail);
+            stmt.executeUpdate();
+        }
+
+        try {
+            CertificateRequest cr = new CertificateRequest(ac, generatePEMCSR(kp, "CN=a ab"));
+            cr.update("name", "SHA512", "mail", null, null, "email:" + furtherEmail);
+            cr.draft();
+            fail();
+        } catch (GigiApiException e) {
+            assertThat(e.getMessage(), containsString("needs an email ping within the past"));
+        }
+
+    }
+
+    @Test
+    public void testPingPeriodTwoAddresses() throws IOException, GeneralSecurityException, GigiApiException {
+        // get new email address with last ping in past
+        String furtherEmail = createUniqueName() + "@example.org";
+        EmailAddress ea = new EmailAddress(u, furtherEmail, Locale.ENGLISH);
+        TestMail mail = getMailReceiver().receive(furtherEmail);
+        try (GigiPreparedStatement stmt = new GigiPreparedStatement("UPDATE `emailPinglog` SET `status`='success'::`pingState`, `when` = (now() - interval '1 months' * ?::INTEGER) WHERE `email`=? ")) {
+            stmt.setInt(1, TimeConditions.getInstance().getEmailPingMonths());
+            stmt.setString(2, furtherEmail);
+            stmt.executeUpdate();
+        }
+
+        try {
+            CertificateRequest cr = new CertificateRequest(ac, generatePEMCSR(kp, "CN=a ab"));
+            cr.update("name", "SHA512", "mail", null, null, "email:" + furtherEmail + ",email:" + email);
+            cr.draft();
+            fail();
+        } catch (GigiApiException e) {
+            assertThat(e.getMessage(), containsString("needs an email ping within the past"));
+        }
+
+    }
 }