From: INOPIAE Date: Mon, 13 May 2019 13:28:26 +0000 (+0200) Subject: add: ensure to revoke certificates if email address is deleted X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=7da1e022744b277d2eaf2e445484cc2ec33f0fa5 add: ensure to revoke certificates if email address is deleted Make sure all certificates that are not expired containing an email address are revoked if email address is deleted from user account. Function deleteEmailCerts is introduced to enable support to delete an email address or account in a later patch. Related to issue 60 Change-Id: I88c94e398b0e22465ac0cbf9623b101bcea072a6 --- diff --git a/src/club/wpia/gigi/dbObjects/User.java b/src/club/wpia/gigi/dbObjects/User.java index e3beaf86..3213fd8e 100644 --- a/src/club/wpia/gigi/dbObjects/User.java +++ b/src/club/wpia/gigi/dbObjects/User.java @@ -17,6 +17,7 @@ import club.wpia.gigi.GigiApiException; import club.wpia.gigi.database.GigiPreparedStatement; import club.wpia.gigi.database.GigiResultSet; import club.wpia.gigi.dbObjects.CATS.CATSType; +import club.wpia.gigi.dbObjects.Certificate.RevocationType; import club.wpia.gigi.dbObjects.Country.CountryCodeType; import club.wpia.gigi.dbObjects.Verification.VerificationType; import club.wpia.gigi.email.EmailProvider; @@ -360,16 +361,51 @@ public class User extends CertificateOwner { throw new GigiApiException("Can't delete user's default e-mail."); } + deleteEmailCerts(delMail, RevocationType.USER); + } + + private void deleteEmailCerts(EmailAddress delMail, RevocationType rt) throws GigiApiException { for (EmailAddress email : getEmails()) { if (email.getId() == delMail.getId()) { try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `emails` SET `deleted`=CURRENT_TIMESTAMP WHERE `id`=?")) { ps.setInt(1, delMail.getId()); ps.execute(); } + LinkedList revokes = new LinkedList(); + for (Certificate cert : fetchActiveEmailCertificates(delMail.getAddress())) { + revokes.add(cert.revoke(RevocationType.USER)); + } + long start = System.currentTimeMillis(); + for (Job job : revokes) { + int toWait = (int) (60000 + start - System.currentTimeMillis()); + if (toWait > 0) { + job.waitFor(toWait); + } else { + break; // canceled... waited too log + } + } return; } + } throw new GigiApiException("Email not one of user's email addresses."); + + } + + public Certificate[] fetchActiveEmailCertificates(String email) { + try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT DISTINCT `certs`.`id` FROM `certs` INNER JOIN `subjectAlternativeNames` ON `subjectAlternativeNames`.`certId` = `certs`.`id` WHERE `contents`=? AND `type`='email' AND `revoked` IS NULL AND `expire` > CURRENT_TIMESTAMP AND `memid`=?", true)) { + ps.setString(1, email); + ps.setInt(2, getId()); + GigiResultSet rs = ps.executeQuery(); + rs.last(); + Certificate[] res = new Certificate[rs.getRow()]; + rs.beforeFirst(); + int i = 0; + while (rs.next()) { + res[i++] = Certificate.getById(rs.getInt(1)); + } + return res; + } } public synchronized Verification[] getReceivedVerifications() { diff --git a/src/club/wpia/gigi/pages/account/mail/MailManagementForm.templ b/src/club/wpia/gigi/pages/account/mail/MailManagementForm.templ index 2449bca1..c71306f0 100644 --- a/src/club/wpia/gigi/pages/account/mail/MailManagementForm.templ +++ b/src/club/wpia/gigi/pages/account/mail/MailManagementForm.templ @@ -19,7 +19,7 @@ - + diff --git a/tests/club/wpia/gigi/dbObjects/TestUserManaged.java b/tests/club/wpia/gigi/dbObjects/TestUserManaged.java new file mode 100644 index 00000000..50ac27dc --- /dev/null +++ b/tests/club/wpia/gigi/dbObjects/TestUserManaged.java @@ -0,0 +1,39 @@ +package club.wpia.gigi.dbObjects; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; + +import org.junit.Test; + +import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.dbObjects.Certificate.CSRType; +import club.wpia.gigi.dbObjects.Certificate.SANType; +import club.wpia.gigi.testUtils.ManagedTest; + +public class TestUserManaged extends ManagedTest { + + @Test + public void testDeleteEmailWithCertificate() throws GigiApiException, GeneralSecurityException, IOException, InterruptedException { + + int id = createVerifiedUser("Test", "User", createUniqueName() + "test@test.tld", TEST_PASSWORD); + String email = createUniqueName() + "test@test.tld"; + User u = User.getById(id); + Certificate[] certs = u.getCertificates(false); + int certCount = certs.length; + EmailAddress testAddress = createVerifiedEmail(u, email); + KeyPair kp = generateKeypair(); + String key = generatePEMCSR(kp, "CN=" + email); + Certificate c = new Certificate(u, u, Certificate.buildDN("CN", email), Digest.SHA256, key, CSRType.CSR, getClientProfile(), new Certificate.SubjectAlternateName(SANType.EMAIL, email)); + c.issue(null, "2y", u).waitFor(60000); + + u.deleteEmail(testAddress); + + assertFalse(c.getRevocationDate().toString().isEmpty()); + certs = u.getCertificates(false); + assertEquals(certCount, certs.length); + + } +} diff --git a/tests/club/wpia/gigi/testUtils/BusinessTest.java b/tests/club/wpia/gigi/testUtils/BusinessTest.java index 28da80f8..4566d0e1 100644 --- a/tests/club/wpia/gigi/testUtils/BusinessTest.java +++ b/tests/club/wpia/gigi/testUtils/BusinessTest.java @@ -183,4 +183,13 @@ public abstract class BusinessTest extends ConfiguredTest { supporter.refreshGroups(); return supporter; } + + public EmailAddress createVerifiedEmail(User u, String email) throws InterruptedException, GigiApiException { + EmailAddress addr = new EmailAddress(u, email, Locale.ENGLISH); + TestMail testMail = getMailReceiver().receive(addr.getAddress()); + String hash = testMail.extractLink().substring(testMail.extractLink().lastIndexOf('=') + 1); + addr.verify(hash); + getMailReceiver().assertEmpty(); + return addr; + } }