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;
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;
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;
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");
--- /dev/null
+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);
+ }
+ }
+}
api.put(RevokeCertificate.PATH, new RevokeCertificate());
api.put(CATSImport.PATH, new CATSImport());
api.put(CATSResolve.PATH, new CATSResolve());
+ FindAgent.register(api);
}
@Override
}
- 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;
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,
"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` (
--- /dev/null
+ALTER TYPE "userGroup" ADD VALUE 'locate-agent';
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;
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+<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>
--- /dev/null
+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);
+ }
+}