From: INOPIAE Date: Sun, 29 Sep 2019 18:36:55 +0000 (+0200) Subject: add: user client certificate must have a verification within <=24 months X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=a7dd0d91bd94ec5eb3ff4e066c8e3492659c7174;hp=-c add: user client certificate must have a verification within <=24 months To ensure that the name in a client certificate is valid the last verification of that name must not be older than 24 months. fixes issue #134 Change-Id: I9e1434f5114c8d3ad13eb06cc48f90314fa994ad --- a7dd0d91bd94ec5eb3ff4e066c8e3492659c7174 diff --git a/src/club/wpia/gigi/dbObjects/Name.java b/src/club/wpia/gigi/dbObjects/Name.java index fbcf10ee..ce8e7e2a 100644 --- a/src/club/wpia/gigi/dbObjects/Name.java +++ b/src/club/wpia/gigi/dbObjects/Name.java @@ -1,6 +1,9 @@ package club.wpia.gigi.dbObjects; import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; import java.util.Map; import club.wpia.gigi.GigiApiException; @@ -11,6 +14,7 @@ import club.wpia.gigi.dbObjects.NamePart.NamePartType; import club.wpia.gigi.localisation.Language; import club.wpia.gigi.output.template.Outputable; import club.wpia.gigi.util.HTMLEncoder; +import club.wpia.gigi.util.TimeConditions; public class Name implements Outputable, IdCachable { @@ -512,4 +516,26 @@ public class Name implements Outputable, IdCachable { } return initals.toString(); } + + public boolean isValidVerification() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis()); + c.add(Calendar.MONTH, -TimeConditions.getInstance().getVerificationMonths()); + String date = sdf.format(new Date(c.getTimeInMillis())); + try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT COUNT(id) FROM `notary` WHERE `to` = ? AND `deleted` IS NULL AND (`expire` IS NULL OR `expire` > CURRENT_TIMESTAMP) AND `date` > ?")) { + query.setInt(1, getId()); + query.setString(2, date); + GigiResultSet rs = query.executeQuery(); + + if (rs.next()) { + if (rs.getInt(1) > 0) { + return true; + } + } + + return false; + } + } + } diff --git a/src/club/wpia/gigi/dbObjects/User.java b/src/club/wpia/gigi/dbObjects/User.java index 714bfc3a..3d88aa6a 100644 --- a/src/club/wpia/gigi/dbObjects/User.java +++ b/src/club/wpia/gigi/dbObjects/User.java @@ -338,6 +338,15 @@ public class User extends CertificateOwner { return false; } + public boolean isValidNameVerification(String name) { + for (Name n : getNames()) { + if (n.matches(name) && n.isValidVerification()) { + return true; + } + } + return false; + } + public void updateDefaultEmail(EmailAddress newMail) throws GigiApiException { for (EmailAddress email : getEmails()) { if (email.getAddress().equals(newMail.getAddress())) { diff --git a/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java b/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java index d9d090ca..28a5b098 100644 --- a/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java +++ b/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java @@ -443,7 +443,7 @@ public class CertificateRequest { subject.put("OU", ou); } } - System.out.println(subject); + if ( !error.isEmpty()) { throw error; } @@ -493,7 +493,11 @@ public class CertificateRequest { User u = (User) ctx.getTarget(); if (name != null && u.isValidName(name)) { if (realIsOK) { - verifiedCN = name; + if (u.isValidNameVerification(name)) { + verifiedCN = name; + } else { + error.mergeInto(new GigiApiException(SprintfCommand.createSimple("The entered name needs a valid verification within the last {0} months.", TimeConditions.getInstance().getVerificationMonths()))); + } } else { error.mergeInto(new GigiApiException("Your real name is not allowed in this certificate.")); if (defaultIsOK) { diff --git a/tests/club/wpia/gigi/dbObjects/TestUser.java b/tests/club/wpia/gigi/dbObjects/TestUser.java index e7aa70cf..7d7b6dba 100644 --- a/tests/club/wpia/gigi/dbObjects/TestUser.java +++ b/tests/club/wpia/gigi/dbObjects/TestUser.java @@ -134,4 +134,19 @@ public class TestUser extends ClientBusinessTest { assertThat(result, ArrayContains.contains(CoreMatchers.equalTo(type))); } + @Test + public void testValidVerification() throws GigiApiException { + User u0 = User.getById(createVerifiedUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD)); + assertFalse(u0.isValidNameVerification(u0.getPreferredName().toString())); + + add100Points(u0.getId()); + assertTrue(u0.isValidNameVerification(u0.getPreferredName().toString())); + + setVerificationDateToPast(u0.getPreferredName()); + assertFalse(u0.isValidNameVerification(u0.getPreferredName().toString())); + + add100Points(u0.getId()); + assertTrue(u0.isValidNameVerification(u0.getPreferredName().toString())); + } + } diff --git a/tests/club/wpia/gigi/dbObjects/TestVerifyName.java b/tests/club/wpia/gigi/dbObjects/TestVerifyName.java index 7f3af269..7ad2c7f4 100644 --- a/tests/club/wpia/gigi/dbObjects/TestVerifyName.java +++ b/tests/club/wpia/gigi/dbObjects/TestVerifyName.java @@ -5,13 +5,9 @@ import static org.junit.Assert.*; import org.junit.Test; import club.wpia.gigi.GigiApiException; -import club.wpia.gigi.dbObjects.Country; -import club.wpia.gigi.dbObjects.Name; -import club.wpia.gigi.dbObjects.NamePart; -import club.wpia.gigi.dbObjects.User; -import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.dbObjects.Country.CountryCodeType; import club.wpia.gigi.dbObjects.NamePart.NamePartType; +import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.testUtils.ClientBusinessTest; import club.wpia.gigi.util.Notary; @@ -35,4 +31,20 @@ public class TestVerifyName extends ClientBusinessTest { assertEquals(10, n4.getVerificationPoints()); assertEquals(10, u.getMaxVerifyPoints()); } + + @Test + public void testValidVerification() throws GigiApiException { + User u0 = User.getById(createVerifiedUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD)); + assertFalse(u0.getPreferredName().isValidVerification()); + + add100Points(u0.getId()); + assertTrue(u0.getPreferredName().isValidVerification()); + + setVerificationDateToPast(u0.getPreferredName()); + assertFalse(u0.getPreferredName().isValidVerification()); + + add100Points(u0.getId()); + assertTrue(u0.getPreferredName().isValidVerification()); + } + } diff --git a/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java b/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java index bb6c575d..372f2bfa 100644 --- a/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java +++ b/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java @@ -15,6 +15,7 @@ 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.ClientBusinessTest; import club.wpia.gigi.testUtils.ClientTest; import club.wpia.gigi.util.AuthorizationContext; import club.wpia.gigi.util.TimeConditions; @@ -135,4 +136,19 @@ public class TestCertificateRequest extends ClientTest { } } + + @Test + public void testVerificationInPast() throws IOException, GeneralSecurityException, GigiApiException { + + ClientBusinessTest.setVerificationDateToPast(u.getPreferredName()); + try { + CertificateRequest cr = new CertificateRequest(ac, generatePEMCSR(kp, "CN=a ab")); + cr.update(u.getPreferredName().toString(), "SHA512", "client-a", null, null, "email:" + email); + cr.draft(); + fail(); + } catch (GigiApiException e) { + assertThat(e.getMessage(), containsString("The entered name needs a valid verification within the last")); + } + + } } diff --git a/tests/club/wpia/gigi/testUtils/ClientBusinessTest.java b/tests/club/wpia/gigi/testUtils/ClientBusinessTest.java index 023d55ed..3a615694 100644 --- a/tests/club/wpia/gigi/testUtils/ClientBusinessTest.java +++ b/tests/club/wpia/gigi/testUtils/ClientBusinessTest.java @@ -1,8 +1,14 @@ package club.wpia.gigi.testUtils; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.database.GigiPreparedStatement; import club.wpia.gigi.dbObjects.Name; import club.wpia.gigi.dbObjects.User; +import club.wpia.gigi.util.TimeConditions; public class ClientBusinessTest extends BusinessTest { @@ -21,4 +27,18 @@ public class ClientBusinessTest extends BusinessTest { throw new Error(e); } } + + public static void setVerificationDateToPast(Name name) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis()); + c.add(Calendar.MONTH, -TimeConditions.getInstance().getVerificationMonths()); + String date = sdf.format(new Date(c.getTimeInMillis())); + GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `notary` SET `date`=? WHERE `to`=? AND `date`>?"); + ps.setString(1, date); + ps.setInt(2, name.getId()); + ps.setString(3, date); + ps.execute(); + ps.close(); + } } diff --git a/tests/club/wpia/gigi/testUtils/ConfiguredTest.java b/tests/club/wpia/gigi/testUtils/ConfiguredTest.java index 322af0bc..43be01db 100644 --- a/tests/club/wpia/gigi/testUtils/ConfiguredTest.java +++ b/tests/club/wpia/gigi/testUtils/ConfiguredTest.java @@ -360,9 +360,11 @@ public abstract class ConfiguredTest { } public static void add100Points(int uid) { - try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100', `date`=?")) { ps2.setInt(1, uid); ps2.setInt(2, User.getById(uid).getPreferredName().getId()); + ps2.setString(3, sdf.format(new Date(System.currentTimeMillis()))); ps2.execute(); } } diff --git a/util-testing/club/wpia/gigi/pages/Manager.java b/util-testing/club/wpia/gigi/pages/Manager.java index f68d307b..0ca61199 100644 --- a/util-testing/club/wpia/gigi/pages/Manager.java +++ b/util-testing/club/wpia/gigi/pages/Manager.java @@ -48,6 +48,7 @@ import club.wpia.gigi.dbObjects.DomainPingExecution; import club.wpia.gigi.dbObjects.DomainPingType; import club.wpia.gigi.dbObjects.EmailAddress; import club.wpia.gigi.dbObjects.Group; +import club.wpia.gigi.dbObjects.Name; import club.wpia.gigi.dbObjects.NamePart; import club.wpia.gigi.dbObjects.NamePart.NamePartType; import club.wpia.gigi.dbObjects.User; @@ -447,6 +448,17 @@ public class Manager extends Page { resp.getWriter().println("User has been verified " + verifications + " times." + info); + } else if (req.getParameter("verifyexpire") != null) { + String mail = req.getParameter("verifyEmail"); + User byEmail = User.getByEmail(mail); + if (byEmail == null) { + resp.getWriter().println("User not found."); + return; + } else { + setVerificationDateToPast(byEmail.getPreferredName()); + } + + resp.getWriter().println("Verification set to time past the limit."); } else if (req.getParameter("letverify") != null) { String mail = req.getParameter("letverifyEmail"); User byEmail = User.getByEmail(mail); @@ -628,4 +640,18 @@ public class Manager extends Page { form.output(resp.getWriter(), getLanguage(req), vars); } + + private static void setVerificationDateToPast(Name name) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(System.currentTimeMillis()); + c.add(Calendar.MONTH, -TimeConditions.getInstance().getVerificationMonths()); + String date = sdf.format(new Date(c.getTimeInMillis())); + GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `notary` SET `date`=? WHERE `to`=? AND `date`>?"); + ps.setString(1, date); + ps.setInt(2, name.getId()); + ps.setString(3, date); + ps.execute(); + ps.close(); + } } diff --git a/util-testing/club/wpia/gigi/pages/Manager.templ b/util-testing/club/wpia/gigi/pages/Manager.templ index 89627aee..f6e1519a 100644 --- a/util-testing/club/wpia/gigi/pages/Manager.templ +++ b/util-testing/club/wpia/gigi/pages/Manager.templ @@ -70,6 +70,7 @@ Email: Verification Points to issue to preferred name:
+