]> WPIA git - gigi.git/commitdiff
add: implement + test api for find-an-agent-system
authorFelix Dörre <felix@dogcraft.de>
Sun, 17 Jul 2016 10:49:05 +0000 (12:49 +0200)
committerFelix Dörre <felix@dogcraft.de>
Sun, 17 Jul 2016 23:08:48 +0000 (01:08 +0200)
Change-Id: I7e90a6c4189107e07f06b9554e40699b7b9dfe16

src/org/cacert/gigi/Gigi.java
src/org/cacert/gigi/api/FindAgent.java [new file with mode: 0644]
src/org/cacert/gigi/api/GigiAPI.java
src/org/cacert/gigi/database/DatabaseConnection.java
src/org/cacert/gigi/database/tableStructure.sql
src/org/cacert/gigi/database/upgrade/from_18.sql [new file with mode: 0644]
src/org/cacert/gigi/dbObjects/Group.java
src/org/cacert/gigi/pages/account/FindAgentAccess.java [new file with mode: 0644]
src/org/cacert/gigi/pages/account/FindAgentAccess.templ [new file with mode: 0644]
tests/org/cacert/gigi/api/TestFindAgent.java [new file with mode: 0644]

index 37d0e62a0b6cdda673ecf668f9bf806d5353b115..ab0e1b6fa7e2acefa4f15feea664d18648b183cc 100644 (file)
@@ -31,6 +31,7 @@ import org.cacert.gigi.output.Menu;
 import org.cacert.gigi.output.MenuCollector;
 import org.cacert.gigi.output.PageMenuItem;
 import org.cacert.gigi.output.SimpleMenuItem;
+import org.cacert.gigi.output.template.Form;
 import org.cacert.gigi.output.template.Form.CSRFException;
 import org.cacert.gigi.output.template.Outputable;
 import org.cacert.gigi.output.template.Template;
@@ -39,6 +40,7 @@ import org.cacert.gigi.pages.HandlesMixedRequest;
 import org.cacert.gigi.pages.LoginPage;
 import org.cacert.gigi.pages.LogoutPage;
 import org.cacert.gigi.pages.MainPage;
+import org.cacert.gigi.pages.OneFormPage;
 import org.cacert.gigi.pages.Page;
 import org.cacert.gigi.pages.PasswordResetPage;
 import org.cacert.gigi.pages.RootCertPage;
@@ -46,6 +48,7 @@ import org.cacert.gigi.pages.StaticPage;
 import org.cacert.gigi.pages.TestSecure;
 import org.cacert.gigi.pages.Verify;
 import org.cacert.gigi.pages.account.ChangePasswordPage;
+import org.cacert.gigi.pages.account.FindAgentAccess;
 import org.cacert.gigi.pages.account.History;
 import org.cacert.gigi.pages.account.MyDetails;
 import org.cacert.gigi.pages.account.UserTrainings;
@@ -154,6 +157,13 @@ public final class Gigi extends HttpServlet {
             putPage(ChangePasswordPage.PATH, new ChangePasswordPage(), "My Account");
             putPage(LogoutPage.PATH, new LogoutPage(), "My Account");
             putPage(History.PATH, new History(false), "My Account");
+            putPage(FindAgentAccess.PATH, new OneFormPage("Access to Find Agent", FindAgentAccess.class) {
+
+                @Override
+                public String getSuccessPath(Form f) {
+                    return FindAgentAccess.PATH;
+                }
+            }, "My Account");
             putPage(History.SUPPORT_PATH, new History(true), null);
             putPage(UserTrainings.PATH, new UserTrainings(false), "My Account");
             putPage(MyDetails.PATH, new MyDetails(), "My Account");
diff --git a/src/org/cacert/gigi/api/FindAgent.java b/src/org/cacert/gigi/api/FindAgent.java
new file mode 100644 (file)
index 0000000..29e536e
--- /dev/null
@@ -0,0 +1,105 @@
+package org.cacert.gigi.api;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.cacert.gigi.dbObjects.Certificate;
+import org.cacert.gigi.dbObjects.CertificateOwner;
+import org.cacert.gigi.dbObjects.Group;
+import org.cacert.gigi.dbObjects.Organisation;
+import org.cacert.gigi.dbObjects.User;
+import org.cacert.gigi.email.EmailProvider;
+import org.cacert.gigi.pages.account.FindAgentAccess;
+import org.cacert.gigi.util.ServerConstants;
+
+public class FindAgent extends APIPoint {
+
+    public static final String PATH_RESOLVE = "/find-agent/resolve";
+
+    public static final String PATH_INFO = "/find-agent/info";
+
+    public static final String PATH_MAIL = "/find-agent/email";
+
+    public FindAgent() {}
+
+    public static void register(HashMap<String, APIPoint> api) {
+        APIPoint p = new FindAgent();
+        api.put(PATH_RESOLVE, p);
+        api.put(PATH_INFO, p);
+        api.put(PATH_MAIL, p);
+    }
+
+    @Override
+    public void process(HttpServletRequest req, HttpServletResponse resp, CertificateOwner u) throws IOException {
+        if ( !(u instanceof Organisation)) {
+            resp.sendError(500, "Error, invalid cert");
+            return;
+        }
+        if ( !((Organisation) u).isSelfOrganisation()) {
+            resp.sendError(500, "Error, invalid cert");
+            return;
+        }
+        String pi = req.getPathInfo();
+        if (pi.equals(PATH_RESOLVE)) {
+            String serial = req.getParameter("serial");
+            if (serial == null) {
+                resp.sendError(500, "Error, requires serial");
+                return;
+            }
+            Certificate c = Certificate.getBySerial(serial);
+            if (c == null) {
+                resp.sendError(500, "Error, requires serial");
+                return;
+            }
+            CertificateOwner co = c.getOwner();
+            if ( !(co instanceof User)) {
+                resp.sendError(500, "Error, requires serial");
+                return;
+            }
+            User us = (User) co;
+            if ( !us.isInGroup(Group.LOCATE_AGENT)) {
+                resp.setStatus(501);
+                resp.setContentType("text/plain; charset=UTF-8");
+                resp.getWriter().println("https://" + ServerConstants.getSecureHostNamePort() + FindAgentAccess.PATH);
+                return;
+            }
+            resp.setContentType("text/plain; charset=UTF-8");
+            resp.getWriter().print(us.getId());
+        } else if (pi.equals(PATH_INFO)) {
+            resp.setContentType("text/plain; charset=UTF-8");
+            String[] uids = req.getParameterValues("id");
+            for (String i : uids) {
+                User u1 = User.getById(Integer.parseInt(i));
+                if ( !u1.isInGroup(Group.LOCATE_AGENT)) {
+                    continue;
+                }
+                // date, recheck(?), name
+                resp.getWriter().println(i + "," + u1.canAssure() + "," + u1.getName().toString());
+            }
+        } else if (pi.equals(PATH_MAIL)) {
+            String id = req.getParameter("from");
+            String rid = req.getParameter("to");
+            String subject = req.getParameter("subject");
+            String body = req.getParameter("body");
+            if (id == null || rid == null || subject == null || body == null) {
+                resp.sendError(500, "Error, parameter missing");
+                return;
+            }
+            User from = User.getById(Integer.parseInt(id));
+            User to = User.getById(Integer.parseInt(rid));
+            if (from == null || to == null) {
+                resp.sendError(500, "Error, user not found");
+                return;
+            }
+            if ( !from.isInGroup(Group.LOCATE_AGENT) || !to.isInGroup(Group.LOCATE_AGENT)) {
+                resp.sendError(501, "Error, user needs to enable access");
+                return;
+
+            }
+            EmailProvider.getInstance().sendMail(to.getEmail(), "[Find Agent] " + subject, body, to.getEmail(), null, null, null, null, false);
+        }
+    }
+}
index dbac5a881b8a82dcb0ae100c43753f57af38526f..2f5e922c8e146aca32a348bfe880020b1e95e4c5 100644 (file)
@@ -24,6 +24,7 @@ public class GigiAPI extends HttpServlet {
         api.put(RevokeCertificate.PATH, new RevokeCertificate());
         api.put(CATSImport.PATH, new CATSImport());
         api.put(CATSResolve.PATH, new CATSResolve());
+        FindAgent.register(api);
     }
 
     @Override
index 0be7becdf90093ee8dddfd0693a77256656a9377..39071a3d365ed643a1bc289165afb5d4a5af3e72 100644 (file)
@@ -122,7 +122,7 @@ public class DatabaseConnection {
 
     }
 
-    public static final int CURRENT_SCHEMA_VERSION = 18;
+    public static final int CURRENT_SCHEMA_VERSION = 19;
 
     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
 
index 0764954c06358c3ad45d662dc0233849967dbc33..467160cd1bfbfff0e7c5d4c0da419c9c2e1c238a 100644 (file)
@@ -330,7 +330,7 @@ CREATE TABLE IF NOT EXISTS "arbitrations" (
 DROP TABLE IF EXISTS "user_groups";
 
 DROP TYPE IF EXISTS "userGroup";
-CREATE TYPE "userGroup" AS enum('supporter','arbitrator','blockedassuree','blockedassurer','blockedlogin','ttp-assurer','ttp-applicant', 'codesigning', 'orgassurer', 'blockedcert', 'nucleus-assurer');
+CREATE TYPE "userGroup" AS enum('supporter','arbitrator','blockedassuree','blockedassurer','blockedlogin','ttp-assurer','ttp-applicant', 'codesigning', 'orgassurer', 'blockedcert', 'nucleus-assurer', 'locate-agent');
 
 CREATE TABLE IF NOT EXISTS "user_groups" (
   "id" serial NOT NULL,
@@ -377,7 +377,7 @@ CREATE TABLE "schemeVersion" (
   "version" smallint NOT NULL,
   PRIMARY KEY ("version")
 );
-INSERT INTO "schemeVersion" (version)  VALUES(18);
+INSERT INTO "schemeVersion" (version)  VALUES(19);
 
 DROP TABLE IF EXISTS `passwordResetTickets`;
 CREATE TABLE `passwordResetTickets` (
diff --git a/src/org/cacert/gigi/database/upgrade/from_18.sql b/src/org/cacert/gigi/database/upgrade/from_18.sql
new file mode 100644 (file)
index 0000000..9e34028
--- /dev/null
@@ -0,0 +1 @@
+ALTER TYPE "userGroup" ADD VALUE 'locate-agent';
index 16cde6c1aa9e197268943fa3f2cb0e90d8f2b983..d5d38efde66a175172b88f2c0448d860d2cb8b2f 100644 (file)
@@ -11,7 +11,7 @@ public enum Group {
     BLOCKEDLOGIN("blockedlogin", "may not login"), BLOCKEDCERT("blockedcert", "may not issue certificates"), //
     TTP_ASSURER("ttp-assurer", "may assure via TTP"), TTP_APPLICANT("ttp-applicant", "requests to be assured via ttp"), //
     CODESIGNING("codesigning", "may issue codesigning certificates"), ORGASSURER("orgassurer", "may assure organisations"), //
-    NUCLEUS_ASSURER("nucleus-assurer", "may issue nucleus assurances");
+    NUCLEUS_ASSURER("nucleus-assurer", "may issue nucleus assurances"), LOCATE_AGENT("locate-agent", "wants access to the locate agent system");
 
     private final String dbName;
 
diff --git a/src/org/cacert/gigi/pages/account/FindAgentAccess.java b/src/org/cacert/gigi/pages/account/FindAgentAccess.java
new file mode 100644 (file)
index 0000000..2f325eb
--- /dev/null
@@ -0,0 +1,54 @@
+package org.cacert.gigi.pages.account;
+
+import java.io.PrintWriter;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.cacert.gigi.GigiApiException;
+import org.cacert.gigi.dbObjects.Group;
+import org.cacert.gigi.dbObjects.User;
+import org.cacert.gigi.localisation.Language;
+import org.cacert.gigi.output.template.Form;
+import org.cacert.gigi.output.template.Template;
+import org.cacert.gigi.pages.LoginPage;
+
+public class FindAgentAccess extends Form {
+
+    private User target;
+
+    public FindAgentAccess(HttpServletRequest hsr) {
+        super(hsr);
+        target = LoginPage.getUser(hsr);
+    }
+
+    public static final String PATH = "/account/find-agent";
+
+    private static Template t;
+    static {
+        t = new Template(ChangePasswordPage.class.getResource("FindAgentAccess.templ"));
+    }
+
+    @Override
+    public boolean submit(PrintWriter out, HttpServletRequest req) throws GigiApiException {
+        String nv = req.getParameter("new-val");
+        if (nv == null) {
+            return false;
+        }
+        if (nv.equals("enable")) {
+            target.grantGroup(target, Group.LOCATE_AGENT);
+        } else {
+            target.revokeGroup(target, Group.LOCATE_AGENT);
+        }
+        return true;
+    }
+
+    @Override
+    protected void outputContent(PrintWriter out, Language l, Map<String, Object> vars) {
+        boolean inGroup = target.isInGroup(Group.LOCATE_AGENT);
+        vars.put("enable", inGroup ? " disabled" : "");
+        vars.put("disable", !inGroup ? " disabled" : "");
+        t.output(out, l, vars);
+    }
+
+}
diff --git a/src/org/cacert/gigi/pages/account/FindAgentAccess.templ b/src/org/cacert/gigi/pages/account/FindAgentAccess.templ
new file mode 100644 (file)
index 0000000..4145636
--- /dev/null
@@ -0,0 +1,2 @@
+<button class="btn btn-primary" type="submit" name="new-val" value="enable"<?=$enable?>><?=_Enable Find-Assurer Access?></button>
+<button class="btn btn-primary" type="submit" name="new-val" value="disable"<?=$disable?>><?=_Disable Find-Assurer Access?></button>
diff --git a/tests/org/cacert/gigi/api/TestFindAgent.java b/tests/org/cacert/gigi/api/TestFindAgent.java
new file mode 100644 (file)
index 0000000..e889f1e
--- /dev/null
@@ -0,0 +1,87 @@
+package org.cacert.gigi.api;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.security.GeneralSecurityException;
+
+import org.cacert.gigi.GigiApiException;
+import org.cacert.gigi.dbObjects.Certificate;
+import org.cacert.gigi.dbObjects.Certificate.CSRType;
+import org.cacert.gigi.dbObjects.Certificate.SANType;
+import org.cacert.gigi.dbObjects.CertificateProfile;
+import org.cacert.gigi.dbObjects.Digest;
+import org.cacert.gigi.dbObjects.Group;
+import org.cacert.gigi.dbObjects.User;
+import org.cacert.gigi.pages.account.FindAgentAccess;
+import org.cacert.gigi.testUtils.IOUtils;
+import org.cacert.gigi.testUtils.RestrictedApiTest;
+import org.cacert.gigi.testUtils.TestEmailReceiver.TestMail;
+import org.junit.Test;
+
+public class TestFindAgent extends RestrictedApiTest {
+
+    @Test
+    public void testResolve() 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));
+
+        HttpURLConnection v = doApi(FindAgent.PATH_RESOLVE, "serial=" + target2.getSerial().toLowerCase());
+        assertEquals(501, v.getResponseCode());
+        assertThat(IOUtils.readURL(new InputStreamReader(v.getErrorStream(), "UTF-8")), containsString(FindAgentAccess.PATH));
+
+        grant(u.getEmail(), Group.LOCATE_AGENT);
+        v = doApi(FindAgent.PATH_RESOLVE, "serial=" + target2.getSerial().toLowerCase());
+        assertEquals(u.getId(), Integer.parseInt(IOUtils.readURL(v)));
+    }
+
+    @Test
+    public void testMailA() throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
+        testMail(true);
+    }
+
+    @Test
+    public void testMailB() throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
+        testMail(false);
+    }
+
+    public void testMail(boolean userUFirst) throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
+        int u2 = createVerifiedUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD);
+        User us2 = User.getById(u2);
+
+        // email sending fails
+        HttpURLConnection v = doApi(FindAgent.PATH_MAIL, "from=" + id + "&to=" + u2 + "&subject=the-subject&body=body");
+        assertEquals(v.getResponseMessage(), 501, v.getResponseCode());
+        assertThat(v.getResponseMessage(), containsString("needs to enable access"));
+
+        // even if sender enables service
+        grant((userUFirst ? u : us2).getEmail(), Group.LOCATE_AGENT);
+        v = doApi(FindAgent.PATH_MAIL, "from=" + id + "&to=" + u2 + "&subject=the-subject&body=body");
+        assertEquals(v.getResponseMessage(), 501, v.getResponseCode());
+        assertThat(v.getResponseMessage(), containsString("needs to enable access"));
+
+        // receiver needs to enable access as well
+        grant((userUFirst ? us2 : u).getEmail(), Group.LOCATE_AGENT);
+        v = doApi(FindAgent.PATH_MAIL, "from=" + id + "&to=" + u2 + "&subject=the-subject&body=body");
+        assertEquals(v.getResponseMessage(), 200, v.getResponseCode());
+        TestMail mail = getMailReceiver().receive();
+        assertEquals("body", mail.getMessage());
+        assertThat(mail.getSubject(), containsString("the-subject"));
+        assertEquals(us2.getEmail(), mail.getTo());
+    }
+
+    @Test
+    public void testLookupName() throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
+        int u2 = createVerifiedUser("f", "l", createUniqueName() + "@email.com", TEST_PASSWORD);
+
+        String res = IOUtils.readURL(doApi(FindAgent.PATH_INFO, "id=" + id + "&id=" + u2)).replace("\r", "");
+        assertEquals(res, "");
+        grant(email, Group.LOCATE_AGENT);
+        grant(User.getById(u2).getEmail(), Group.LOCATE_AGENT);
+        res = IOUtils.readURL(doApi(FindAgent.PATH_INFO, "id=" + id + "&id=" + u2)).replace("\r", "");
+        assertEquals(id + ",true," + u.getName().toString() + "\n" + u2 + ",false," + User.getById(u2).getName().toString() + "\n", res);
+    }
+}