From: Felix Dörre Date: Tue, 20 Feb 2018 20:21:39 +0000 (+0100) Subject: Merge changes I18f5f27f,I27ec303f,I78009fe3 X-Git-Url: https://code.wpia.club/?p=gigi.git;a=commitdiff_plain;h=985d31f75a724d141ff37bb678c28aaa474d5915;hp=ffb01a792727b470e7d24251f63cce0dc8bd462e Merge changes I18f5f27f,I27ec303f,I78009fe3 * changes: fix: avoid resource leak when generating OCSP requests fix: prevent possible NPE on failure to list the CA directory chg: ensure actor, target and support ticket are non-null --- diff --git a/links.txt b/links.txt index e68f4e90..d9dd6808 100644 --- a/links.txt +++ b/links.txt @@ -11,7 +11,9 @@ /kb/lostPassword /kb/goodPassword /kb/verificationHandbook +/kb/truststores /ttp/user /ttp/country /blog /imprint +/isocode http://www.iso.org/iso/home/standards/country_codes/iso-3166-1_decoding_table.htm diff --git a/src/club/wpia/gigi/Gigi.java b/src/club/wpia/gigi/Gigi.java index 6d8996c9..15a52143 100644 --- a/src/club/wpia/gigi/Gigi.java +++ b/src/club/wpia/gigi/Gigi.java @@ -64,6 +64,7 @@ import club.wpia.gigi.pages.admin.support.FindCertPage; import club.wpia.gigi.pages.admin.support.FindUserByDomainPage; import club.wpia.gigi.pages.admin.support.FindUserByEmailPage; import club.wpia.gigi.pages.admin.support.SupportEnterTicketPage; +import club.wpia.gigi.pages.admin.support.SupportOrgDomainPage; import club.wpia.gigi.pages.admin.support.SupportUserDetailsPage; import club.wpia.gigi.pages.error.AccessDenied; import club.wpia.gigi.pages.error.PageNotFound; @@ -71,6 +72,7 @@ import club.wpia.gigi.pages.main.CertStatusRequestPage; import club.wpia.gigi.pages.main.KeyCompromisePage; import club.wpia.gigi.pages.main.RegisterPage; import club.wpia.gigi.pages.orga.CreateOrgPage; +import club.wpia.gigi.pages.orga.SwitchOrganisation; import club.wpia.gigi.pages.orga.ViewOrgPage; import club.wpia.gigi.pages.statistics.StatisticsRoles; import club.wpia.gigi.pages.wot.Points; @@ -164,6 +166,7 @@ public final class Gigi extends HttpServlet { putPage(TTPAdminPage.PATH + "/*", new TTPAdminPage(), admMenu); putPage(CreateOrgPage.DEFAULT_PATH, new CreateOrgPage(), orgAdm); putPage(ViewOrgPage.DEFAULT_PATH + "/*", new ViewOrgPage(), orgAdm); + putPage(SwitchOrganisation.PATH, new SwitchOrganisation(), orgAdm); Menu support = createMenu("Support Console"); putPage(SupportEnterTicketPage.PATH, new SupportEnterTicketPage(), support); @@ -173,6 +176,7 @@ public final class Gigi extends HttpServlet { Menu account = createMenu("My Account"); putPage(SupportUserDetailsPage.PATH + "*", new SupportUserDetailsPage(), null); + putPage(SupportOrgDomainPage.PATH + "*", new SupportOrgDomainPage(), null); putPage(ChangePasswordPage.PATH, new ChangePasswordPage(), account); putPage(History.PATH, new History(false), account); putPage(FindAgentAccess.PATH, new OneFormPage("Access to Find Agent", FindAgentAccess.class), account); diff --git a/src/club/wpia/gigi/dbObjects/EmailAddress.java b/src/club/wpia/gigi/dbObjects/EmailAddress.java index 319e415b..7d4c984e 100644 --- a/src/club/wpia/gigi/dbObjects/EmailAddress.java +++ b/src/club/wpia/gigi/dbObjects/EmailAddress.java @@ -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(); } diff --git a/src/club/wpia/gigi/dbObjects/Organisation.java b/src/club/wpia/gigi/dbObjects/Organisation.java index c9754565..0e1c8661 100644 --- a/src/club/wpia/gigi/dbObjects/Organisation.java +++ b/src/club/wpia/gigi/dbObjects/Organisation.java @@ -152,7 +152,7 @@ public class Organisation extends CertificateOwner { public synchronized void addAdmin(User admin, User actor, boolean master) throws GigiApiException { if (actor == admin) { - throw new GigiApiException("You may not add yourself as Organisation Admin. Ask another Organisation Agent to do so."); + throw new GigiApiException("You may not add yourself as Organisation Admin. Ask another Organisation Agent or Organisation Admin to do so."); } if ( !admin.canVerify()) { throw new GigiApiException("Cannot add person who is not RA Agent."); diff --git a/src/club/wpia/gigi/pages/RootCertPage.java b/src/club/wpia/gigi/pages/RootCertPage.java index 9d1d9c90..b065463d 100644 --- a/src/club/wpia/gigi/pages/RootCertPage.java +++ b/src/club/wpia/gigi/pages/RootCertPage.java @@ -2,13 +2,13 @@ package club.wpia.gigi.pages; import java.io.IOException; import java.io.PrintWriter; +import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.LinkedList; import java.util.Map; @@ -16,11 +16,14 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import club.wpia.gigi.GigiApiException; import club.wpia.gigi.dbObjects.CACertificate; import club.wpia.gigi.localisation.Language; import club.wpia.gigi.output.template.Outputable; +import club.wpia.gigi.util.CertExporter; import club.wpia.gigi.util.HTMLEncoder; import club.wpia.gigi.util.PEM; +import club.wpia.gigi.util.ServerConstants; public class RootCertPage extends Page { @@ -30,6 +33,8 @@ public class RootCertPage extends Page { private final OutputableCertificate rootP; + private final String appName = ServerConstants.getAppName().toLowerCase(); + private class OutputableCertificate implements Outputable { private final CACertificate target; @@ -97,6 +102,7 @@ public class RootCertPage extends Page { public boolean beforeTemplate(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (req.getParameter("pem") != null && root != null) { resp.setContentType("application/x-x509-ca-cert"); + resp.setHeader("Content-Disposition", "attachment; filename=\"" + appName + "_roots.crt\""); ServletOutputStream out = resp.getOutputStream(); try { out.println(PEM.encode("CERTIFICATE", root.getEncoded())); @@ -104,8 +110,23 @@ public class RootCertPage extends Page { e.printStackTrace(); } return true; + } else if (req.getParameter("bundle") != null && root != null) { + resp.setContentType("application/x-x509-ca-cert"); + resp.setHeader("Content-Disposition", "attachment; filename=\"" + appName + "_intermediate_bundle.p7b\""); + ServletOutputStream out = resp.getOutputStream(); + try { + CertExporter.writeCertBundle(out); + } catch (CertificateEncodingException e) { + e.printStackTrace(); + } catch (GeneralSecurityException e) { + e.printStackTrace(); + } catch (GigiApiException e) { + e.printStackTrace(); + } + return true; } else if (req.getParameter("cer") != null && root != null) { resp.setContentType("application/x-x509-ca-cert"); + resp.setHeader("Content-Disposition", "attachment; filename=\"" + appName + "_roots.cer\""); ServletOutputStream out = resp.getOutputStream(); try { out.write(root.getEncoded()); @@ -119,8 +140,9 @@ public class RootCertPage extends Page { @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - HashMap map = new HashMap(); + Map map = Page.getDefaultVars(req); map.put("root", rootP); + map.put("bundle", appName + "_intermediate_bundle.p7b"); getDefaultTemplate().output(resp.getWriter(), getLanguage(req), map); } diff --git a/src/club/wpia/gigi/pages/RootCertPage.templ b/src/club/wpia/gigi/pages/RootCertPage.templ index 0f6a8f05..899470ec 100644 --- a/src/club/wpia/gigi/pages/RootCertPage.templ +++ b/src/club/wpia/gigi/pages/RootCertPage.templ @@ -1,5 +1,8 @@ -
-PEM DER +


+PEM DER

+


+

+

'.?>

diff --git a/src/club/wpia/gigi/pages/account/MyDetails.java b/src/club/wpia/gigi/pages/account/MyDetails.java index 12d127fa..b4a52d4e 100644 --- a/src/club/wpia/gigi/pages/account/MyDetails.java +++ b/src/club/wpia/gigi/pages/account/MyDetails.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse; import club.wpia.gigi.output.template.Form; import club.wpia.gigi.pages.LoginPage; import club.wpia.gigi.pages.Page; +import club.wpia.gigi.pages.orga.MyOrganisationsForm; public class MyDetails extends Page { diff --git a/src/club/wpia/gigi/pages/account/MyOrganisationsForm.templ b/src/club/wpia/gigi/pages/account/MyOrganisationsForm.templ deleted file mode 100644 index 96d7bbe7..00000000 --- a/src/club/wpia/gigi/pages/account/MyOrganisationsForm.templ +++ /dev/null @@ -1,10 +0,0 @@ - -

- - - - -
- - - diff --git a/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java b/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java index 8a1bc594..cdf4dd41 100644 --- a/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java +++ b/src/club/wpia/gigi/pages/account/certs/CertificateRequest.java @@ -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(// diff --git a/src/club/wpia/gigi/pages/admin/support/FindUserByDomainForm.java b/src/club/wpia/gigi/pages/admin/support/FindUserByDomainForm.java index 75c8c590..500a3b0a 100644 --- a/src/club/wpia/gigi/pages/admin/support/FindUserByDomainForm.java +++ b/src/club/wpia/gigi/pages/admin/support/FindUserByDomainForm.java @@ -59,7 +59,7 @@ public class FindUserByDomainForm extends Form { if (res instanceof User) { return new RedirectResult(SupportUserDetailsPage.PATH + res.getId() + "/"); } else if (res instanceof Organisation) { - return new RedirectResult("/support/domain/" + res.getId()); + return new RedirectResult(SupportOrgDomainPage.PATH + d.getId()); } else { throw new PermamentFormException(new GigiApiException("Unknown owner type.")); } diff --git a/src/club/wpia/gigi/pages/admin/support/SupportOrgDomainPage.java b/src/club/wpia/gigi/pages/admin/support/SupportOrgDomainPage.java new file mode 100644 index 00000000..019f2496 --- /dev/null +++ b/src/club/wpia/gigi/pages/admin/support/SupportOrgDomainPage.java @@ -0,0 +1,59 @@ +package club.wpia.gigi.pages.admin.support; + +import java.io.IOException; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import club.wpia.gigi.dbObjects.Domain; +import club.wpia.gigi.dbObjects.Organisation; +import club.wpia.gigi.pages.Page; +import club.wpia.gigi.util.AuthorizationContext; + +public class SupportOrgDomainPage extends Page { + + public static final String PATH = "/support/domain/"; + + public SupportOrgDomainPage() { + super("Support: Organisation Domain"); + } + + @Override + public boolean isPermitted(AuthorizationContext ac) { + return ac != null && ac.canSupport(); + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + Domain orgDomain = getDomain(req, resp); + if (orgDomain == null) { + return; + } + + Organisation org = Organisation.getById(orgDomain.getOwner().getId()); + Map vars = getDefaultVars(req); + vars.put("domain", orgDomain.getSuffix()); + vars.put("organisation", org.getName()); + + getDefaultTemplate().output(resp.getWriter(), getLanguage(req), vars); + } + + private Domain getDomain(HttpServletRequest req, HttpServletResponse resp) throws IOException { + int id = -1; + String[] idP = req.getPathInfo().split("/"); + try { + id = Integer.parseInt(idP[idP.length - 1]); + } catch (NumberFormatException e) { + resp.sendError(400); + return null; + } + final Domain domain = Domain.getById(id); + if (domain == null) { + resp.sendError(400); + return null; + } + return domain; + } + +} diff --git a/src/club/wpia/gigi/pages/admin/support/SupportOrgDomainPage.templ b/src/club/wpia/gigi/pages/admin/support/SupportOrgDomainPage.templ new file mode 100644 index 00000000..79f5e349 --- /dev/null +++ b/src/club/wpia/gigi/pages/admin/support/SupportOrgDomainPage.templ @@ -0,0 +1 @@ + diff --git a/src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.java b/src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.java index 969cbe62..7445c52c 100644 --- a/src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.java +++ b/src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.java @@ -6,6 +6,7 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; +import club.wpia.gigi.Gigi; import club.wpia.gigi.GigiApiException; import club.wpia.gigi.dbObjects.Group; import club.wpia.gigi.dbObjects.Name; @@ -20,6 +21,8 @@ import club.wpia.gigi.output.template.Form; import club.wpia.gigi.output.template.Template; import club.wpia.gigi.output.template.TranslateCommand; import club.wpia.gigi.pages.LoginPage; +import club.wpia.gigi.pages.account.MyDetails; +import club.wpia.gigi.util.AuthorizationContext; public class SupportUserDetailsForm extends Form { @@ -42,12 +45,31 @@ public class SupportUserDetailsForm extends Form { if (user.getTicket() == null) { throw new GigiApiException("No ticket number set."); } + + int numActions = 0; + numActions += req.getParameter("detailupdate") != null ? 1 : 0; + numActions += req.getParameter("addGroup") != null ? 1 : 0; + numActions += req.getParameter("removeGroup") != null ? 1 : 0; + numActions += req.getParameter("resetPass") != null ? 1 : 0; + + if (numActions != 1) { + throw new GigiApiException("More than one action requested!"); + } + if (user.getTargetUser() == LoginPage.getUser(req)) { + if (req.getParameter("removeGroup") != null) { + value.update(req); + Group toMod = value.getGroup(); + if (toMod == Group.SUPPORTER) { + user.revoke(toMod); + AuthorizationContext ac = LoginPage.getAuthorizationContext(req); + req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(ac.getActor(), ac.getActor())); + return new RedirectResult(MyDetails.PATH); + } + } throw new GigiApiException("Supporter may not modify himself."); } - if ((req.getParameter("detailupdate") != null ? 1 : 0) + (req.getParameter("addGroup") != null ? 1 : 0) + (req.getParameter("removeGroup") != null ? 1 : 0) + (req.getParameter("resetPass") != null ? 1 : 0) != 1) { - throw new GigiApiException("More than one action requested!"); - } + if (req.getParameter("addGroup") != null || req.getParameter("removeGroup") != null) { value.update(req); Group toMod = value.getGroup(); diff --git a/src/club/wpia/gigi/pages/orga/AffiliationForm.java b/src/club/wpia/gigi/pages/orga/AffiliationForm.java index 278e38b7..1fd1c010 100644 --- a/src/club/wpia/gigi/pages/orga/AffiliationForm.java +++ b/src/club/wpia/gigi/pages/orga/AffiliationForm.java @@ -39,7 +39,7 @@ public class AffiliationForm extends Form { } else if (req.getParameter("do_affiliate") != null) { User byEmail = User.getByEmail(req.getParameter("email")); if (byEmail == null) { - throw new GigiApiException("To add an admin, the email address is required."); + throw new GigiApiException("To add an admin, the email address needs to be known to the system."); } if (byEmail.canVerify()) { o.addAdmin(byEmail, LoginPage.getUser(req), req.getParameter("master") != null); diff --git a/src/club/wpia/gigi/pages/orga/CreateOrgForm.templ b/src/club/wpia/gigi/pages/orga/CreateOrgForm.templ index 7fdd98de..865f8dde 100644 --- a/src/club/wpia/gigi/pages/orga/CreateOrgForm.templ +++ b/src/club/wpia/gigi/pages/orga/CreateOrgForm.templ @@ -28,7 +28,7 @@ : - 'ISO code!'')?> + ')?> diff --git a/src/club/wpia/gigi/pages/orga/CreateOrgPage.java b/src/club/wpia/gigi/pages/orga/CreateOrgPage.java index 4eab3d6e..98076fe9 100644 --- a/src/club/wpia/gigi/pages/orga/CreateOrgPage.java +++ b/src/club/wpia/gigi/pages/orga/CreateOrgPage.java @@ -1,7 +1,6 @@ package club.wpia.gigi.pages.orga; import java.io.IOException; -import java.util.HashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -27,6 +26,6 @@ public class CreateOrgPage extends ManagedFormPage { @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - new CreateOrgForm(req).output(resp.getWriter(), getLanguage(req), new HashMap()); + new CreateOrgForm(req).output(resp.getWriter(), getLanguage(req), getDefaultVars(req)); } } diff --git a/src/club/wpia/gigi/pages/account/MyOrganisationsForm.java b/src/club/wpia/gigi/pages/orga/MyOrganisationsForm.java similarity index 94% rename from src/club/wpia/gigi/pages/account/MyOrganisationsForm.java rename to src/club/wpia/gigi/pages/orga/MyOrganisationsForm.java index 835973a1..8858c5c0 100644 --- a/src/club/wpia/gigi/pages/account/MyOrganisationsForm.java +++ b/src/club/wpia/gigi/pages/orga/MyOrganisationsForm.java @@ -1,4 +1,4 @@ -package club.wpia.gigi.pages.account; +package club.wpia.gigi.pages.orga; import java.io.PrintWriter; import java.util.Enumeration; @@ -33,7 +33,7 @@ public class MyOrganisationsForm extends Form { public SubmissionResult submit(HttpServletRequest req) throws GigiApiException { if (req.getParameter("org-leave") != null) { req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(target.getActor(), target.getActor())); - return new RedirectResult(MyDetails.PATH); + return new RedirectResult(SwitchOrganisation.PATH); } Enumeration i = req.getParameterNames(); int orgId = -1; @@ -52,7 +52,7 @@ public class MyOrganisationsForm extends Form { if (org.getId() == orgId) { req.getSession().setAttribute(Gigi.AUTH_CONTEXT, new AuthorizationContext(org, target.getActor())); - return new RedirectResult(MyDetails.PATH); + return new RedirectResult(SwitchOrganisation.PATH); } } throw new PermamentFormException(new GigiApiException("Context switch failed.")); diff --git a/src/club/wpia/gigi/pages/orga/MyOrganisationsForm.templ b/src/club/wpia/gigi/pages/orga/MyOrganisationsForm.templ new file mode 100644 index 00000000..5c63f04f --- /dev/null +++ b/src/club/wpia/gigi/pages/orga/MyOrganisationsForm.templ @@ -0,0 +1,9 @@ +

+ + + + + + + +
diff --git a/src/club/wpia/gigi/pages/orga/SwitchOrganisation.java b/src/club/wpia/gigi/pages/orga/SwitchOrganisation.java new file mode 100644 index 00000000..16dfe6ed --- /dev/null +++ b/src/club/wpia/gigi/pages/orga/SwitchOrganisation.java @@ -0,0 +1,29 @@ +package club.wpia.gigi.pages.orga; + +import java.io.IOException; +import java.util.HashMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import club.wpia.gigi.pages.ManagedFormPage; +import club.wpia.gigi.util.AuthorizationContext; + +public class SwitchOrganisation extends ManagedFormPage { + + public static final String PATH = "/orga/switch-orga"; + + public SwitchOrganisation() { + super("Switch to Organisation", MyOrganisationsForm.class); + } + + @Override + public boolean isPermitted(AuthorizationContext ac) { + return ac != null && ac.getActor().getOrganisations().size() != 0; + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + new MyOrganisationsForm(req).output(resp.getWriter(), getLanguage(req), new HashMap()); + } +} diff --git a/src/club/wpia/gigi/pages/orga/ViewOrgPage.java b/src/club/wpia/gigi/pages/orga/ViewOrgPage.java index d676c1de..909f9efe 100644 --- a/src/club/wpia/gigi/pages/orga/ViewOrgPage.java +++ b/src/club/wpia/gigi/pages/orga/ViewOrgPage.java @@ -13,11 +13,12 @@ import club.wpia.gigi.dbObjects.Organisation; import club.wpia.gigi.dbObjects.User; import club.wpia.gigi.localisation.Language; import club.wpia.gigi.output.template.Form; +import club.wpia.gigi.output.template.Form.CSRFException; import club.wpia.gigi.output.template.IterableDataset; import club.wpia.gigi.output.template.Template; -import club.wpia.gigi.output.template.Form.CSRFException; import club.wpia.gigi.pages.LoginPage; import club.wpia.gigi.pages.ManagedMultiFormPage; +import club.wpia.gigi.pages.Page; import club.wpia.gigi.pages.account.domain.DomainManagementForm; import club.wpia.gigi.util.AuthorizationContext; @@ -91,7 +92,7 @@ public class ViewOrgPage extends ManagedMultiFormPage { resp.sendError(404); return; } - HashMap vars = new HashMap<>(); + Map vars = Page.getDefaultVars(req); if (orgAss) { vars.put("editForm", new CreateOrgForm(req, o)); vars.put("affForm", new AffiliationForm(req, o)); diff --git a/src/club/wpia/gigi/util/CertExporter.java b/src/club/wpia/gigi/util/CertExporter.java index 06102fc0..5d465919 100644 --- a/src/club/wpia/gigi/util/CertExporter.java +++ b/src/club/wpia/gigi/util/CertExporter.java @@ -1,6 +1,7 @@ package club.wpia.gigi.util; import java.io.IOException; +import java.io.OutputStream; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.cert.CRLException; @@ -58,7 +59,12 @@ public class CertExporter { } private static PKCS7 toP7Chain(Certificate c) throws IOException, GeneralSecurityException, GigiApiException { - LinkedList ll = getChain(c); + + return generateP7Bundle(getChain(c)); + + } + + private static PKCS7 generateP7Bundle(LinkedList ll) { PKCS7 p7 = new PKCS7(new AlgorithmId[0], new ContentInfo(ContentInfo.DATA_OID, null), ll.toArray(new X509Certificate[ll.size()]), new SignerInfo[0]) { @Override @@ -164,4 +170,17 @@ public class CertExporter { return ll; } + public static void writeCertBundle(OutputStream out) throws IOException, GeneralSecurityException, GigiApiException { + + CACertificate[] cs = CACertificate.getAll(); + LinkedList ll = new LinkedList<>(); + for (CACertificate cb : cs) { + if ( !cb.isSelfsigned()) { + ll.add(cb.getCertificate()); + } + } + + PKCS7 p7 = generateP7Bundle(ll); + p7.encodeSignedData(out); + } } diff --git a/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java b/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java index 79edd932..da580ccf 100644 --- a/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java +++ b/tests/club/wpia/gigi/pages/account/TestCertificateRequest.java @@ -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")); + } + + } } diff --git a/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java b/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java index 30aeb64f..97ac6a00 100644 --- a/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java +++ b/tests/club/wpia/gigi/pages/admin/TestSEAdminNotificationMail.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; +import java.net.URLConnection; import java.net.URLEncoder; import java.util.HashMap; import java.util.Locale; @@ -17,10 +18,13 @@ import club.wpia.gigi.GigiApiException; import club.wpia.gigi.dbObjects.Group; import club.wpia.gigi.dbObjects.User; import club.wpia.gigi.localisation.Language; +import club.wpia.gigi.pages.account.MyDetails; import club.wpia.gigi.pages.admin.support.SupportUserDetailsPage; +import club.wpia.gigi.testUtils.IOUtils; import club.wpia.gigi.testUtils.SEClientTest; import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail; import club.wpia.gigi.util.ServerConstants; +import club.wpia.gigi.util.ServerConstants.Host; public class TestSEAdminNotificationMail extends SEClientTest { @@ -141,4 +145,34 @@ public class TestSEAdminNotificationMail extends SEClientTest { message = getMailReceiver().receive(targetEmail).getMessage(); assertThat(message, containsString("All certificates in your account have been revoked.")); } + + @Test + public void testSupportSupporterGroup() throws MalformedURLException, IOException { + // supporter adds to his own groups + String s = IOUtils.readURL(post(SupportUserDetailsPage.PATH + u.getId() + "/", "addGroup&groupToModify=" + URLEncoder.encode(Group.ORG_AGENT.getDBName(), "UTF-8"))); + assertThat(s, containsString("Supporter may not modify himself.")); + + // supporter removes from his own groups + s = IOUtils.readURL(post(SupportUserDetailsPage.PATH + u.getId() + "/", "removeGroup&groupToModify=" + URLEncoder.encode(Group.ORG_AGENT.getDBName(), "UTF-8"))); + assertThat(s, containsString("Supporter may not modify himself.")); + + // supporter removes supporter flag + URLConnection uc = post(SupportUserDetailsPage.PATH + u.getId() + "/", "removeGroup&groupToModify=" + URLEncoder.encode(Group.SUPPORTER.getDBName(), "UTF-8")); + assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + MyDetails.PATH, uc.getHeaderField("Location")); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Group.SUPPORTER.getName().output(pw, Language.getInstance(Locale.ENGLISH), new HashMap()); + // mail to support + String message = getMailReceiver().receive(ServerConstants.getSupportMailAddress()).getMessage(); + assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked.")); + // mail to user + message = getMailReceiver().receive(u.getEmail()).getMessage(); + assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked from your account.")); + // mail to board + message = getMailReceiver().receive(ServerConstants.getBoardMailAddress()).getMessage(); + assertThat(message, containsString("The group permission '" + sw.toString() + "' was revoked for '" + u.getPreferredName().toString() + "'.")); + s = IOUtils.readURL(get(cookie, MyDetails.PATH)); + assertThat(s, not(containsString("supporter"))); + } + } diff --git a/tests/club/wpia/gigi/pages/admin/TestSEAdminPageUserDomainSearch.java b/tests/club/wpia/gigi/pages/admin/TestSEAdminPageUserDomainSearch.java index 383d2326..d820a1d1 100644 --- a/tests/club/wpia/gigi/pages/admin/TestSEAdminPageUserDomainSearch.java +++ b/tests/club/wpia/gigi/pages/admin/TestSEAdminPageUserDomainSearch.java @@ -1,9 +1,11 @@ package club.wpia.gigi.pages.admin; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URLConnection; import java.net.URLEncoder; @@ -13,9 +15,14 @@ import org.junit.Assume; import org.junit.Test; import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.dbObjects.Country; +import club.wpia.gigi.dbObjects.Country.CountryCodeType; import club.wpia.gigi.dbObjects.Domain; +import club.wpia.gigi.dbObjects.Group; +import club.wpia.gigi.dbObjects.Organisation; import club.wpia.gigi.dbObjects.User; import club.wpia.gigi.pages.admin.support.FindUserByDomainPage; +import club.wpia.gigi.pages.admin.support.SupportOrgDomainPage; import club.wpia.gigi.pages.admin.support.SupportUserDetailsPage; import club.wpia.gigi.testUtils.IOUtils; import club.wpia.gigi.testUtils.SEClientTest; @@ -72,4 +79,38 @@ public class TestSEAdminPageUserDomainSearch extends SEClientTest { URLConnection uc = post(FindUserByDomainPage.PATH, "process&domain=#" + id); assertNotNull(fetchStartErrorMessage(IOUtils.readURL(uc))); } + + @Test + public void testOrgDomainSearch() throws MalformedURLException, UnsupportedEncodingException, IOException, GigiApiException { + // generate organisation with domain + u.grantGroup(getSupporter(), Group.ORG_AGENT); + Organisation o1 = new Organisation(createUniqueName(), Country.getCountryByCode("DE", CountryCodeType.CODE_2_CHARS), "pr", "city", "test@example.com", "", "", u); + String dom = createUniqueName() + ".de"; + Domain d = new Domain(u, o1, dom); + + // test + URLConnection uc = post(FindUserByDomainPage.PATH, "process&domain=" + URLEncoder.encode(dom, "UTF-8")); + + assertEquals("https://" + ServerConstants.getHostNamePortSecure(Host.WWW) + SupportOrgDomainPage.PATH + d.getId(), uc.getHeaderField("Location")); + + String s = IOUtils.readURL(get(cookie, SupportOrgDomainPage.PATH + d.getId())); + assertThat(s, containsString(dom)); + assertThat(s, containsString(o1.getName())); + + // test malformated id + HttpURLConnection uc1 = get(SupportOrgDomainPage.PATH + d.getId() + "a"); + assertEquals(400, uc1.getResponseCode()); + + // test non existing id + uc1 = get(SupportOrgDomainPage.PATH + "5000"); + assertEquals(400, uc1.getResponseCode()); + + } + + @Test + public void testDomainSearchByMalformatedId() throws MalformedURLException, UnsupportedEncodingException, IOException, GigiApiException { + URLConnection uc = post(FindUserByDomainPage.PATH, "process&domain=#" + d.getId() + "a"); + assertNotNull(fetchStartErrorMessage(IOUtils.readURL(uc))); + } + } diff --git a/tests/club/wpia/gigi/pages/orga/TestOrgSwitch.java b/tests/club/wpia/gigi/pages/orga/TestOrgSwitch.java new file mode 100644 index 00000000..94586e34 --- /dev/null +++ b/tests/club/wpia/gigi/pages/orga/TestOrgSwitch.java @@ -0,0 +1,121 @@ +package club.wpia.gigi.pages.orga; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.*; + +import java.io.IOException; +import java.net.URLEncoder; +import java.sql.SQLException; + +import org.junit.After; +import org.junit.Test; + +import club.wpia.gigi.GigiApiException; +import club.wpia.gigi.dbObjects.Organisation; +import club.wpia.gigi.dbObjects.User; +import club.wpia.gigi.testUtils.IOUtils; +import club.wpia.gigi.testUtils.OrgTest; + +public class TestOrgSwitch extends OrgTest { + + private User u2; + + private Organisation org1 = createUniqueOrg(); + + private Organisation org2 = createUniqueOrg(); + + public TestOrgSwitch() throws IOException, GigiApiException { + + assertEquals(403, get(SwitchOrganisation.PATH).getResponseCode()); + + String email = createUniqueName() + "@testdom.com"; + u2 = User.getById(createVerificationUser("testworker", "testname", email, TEST_PASSWORD)); + assertNull(executeBasicWebInteraction(cookie, ViewOrgPage.DEFAULT_PATH + "/" + org1.getId(), "email=" + URLEncoder.encode(u2.getEmail(), "UTF-8") + "&do_affiliate=y&master=y", 1)); + assertNull(executeBasicWebInteraction(cookie, ViewOrgPage.DEFAULT_PATH + "/" + org2.getId(), "email=" + URLEncoder.encode(u2.getEmail(), "UTF-8") + "&do_affiliate=y&master=y", 1)); + + // login with new user u2 + cookie = login(email, TEST_PASSWORD); + } + + @After + public void purgeDbAfterTest() throws SQLException, IOException { + purgeDatabase(); + } + + @Test + public void testSwitchToOrg() throws IOException, GigiApiException { + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org1.getId() + "=y", 0)); + + String res = IOUtils.readURL(get(SwitchOrganisation.PATH)); + assertThat(res, containsString("Logged in as " + org1.getName() + " (on behalf of " + u2.getPreferredName())); + + } + + @Test + public void testSwitchToNonOrg() throws IOException, GigiApiException { + + String res = IOUtils.readURL(post(SwitchOrganisation.PATH, "org:5000=y")); + assertThat(res, containsString("Context switch failed")); + + } + + @Test + public void testSwitchToPersonal() throws IOException, GigiApiException { + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org-leave=personal", 0)); + + String res = IOUtils.readURL(get(SwitchOrganisation.PATH)); + assertThat(res, containsString("Logged in as " + u2.getPreferredName())); + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org-leave=personal", 0)); + + res = IOUtils.readURL(get(SwitchOrganisation.PATH)); + assertThat(res, containsString("Logged in as " + u2.getPreferredName())); + + } + + @Test + public void testSwitchOrgToOrg() throws IOException, GigiApiException { + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org1.getId() + "=y", 0)); + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org2.getId() + "=y", 0)); + + String res = IOUtils.readURL(get(SwitchOrganisation.PATH)); + assertThat(res, containsString("Logged in as " + org2.getName() + " (on behalf of " + u2.getPreferredName())); + + } + + @Test + public void testSwitchOrgToSameOrg() throws IOException, GigiApiException { + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org1.getId() + "=y", 0)); + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org1.getId() + "=y", 0)); + + String res = IOUtils.readURL(get(SwitchOrganisation.PATH)); + assertThat(res, containsString("Logged in as " + org1.getName() + " (on behalf of " + u2.getPreferredName())); + + } + + @Test + public void testSwitchOrgToNonOrg() throws IOException, GigiApiException { + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org1.getId() + "=y", 0)); + String res = IOUtils.readURL(post(SwitchOrganisation.PATH, "org:5000=y")); + assertThat(res, containsString("Context switch failed")); + + } + + @Test + public void testSwitchOrgToPersonal() throws IOException, GigiApiException { + + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org:" + org1.getId() + "=y", 0)); + assertNull(executeBasicWebInteraction(cookie, SwitchOrganisation.PATH, "org-leave=personal", 0)); + + String res = IOUtils.readURL(get(SwitchOrganisation.PATH)); + assertThat(res, containsString("Logged in as " + u2.getPreferredName())); + + } + +} diff --git a/util-testing/club/wpia/gigi/pages/Manager.templ b/util-testing/club/wpia/gigi/pages/Manager.templ index ea375e87..36afa443 100644 --- a/util-testing/club/wpia/gigi/pages/Manager.templ +++ b/util-testing/club/wpia/gigi/pages/Manager.templ @@ -1,10 +1,10 @@
-Batch create users: +Batch Create Users:
- Email: + Email: NNN@
@@ -12,9 +12,9 @@ Amount:
-Add privilege: +Add Privilege: -Email: +Email: - - + +
@@ -40,7 +40,7 @@ Email:
-Add CATs entry: +Add Qualifying Challenge Entry: Email: @@ -49,7 +49,7 @@ Email: - +
Add 100 Verification Points: @@ -62,7 +62,7 @@ Verification Points to issue to preferred name:
-Verify 25 others (get 100 Experience Points) : +Verify 25 Others (get 100 Experience Points): Email: @@ -70,12 +70,12 @@ Email:
-Add verified Email: +Add Verified Email: Email: -new Email: - +New Email: +
@@ -83,7 +83,7 @@ Add Client Cert: Email: - +
@@ -98,7 +98,7 @@ Domain:
-Test server settings +Test Server Settings