]> WPIA git - gigi.git/commitdiff
Merge "add: add (OU) to make sure what is the entry department used for"
authorFelix Dörre <felix@dogcraft.de>
Thu, 19 Dec 2019 07:19:14 +0000 (07:19 +0000)
committerGerrit Code Review <gigi-system@dogcraft.de>
Thu, 19 Dec 2019 07:19:14 +0000 (07:19 +0000)
28 files changed:
config/generateTruststoreNRE.sh
src/club/wpia/gigi/Gigi.java
src/club/wpia/gigi/database/DatabaseConnection.java
src/club/wpia/gigi/database/tableStructure.sql
src/club/wpia/gigi/database/upgrade/from_37.sql [new file with mode: 0644]
src/club/wpia/gigi/dbObjects/Contract.java [new file with mode: 0644]
src/club/wpia/gigi/dbObjects/ContractNotice.templ [new file with mode: 0644]
src/club/wpia/gigi/dbObjects/User.java
src/club/wpia/gigi/pages/account/MyContracts.java [new file with mode: 0644]
src/club/wpia/gigi/pages/account/MyContracts.templ [new file with mode: 0644]
src/club/wpia/gigi/pages/account/MyDetailsContracts.templ [new file with mode: 0644]
src/club/wpia/gigi/pages/account/MyDetailsForm.java
src/club/wpia/gigi/pages/account/certs/CertificateIssueForm.java
src/club/wpia/gigi/pages/account/certs/CertificateRequest.java
src/club/wpia/gigi/pages/account/certs/RequestCertificate.templ
src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.java
src/club/wpia/gigi/pages/admin/support/SupportUserDetailsForm.templ
tests/club/wpia/gigi/dbObjects/TestContract.java [new file with mode: 0644]
tests/club/wpia/gigi/dbObjects/TestUser.java
tests/club/wpia/gigi/pages/TestMain.java
tests/club/wpia/gigi/pages/account/TestCertificateAdd.java
tests/club/wpia/gigi/pages/account/TestCertificateRequest.java
tests/club/wpia/gigi/pages/admin/TestSEAdminPageDetails.java
tests/club/wpia/gigi/pages/wot/TestVerification.java
tests/club/wpia/gigi/testUtils/ConfiguredTest.java
tests/club/wpia/gigi/util/TestNotary.java
util-testing/club/wpia/gigi/pages/Manager.java
util-testing/club/wpia/gigi/pages/Manager.templ

index ca0c28a5bb5bbfc5e6eb12c9053b703f22ee408b..4955a1f9c08435f6dceb21c6b440c98463b637d2 100755 (executable)
@@ -47,8 +47,8 @@ if [[ -f "$ca.key" ]] && ! [[ -f keystore.pkcs12 ]]; then
     openssl req -newkey rsa:2048 -keyout mail.key -out mail.csr -nodes -subj "/CN=gigi system"
 
     # Sign the two requests with the keys in the config of the simple signer. Use the serial_base with extensions 1 and 2. These serials are long enough to probably not collide with the "simple signer"
-    openssl x509 -req -days 356 -in www.csr -out www.crt -CA $ca.crt -CAkey $ca.key -set_serial ${serial_base}1 -extfile <(printf '[ext]\nsubjectAltName=DNS:www.%s,DNS:secure.%s,DNS:static.%s,DNS:api.%s\nbasicConstraints=CA:FALSE\nextendedKeyUsage=serverAuth\nkeyUsage=digitalSignature,keyEncipherment\n' "$DOMAIN" "$DOMAIN" "$DOMAIN" "$DOMAIN") -extensions ext
-    openssl x509 -req -days 356 -in mail.csr -out mail.crt -CA $ca.crt -CAkey $ca.key -set_serial ${serial_base}2 -extfile <(printf '[ext]\nsubjectAltName=email:support@%s\nbasicConstraints=CA:FALSE\nextendedKeyUsage=emailProtection\nkeyUsage=digitalSignature,keyEncipherment\n' "$DOMAIN") -extensions ext
+    openssl x509 -req -days 365 -in www.csr -out www.crt -CA $ca.crt -CAkey $ca.key -set_serial ${serial_base}1 -extfile <(printf '[ext]\nsubjectAltName=DNS:www.%s,DNS:secure.%s,DNS:static.%s,DNS:api.%s\nbasicConstraints=CA:FALSE\nextendedKeyUsage=serverAuth\nkeyUsage=digitalSignature,keyEncipherment\n' "$DOMAIN" "$DOMAIN" "$DOMAIN" "$DOMAIN") -extensions ext
+    openssl x509 -req -days 365 -in mail.csr -out mail.crt -CA $ca.crt -CAkey $ca.key -set_serial ${serial_base}2 -extfile <(printf '[ext]\nsubjectAltName=email:support@%s\nbasicConstraints=CA:FALSE\nextendedKeyUsage=emailProtection\nkeyUsage=digitalSignature,keyEncipherment\n' "$DOMAIN") -extensions ext
 
     # Store the webserver cert in 4 different pkcs12-keystores to have different "key aliases" and import them all into the "keystore.pkcs12" using the "importP"-method
     for t in www api secure static; do
index e76c51710e6c1c664d19c72c176d238f9f05c2ee..d33d546d9558cf02882f21365ce030c4e80eb31b 100644 (file)
@@ -57,6 +57,7 @@ import club.wpia.gigi.pages.Verify;
 import club.wpia.gigi.pages.account.ChangePasswordPage;
 import club.wpia.gigi.pages.account.FindAgentAccess;
 import club.wpia.gigi.pages.account.History;
+import club.wpia.gigi.pages.account.MyContracts;
 import club.wpia.gigi.pages.account.MyDetails;
 import club.wpia.gigi.pages.account.UserTrainings;
 import club.wpia.gigi.pages.account.certs.CertificateAdd;
@@ -195,6 +196,7 @@ public final class Gigi extends HttpServlet {
             putPage(UserTrainings.SUPPORT_PATH, new UserTrainings(true), null);
             putPage(Points.SUPPORT_PATH, new Points(true), null);
             putPage(Certificates.SUPPORT_PATH + "/*", new Certificates(true), null);
+            putPage(MyContracts.PATH, new MyContracts(), null);
 
             putPage(PasswordResetPage.PATH, new PasswordResetPage(), null);
             putPage(LogoutPage.PATH, new LogoutPage(), null);
index b5e78eaaffa902764e0a29f938d3744848511b67..55a597e8c245c63ff8b11b78ad5bcf0d3ba6f1fa 100644 (file)
@@ -181,7 +181,7 @@ public class DatabaseConnection {
 
     }
 
-    public static final int CURRENT_SCHEMA_VERSION = 37;
+    public static final int CURRENT_SCHEMA_VERSION = 38;
 
     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
 
index e9097fd1a6eb0d22fc06b5b0cd19c2e040013a29..ef7547cedcd2907fd3f47929be290d5384568b53 100644 (file)
@@ -372,7 +372,7 @@ CREATE TABLE "schemeVersion" (
   "version" smallint NOT NULL,
   PRIMARY KEY ("version")
 );
-INSERT INTO "schemeVersion" (version)  VALUES(37);
+INSERT INTO "schemeVersion" (version)  VALUES(38);
 
 DROP TABLE IF EXISTS `passwordResetTickets`;
 CREATE TABLE `passwordResetTickets` (
@@ -698,3 +698,22 @@ CREATE TABLE "jobLog" (
   PRIMARY KEY ("jobid", "attempt")
 );
 CREATE INDEX ON "jobLog" ("jobid");
+
+DROP TABLE IF EXISTS "user_contracts";
+DROP TYPE IF EXISTS "contractType";
+CREATE TYPE "contractType" AS ENUM ('RA Agent Contract', 'Org RA Agent Contract');
+
+CREATE TABLE "user_contracts" (
+  "id" serial NOT NULL,
+  "token" varchar(32) NOT NULL,
+  "memid" int NOT NULL,
+  "document" "contractType" NOT NULL,
+  "agentname" varchar(255) NOT NULL,
+  "datesigned" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  "daterevoked" timestamp DEFAULT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX ON "user_contracts" ("memid");
+CREATE INDEX ON "user_contracts" ("document");
+CREATE INDEX ON "user_contracts" ("datesigned");
+CREATE INDEX ON "user_contracts" ("daterevoked");
diff --git a/src/club/wpia/gigi/database/upgrade/from_37.sql b/src/club/wpia/gigi/database/upgrade/from_37.sql
new file mode 100644 (file)
index 0000000..1ac2a4e
--- /dev/null
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS "user_contracts";
+DROP TYPE IF EXISTS "contractType";
+CREATE TYPE "contractType" AS ENUM ('RA Agent Contract', 'Org RA Agent Contract');
+
+CREATE TABLE "user_contracts" (
+  "id" serial NOT NULL,
+  "token" varchar(32) NOT NULL,
+  "memid" int NOT NULL,
+  "document" "contractType" NOT NULL,
+  "agentname" varchar(255) NOT NULL,
+  "datesigned" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  "daterevoked" timestamp DEFAULT NULL,
+  PRIMARY KEY ("id")
+);
+CREATE INDEX ON "user_contracts" ("memid");
+CREATE INDEX ON "user_contracts" ("document");
+CREATE INDEX ON "user_contracts" ("datesigned");
+CREATE INDEX ON "user_contracts" ("daterevoked");
diff --git a/src/club/wpia/gigi/dbObjects/Contract.java b/src/club/wpia/gigi/dbObjects/Contract.java
new file mode 100644 (file)
index 0000000..6886dc2
--- /dev/null
@@ -0,0 +1,188 @@
+package club.wpia.gigi.dbObjects;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.database.DBEnum;
+import club.wpia.gigi.database.GigiPreparedStatement;
+import club.wpia.gigi.database.GigiResultSet;
+import club.wpia.gigi.localisation.Language;
+import club.wpia.gigi.output.template.MailTemplate;
+import club.wpia.gigi.util.RandomToken;
+
+public class Contract {
+
+    public enum ContractType implements DBEnum {
+        RA_AGENT_CONTRACT("RA Agent Contract"), ORG_RA_AGENT_CONTRACT("Org RA Agent Contract");
+
+        private final String description;
+
+        private ContractType(String description) {
+            this.description = description;
+        }
+
+        public String getDBName() {
+            return description;
+        }
+    }
+
+    private final ContractType contractType;
+
+    private final User user;
+
+    private String agentname = "";
+
+    private String token = "";
+
+    private Date dateSigned = null;
+
+    private Date dateRevoked = null;
+
+    private int contractID;
+
+    private static final MailTemplate contractNotice = new MailTemplate(Contract.class.getResource("ContractNotice.templ"));
+
+    public Contract(User u, ContractType contractType) throws GigiApiException {
+        this.contractType = contractType;
+        this.user = u;
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `memid`=? AND `document`=?::`contractType` and `daterevoked` IS NULL ORDER BY `datesigned` DESC LIMIT 1")) {
+            query.setInt(1, user.getId());
+            query.setEnum(2, contractType);
+            GigiResultSet rs = query.executeQuery();
+            if (rs.next()) {
+                throw new GigiApiException("Contract exists");
+            } else {
+                signContract();
+            }
+        }
+
+    }
+
+    private void signContract() throws GigiApiException {
+        agentname = user.getPreferredName().toString();
+        token = RandomToken.generateToken(32);
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `user_contracts` SET `memid`=?, `token`=?, `document`=?::`contractType`,`agentname`=?")) {
+            ps.setInt(1, user.getId());
+            ps.setString(2, token);
+            ps.setEnum(3, this.contractType);
+            ps.setString(4, agentname);
+            ps.execute();
+            contractID = ps.lastInsertId();
+            dateSigned = new Date();
+
+            HashMap<String, Object> vars = new HashMap<>();
+            Language l = Language.getInstance(user.getPreferredLocale());
+            vars.put("user", agentname);
+            vars.put("actionsubject", "Signing");
+            vars.put("actionbody", "signed");
+
+            try {
+                contractNotice.sendMail(l, vars, user.getEmail());
+            } catch (IOException e) {
+                throw new GigiApiException("Sending the notification mail failed.");
+            }
+        }
+    }
+
+    public void revokeContract() throws GigiApiException {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("UPDATE `user_contracts` SET `daterevoked`=NOW() WHERE `id`=?")) {
+            ps.setInt(1, contractID);
+            ps.execute();
+        }
+        dateRevoked = new Date();
+        HashMap<String, Object> vars = new HashMap<>();
+        Language l = Language.getInstance(user.getPreferredLocale());
+        vars.put("user", user.getPreferredName());
+        vars.put("actionsubject", "Revoking");
+        vars.put("actionbody", "revoked");
+
+        try {
+            contractNotice.sendMail(l, vars, user.getEmail());
+        } catch (IOException e) {
+            throw new GigiApiException("Sending the notification mail failed.");
+        }
+    }
+
+    private Contract(GigiResultSet rs) {
+        contractID = rs.getInt("id");
+        user = User.getById(rs.getInt("memid"));
+        token = rs.getString("token");
+        contractType = ContractType.valueOf(rs.getString("document").toUpperCase().replace(" ", "_"));
+        dateSigned = rs.getDate("datesigned");
+        dateRevoked = rs.getDate("daterevoked");
+        agentname = rs.getString("agentname");
+    }
+
+    public static Contract getById(int id) {
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `id` = ?")) {
+            ps.setInt(1, id);
+            GigiResultSet rs = ps.executeQuery();
+            if ( !rs.next()) {
+                return null;
+            }
+
+            Contract c = new Contract(rs);
+
+            return c;
+        }
+    }
+
+    public int getID() {
+        return contractID;
+    }
+
+    public Date getDateSigned() {
+        return dateSigned;
+    }
+
+    public Date getDateRevoked() {
+        return dateRevoked;
+    }
+
+    public String getRAAgentName() {
+        return agentname;
+    }
+
+    public ContractType getContractType() {
+        return contractType;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public static boolean hasSignedContract(User u, Contract.ContractType ct) {
+        return getContractByUser(u, ct) != null;
+    }
+
+    public static Contract getRAAgentContractByUser(User u) {
+        return getContractByUser(u, Contract.ContractType.RA_AGENT_CONTRACT);
+    }
+
+    public static Contract getContractByUser(User u, ContractType ct) {
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `memid`=? AND `document`=?::`contractType` and `daterevoked` IS NULL ORDER BY `datesigned` DESC LIMIT 1")) {
+            query.setInt(1, u.getId());
+            query.setEnum(2, ct);
+            GigiResultSet rs = query.executeQuery();
+            if ( !rs.next()) {
+                return null;
+            }
+            Contract c = new Contract(rs);
+            return c;
+        }
+    }
+
+    public static Contract getRAAgentContractByToken(String token) throws GigiApiException {
+        try (GigiPreparedStatement query = new GigiPreparedStatement("SELECT * FROM `user_contracts` WHERE `token`=? LIMIT 1")) {
+            query.setString(1, token);
+            GigiResultSet rs = query.executeQuery();
+            if ( !rs.next()) {
+                return null;
+            }
+            Contract c = new Contract(rs);
+            return c;
+        }
+    }
+}
diff --git a/src/club/wpia/gigi/dbObjects/ContractNotice.templ b/src/club/wpia/gigi/dbObjects/ContractNotice.templ
new file mode 100644 (file)
index 0000000..e0e499d
--- /dev/null
@@ -0,0 +1,6 @@
+Subject: <?=_${actionsubject} of RA Agent Contract?>
+
+<?=_Hello ${user}, ?>
+
+<?=_you just ${actionbody} the RA Agent Contract.?>
+
index 4612d033f91d4d750700f77026913fc966417661..714bfc3a9122b95bcb1fad5bbd51a2f0ebb0678b 100644 (file)
@@ -242,6 +242,10 @@ public class User extends CertificateOwner {
             return false;
         }
 
+        if ( !Contract.hasSignedContract(this, Contract.ContractType.RA_AGENT_CONTRACT)) {
+            return false;
+        }
+
         return hasPassedCATS();
 
     }
diff --git a/src/club/wpia/gigi/pages/account/MyContracts.java b/src/club/wpia/gigi/pages/account/MyContracts.java
new file mode 100644 (file)
index 0000000..bf0574b
--- /dev/null
@@ -0,0 +1,42 @@
+package club.wpia.gigi.pages.account;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.User;
+import club.wpia.gigi.localisation.Language;
+import club.wpia.gigi.pages.LoginPage;
+import club.wpia.gigi.pages.Page;
+
+public class MyContracts extends Page {
+
+    public static final String PATH = "/account/contracts";
+
+    public MyContracts() {
+        super("My Contracts");
+    }
+
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        PrintWriter out = resp.getWriter();
+        Map<String, Object> vars = getDefaultVars(req);
+        Language l = LoginPage.getLanguage(req);
+        User u = getUser(req);
+        vars.put("raname", u.getPreferredName());
+        vars.put("csdate", l.getTranslation("not yet"));
+
+        Contract c = Contract.getRAAgentContractByUser(u);
+        if (c != null) {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            vars.put("csdate", sdf.format(c.getDateSigned()));
+        }
+
+        getDefaultTemplate().output(out, getLanguage(req), vars);
+    }
+}
diff --git a/src/club/wpia/gigi/pages/account/MyContracts.templ b/src/club/wpia/gigi/pages/account/MyContracts.templ
new file mode 100644 (file)
index 0000000..ed1bfe9
--- /dev/null
@@ -0,0 +1,18 @@
+<div class="panel panel-default">
+  <div class="panel-heading"><?=_RA Agents Contract?></div>
+  <div class="panel-body">
+
+       <p>This contract concludes an agreement between</p>
+
+       <p>Name: <?=$raname?> - RA Agent hereafter -</p>
+
+       <p>and</p>
+
+       <p>SomeCA - CA hereafter -</p>
+       <p>SomeAddress</p>
+
+       <p>regarding the conduction of registration authority tasks.</p>
+
+       <p>signed <?=$csdate?></p>
+  </div>
+</div>
diff --git a/src/club/wpia/gigi/pages/account/MyDetailsContracts.templ b/src/club/wpia/gigi/pages/account/MyDetailsContracts.templ
new file mode 100644 (file)
index 0000000..81e0b13
--- /dev/null
@@ -0,0 +1,8 @@
+<div class="panel panel-default">
+  <div class="panel-heading"><?=_RA Agents Contract?></div>
+  <div class="panel-body">
+   <button class="btn btn-info" name="action" value="viewContract"><?=_View RA Agent Contract?></button>
+   <button class="btn btn-primary" name="action" value="signContract" <?=$contractsign?> ><?=_Sign RA Agent Contract?></button>
+   <button class="btn btn-danger" name="action" value="revokeContract" <?=$contractrevoke?> ><?=_Revoke RA Agent Contract?></button>
+  </div>
+</div>
index 13d038808fb5c050b32539cf076ce15cc63750ba..bf7cbcfd1bb0724485e7536044ddad8f07364479 100644 (file)
@@ -7,6 +7,7 @@ import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Contract;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.dbObjects.Name;
 import club.wpia.gigi.dbObjects.User;
@@ -30,6 +31,8 @@ public class MyDetailsForm extends Form {
 
     private static final Template roles = new Template(MyDetailsForm.class.getResource("MyDetailsRoles.templ"));
 
+    private static final Template contracts = new Template(MyDetailsForm.class.getResource("MyDetailsContracts.templ"));
+
     private User target;
 
     private DateSelector ds;
@@ -110,6 +113,17 @@ public class MyDetailsForm extends Form {
                     target.revokeGroup(target, toMod);
                 }
                 return new RedirectResult(MyDetails.PATH);
+            } else if ("viewContract".equals(action)) {
+                return new RedirectResult(MyContracts.PATH);
+            } else if ("signContract".equals(action)) {
+                new Contract(target, Contract.ContractType.RA_AGENT_CONTRACT);
+                return new RedirectResult(MyDetails.PATH);
+            } else if ("revokeContract".equals(action)) {
+                Contract c = Contract.getRAAgentContractByUser(target);
+                if (c != null) {
+                    c.revokeContract();
+                }
+                return new RedirectResult(MyDetails.PATH);
             } else {
                 throw new GigiApiException("Invalid action.");
             }
@@ -161,6 +175,11 @@ public class MyDetailsForm extends Form {
         vars.put("groups", new GroupList(gr, false));
         vars.put("groupSelector", selectedGroup);
         roles.output(out, l, vars);
+
+        boolean hasSignedContract = Contract.hasSignedContract(target, Contract.ContractType.RA_AGENT_CONTRACT);
+        vars.put("contractsign", hasSignedContract ? "disabled" : "");
+        vars.put("contractrevoke", hasSignedContract ? "" : "disabled");
+        contracts.output(out, l, vars);
     }
 
 }
index 81925716caba4cc8376f47b312f0242f85473751..31be06f4471e7f06990d0bef219b9d30fedb23a8 100644 (file)
@@ -26,7 +26,6 @@ import club.wpia.gigi.output.template.Template;
 import club.wpia.gigi.pages.LoginPage;
 import club.wpia.gigi.util.AuthorizationContext;
 import club.wpia.gigi.util.HTMLEncoder;
-import club.wpia.gigi.util.RandomToken;
 import club.wpia.gigi.util.ServerConstants;
 import club.wpia.gigi.util.ServerConstants.Host;
 
@@ -42,14 +41,11 @@ public class CertificateIssueForm extends Form {
 
     private AuthorizationContext c;
 
-    private String spkacChallenge;
-
     private boolean login;
 
     public CertificateIssueForm(HttpServletRequest hsr) {
         super(hsr);
         c = LoginPage.getAuthorizationContext(hsr);
-        spkacChallenge = RandomToken.generateToken(16);
     }
 
     private Certificate result;
@@ -65,16 +61,11 @@ public class CertificateIssueForm extends Form {
     @Override
     public SubmissionResult submit(HttpServletRequest req) throws GigiApiException {
         String csr = req.getParameter("CSR");
-        String spkac = req.getParameter("SPKAC");
         try {
             if (csr != null) {
                 cr = new CertificateRequest(c, csr);
                 // TODO cr.checkKeyStrength(out);
                 return new FormContinue();
-            } else if (spkac != null) {
-                cr = new CertificateRequest(c, spkac, spkacChallenge);
-                // TODO cr.checkKeyStrength(out);
-                return new FormContinue();
             } else if (cr != null) {
                 login = "1".equals(req.getParameter("login"));
                 issueDate.update(req);
@@ -138,7 +129,6 @@ public class CertificateIssueForm extends Form {
             HashMap<String, Object> vars2 = new HashMap<String, Object>(vars);
             vars2.put("csrf", getCSRFToken());
             vars2.put("csrf_name", getCsrfFieldName());
-            vars2.put("spkacChallenge", spkacChallenge);
             tIni.output(out, l, vars2);
             return;
         } else {
index cdf4dd41eed765b5959cb979d571a9462d0bd89f..d9d090caa3e36aee24eb1296b50c41edc14b002e 100644 (file)
@@ -371,7 +371,7 @@ public class CertificateRequest {
                 } 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())));
+                            "The requested subject alternate name email address \"{0}\" needs a verification via email ping within the past {1} months.", san.getType().toString().toLowerCase() + ":" + san.getName(), TimeConditions.getInstance().getEmailPingMonths())));
                     break;
                 }
             }
index 89abb8df8afff9304f8ffe40fbf2ee0c9bbe5d63..274ad8eb9b9c0bb3f77d014058155b36e1c7873d 100644 (file)
@@ -1,6 +1,6 @@
 <p><?=_${appName} offers two ways to create a certificate.?>
-<?=_One is to paste a certificate signing request (CSR) created from an existing or newly created private key.?> <?=_If you do not know what a CSR is or how to create one take a look at the !(/kb/CSR)FAQ!'</a>'.?>
-<?=_As an alternative you can generate the private key inside your browser and export it once the certificate has been issued.?></p>
+<?=_One is to paste a certificate signing request (CSR) created from an existing or newly created private key.?> <?=_If you do not know what a CSR is or how to create one take a look at the !(/kb/CSR)FAQ!'</a>'.?></p>
+<p><?=_For inexperienced users the usage of !(/kb/XCA)XCA!'</a>' is recommended and described in !(/kb/XCADocu)XCA usage documentation!'</a>'?></p>
 <form method="post">
 <table class="table">
   <thead>
   </tbody>
 </table>
 </form>
-<form method="post">
-<table class="table">
-  <thead>
-  <tr>
-    <th colspan="2" class="title"><?=_Create a fresh key in the browser (SPKAC)?></th>
-  </tr>
-  </thead>
-  <tbody>
-  <tr>
-    <td><?=_I do not have a CSR.?></td>
-    <td align="left">
-      <?=_key size (2048 recommended)?>: <keygen name="SPKAC" challenge="<?=$spkacChallenge?>"/>
-    </td>
-  </tr>
-  <tr>
-    <td colspan="2">
-     <input class="btn btn-primary" type="submit" name="process" value="<?=_Next?>" />
-     <input type='hidden' name='<?=$csrf_name?>' value='<?=$csrf?>'>
-    </td>
-  </tr>
-  </tbody>
-</table>
-</form>
+
index 71909cf24b48d0793262125897a96dc038c45db1..0ed43d9d589afd1d01f8f0bbf2a023856e0b56a0 100644 (file)
@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest;
 
 import club.wpia.gigi.Gigi;
 import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.dbObjects.Contract;
 import club.wpia.gigi.dbObjects.Group;
 import club.wpia.gigi.dbObjects.Name;
 import club.wpia.gigi.dbObjects.SupportedUser;
@@ -112,6 +113,7 @@ public class SupportUserDetailsForm extends Form {
 
         });
         vars.put("agent", user.canVerify());
+        vars.put("agentcontract", Contract.hasSignedContract(user, Contract.ContractType.RA_AGENT_CONTRACT));
         vars.put("dob", dobSelector);
         vars.put("verificationPoints", user.getVerificationPoints());
         vars.put("exppoints", user.getExperiencePoints());
index e357564ef0e05f7f7375e5b0062266728fcd7c40..5f5ec991231f8e1e0c03d2641e372020bc0d7d22 100644 (file)
@@ -28,7 +28,7 @@
                 <? if($agent) { ?>
                 <?=_Yes?>
                 <? } else { ?>
-                <?=_No?>
+                <?=_No?> (<?=_RA Agent Contract signed:?> <? if($agentcontract) { ?><?=_Yes?><? } else { ?><?=_No?><?}?>)
                 <? } ?>
             </td>
         </tr>
diff --git a/tests/club/wpia/gigi/dbObjects/TestContract.java b/tests/club/wpia/gigi/dbObjects/TestContract.java
new file mode 100644 (file)
index 0000000..98648f0
--- /dev/null
@@ -0,0 +1,91 @@
+package club.wpia.gigi.dbObjects;
+
+import static org.junit.Assert.*;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.testUtils.ClientBusinessTest;
+import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
+import club.wpia.gigi.util.RandomToken;
+
+public class TestContract extends ClientBusinessTest {
+
+    @Test
+    public void testContract() throws GigiApiException {
+
+        assertEquals(Contract.getContractByUser(u, Contract.ContractType.RA_AGENT_CONTRACT), null);
+
+        assertFalse(Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c = Contract.getRAAgentContractByUser(u);
+        assertEquals(c, null);
+
+        c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        TestMail rc = getMailReceiver().receive(u.getEmail());
+
+        assertEquals(u.getEmail(), rc.getTo());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("signed the RA Agent Contract"));
+        assertEquals(u.getPreferredName().toString(), c.getRAAgentName());
+        assertTrue(Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c1 = null;
+        try {
+            c1 = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+            fail("double add contract must fail");
+        } catch (GigiApiException e) {
+            assertEquals("Contract exists", e.getMessage());
+        }
+
+        c1 = Contract.getContractByUser(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        assertEquals(c.getID(), c1.getID());
+
+        c1 = Contract.getRAAgentContractByUser(u);
+        assertEquals(c.getID(), c1.getID());
+
+        c1 = Contract.getRAAgentContractByToken(c.getToken());
+        assertEquals(c.getID(), c1.getID());
+
+        c1 = Contract.getRAAgentContractByToken(RandomToken.generateToken(16));
+        assertEquals(c1, null);
+
+    }
+
+    @Test
+    public void testRevokeContract() throws GigiApiException {
+        Contract c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+
+        TestMail rc = getMailReceiver().receive(u.getEmail());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("signed the RA Agent Contract"));
+
+        c.revokeContract();
+
+        rc = getMailReceiver().receive(u.getEmail());
+        assertEquals(u.getEmail(), rc.getTo());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("revoked the RA Agent Contract"));
+        assertFalse(Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c1 = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        rc = getMailReceiver().receive(u.getEmail());
+
+        assertNotEquals(c.getID(), c1.getID());
+    }
+
+    @Test
+    public void testContractInt() throws GigiApiException {
+        Contract c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+
+        TestMail rc = getMailReceiver().receive(u.getEmail());
+        assertThat(rc.getMessage(), CoreMatchers.containsString("signed the RA Agent Contract"));
+
+        Contract c1 = Contract.getById(c.getID());
+
+        assertEquals(c.getID(), c1.getID());
+        assertEquals(c.getContractType(), c1.getContractType());
+
+        c1 = Contract.getById(0);
+        assertEquals(null, c1);
+    }
+
+}
index 6ec0abecd260381db8a32a64601194072cc0114f..e7aa70cff60c09cf2660f03222424b0c527c8542 100644 (file)
@@ -107,6 +107,19 @@ public class TestUser extends ClientBusinessTest {
         assertTrue(u.hasValidTTPAgentChallenge());
     }
 
+    @Test
+    public void testHasContract() throws GigiApiException {
+        assertEquals(false, Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        Contract c = new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+        getMailReceiver().receive(u.getEmail());
+        assertEquals(true, Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+
+        c.revokeContract();
+        getMailReceiver().receive(u.getEmail());
+        assertEquals(false, Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT));
+    }
+
     @Test
     public void testWriteUserLog() throws GigiApiException {
         String type = "Log test";
index be642f03101825d549f33493e76a484cf58192a6..d0d03ec5b441f2321758ac2afe744ef9537b04a5 100644 (file)
@@ -97,9 +97,10 @@ public class TestMain extends ClientTest {
 
     @Test
     public void testValidChallenges() throws GeneralSecurityException, IOException, GigiApiException, InterruptedException {
-
+        insertRAContract(u.getId());
         // test RA Agent challenge
         cookie = cookieWithCertificateLogin(u);
+
         testChallengeText("you need to pass the RA Agent Challenge", false);
 
         add100Points(u.getId());
index 0d83f301f0320db78b5717647f29609df5557017..16594e1b2efa834f952a478d898b48a277d51efa 100644 (file)
@@ -23,7 +23,6 @@ import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
-import java.util.Base64;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.TimeZone;
@@ -33,7 +32,6 @@ import java.util.regex.Pattern;
 
 import org.junit.Test;
 
-import club.wpia.gigi.crypto.SPKAC;
 import club.wpia.gigi.dbObjects.CertificateOwner;
 import club.wpia.gigi.dbObjects.Digest;
 import club.wpia.gigi.pages.account.certs.CertificateAdd;
@@ -56,7 +54,6 @@ import sun.security.x509.GeneralNameInterface;
 import sun.security.x509.GeneralNames;
 import sun.security.x509.RFC822Name;
 import sun.security.x509.SubjectAlternativeNameExtension;
-import sun.security.x509.X509Key;
 
 public class TestCertificateAdd extends ClientTest {
 
@@ -125,12 +122,6 @@ public class TestCertificateAdd extends ClientTest {
         }, res);
     }
 
-    @Test
-    public void testSPKAC() throws GeneralSecurityException, IOException {
-        testSPKAC(false);
-        testSPKAC(true);
-    }
-
     @Test
     public void testIssue() throws IOException, GeneralSecurityException {
         HttpURLConnection huc = sendCertificateForm("description");
@@ -312,32 +303,6 @@ public class TestCertificateAdd extends ClientTest {
         return uc;
     }
 
-    protected String testSPKAC(boolean correctChallenge) throws GeneralSecurityException, IOException {
-        HttpURLConnection uc = (HttpURLConnection) ncert.openConnection();
-        uc.setRequestProperty("Cookie", cookie);
-        String s = IOUtils.readURL(uc);
-
-        csrf = extractPattern(s, Pattern.compile("<input [^>]*name='csrf' [^>]*value='([^']*)'>"));
-        String challenge = extractPattern(s, Pattern.compile("<keygen [^>]*name=\"SPKAC\" [^>]*challenge=\"([^\"]*)\"/>"));
-
-        SPKAC spk = new SPKAC((X509Key) kp.getPublic(), challenge + (correctChallenge ? "" : "b"));
-        Signature sign = Signature.getInstance("SHA512WithRSA");
-        sign.initSign(kp.getPrivate());
-        try {
-            String[] res = fillOutFormDirect("SPKAC=" + URLEncoder.encode(Base64.getEncoder().encodeToString(spk.getEncoded(sign)), "UTF-8"));
-            if ( !correctChallenge) {
-                fail("Should not succeed with wrong challenge.");
-            }
-            assertArrayEquals(new String[] {
-                    "client", CertificateRequest.DEFAULT_CN, "", Digest.SHA512.toString()
-            }, res);
-        } catch (OnPageError e) {
-            String error = fetchStartErrorMessage(e.getMessage());
-            assertTrue(error, error.startsWith("<p>Challenge mismatch"));
-        }
-        return csrf;
-    }
-
     private PKCS10Attributes buildAtts(ObjectIdentifier[] ekuOIDs, GeneralNameInterface... SANs) throws IOException {
         CertificateExtensions attributeValue = new CertificateExtensions();
         GeneralNames names = new GeneralNames();
index 023be5ae543f307ba95376b116fd419bc1391f0e..bb6c575d7ed81d4457c0ac21951a8c3010ae2c3c 100644 (file)
@@ -108,7 +108,7 @@ public class TestCertificateRequest extends ClientTest {
             cr.draft();
             fail();
         } catch (GigiApiException e) {
-            assertThat(e.getMessage(), containsString("needs an email ping within the past"));
+            assertThat(e.getMessage(), containsString("needs a verification via email ping within the past"));
         }
 
     }
@@ -131,7 +131,7 @@ public class TestCertificateRequest extends ClientTest {
             cr.draft();
             fail();
         } catch (GigiApiException e) {
-            assertThat(e.getMessage(), containsString("needs an email ping within the past"));
+            assertThat(e.getMessage(), containsString("needs a verification via email ping within the past"));
         }
 
     }
index 9187c4f18156eaa87ad033f8d92cdd18a4e8ac97..b3dad24073a29e7572bf9a71225ca999dd0acd0c 100644 (file)
@@ -183,4 +183,28 @@ public class TestSEAdminPageDetails extends SEClientTest {
         return c;
     }
 
+    @Test
+    public void testUserDetailsRAAgent() throws IOException, GigiApiException {
+        User u0 = User.getById(createVerifiedUser("Kurti", "Hansel", createUniqueName() + "@email.com", TEST_PASSWORD));
+
+        HttpURLConnection uc = get(cookie, SupportUserDetailsPage.PATH + u0.getId() + "/");
+        String res = IOUtils.readURL(uc);
+        assertThat(res, containsString("No (RA Agent Contract signed: No)"));
+
+        signRAContract(u0);
+        uc = get(cookie, SupportUserDetailsPage.PATH + u0.getId() + "/");
+        res = IOUtils.readURL(uc);
+        assertThat(res, containsString("No (RA Agent Contract signed: Yes)"));
+
+        insertPassedTest(u0.getId());
+        uc = get(cookie, SupportUserDetailsPage.PATH + u0.getId() + "/");
+        res = IOUtils.readURL(uc);
+        assertThat(res, containsString("No (RA Agent Contract signed: Yes)"));
+
+        insertVerificationPoints(u0.getId());
+        uc = get(cookie, SupportUserDetailsPage.PATH + u0.getId() + "/");
+        res = IOUtils.readURL(uc);
+        assertThat(res, not(containsString("RA Agent Contract signed:")));
+
+    }
 }
index 81ec4df561d2ab4c2adef673b2acab9531d4d5f3..dcc61fc070cf66d857ec173546001b527c415e01 100644 (file)
@@ -399,6 +399,7 @@ public class TestVerification extends ManagedTest {
     public void testVerifyWithoutValidChallenge() throws IOException, GigiApiException {
         cookie = cookieWithCertificateLogin(User.getById(applicantId));
         add100Points(applicantId);
+        insertRAContract(applicantId);
         addChallengeInPast(applicantId, CATSType.AGENT_CHALLENGE);
         assertEquals(403, get(cookie, VerifyPage.PATH).getResponseCode());
         addChallenge(applicantId, CATSType.AGENT_CHALLENGE);
index c0d6d4f74e4ee63a2c489d1ad76e812d029d6f98..322af0bc55e6d15e2b744316b8431b0c2c4d17c4 100644 (file)
@@ -42,6 +42,8 @@ import club.wpia.gigi.database.SQLFileManager.ImportType;
 import club.wpia.gigi.dbObjects.CATS;
 import club.wpia.gigi.dbObjects.CATS.CATSType;
 import club.wpia.gigi.dbObjects.CertificateProfile;
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.Contract.ContractType;
 import club.wpia.gigi.dbObjects.Domain;
 import club.wpia.gigi.dbObjects.DomainPingType;
 import club.wpia.gigi.dbObjects.User;
@@ -52,6 +54,7 @@ import club.wpia.gigi.util.DomainAssessment;
 import club.wpia.gigi.util.Notary;
 import club.wpia.gigi.util.PEM;
 import club.wpia.gigi.util.PasswordHash;
+import club.wpia.gigi.util.RandomToken;
 import club.wpia.gigi.util.ServerConstants;
 import club.wpia.gigi.util.TimeConditions;
 import sun.security.pkcs10.PKCS10;
@@ -336,6 +339,7 @@ public abstract class ConfiguredTest {
     public static void makeAgent(int uid) {
         addChallenge(uid, CATSType.AGENT_CHALLENGE);
         add100Points(uid);
+        insertRAContract(uid);
     }
 
     public static void addChallenge(int uid, CATSType ct) {
@@ -363,6 +367,35 @@ public abstract class ConfiguredTest {
         }
     }
 
+    public static void insertRAContract(int uid) {
+        // insert signed RA Contract
+        try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `user_contracts` SET `memid`=?, `token`=?, `document`=?::`contractType`,`agentname`=?")) {
+            ps.setInt(1, uid);
+            ps.setString(2, RandomToken.generateToken(32));
+            ps.setEnum(3, ContractType.RA_AGENT_CONTRACT);
+            ps.setString(4, User.getById(uid).getPreferredName().toString());
+            ps.execute();
+        }
+    }
+
+    public static void insertVerificationPoints(int uid) {
+        // insert Verification Points
+        try (GigiPreparedStatement ps2 = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'")) {
+            ps2.setInt(1, uid);
+            ps2.setInt(2, User.getById(uid).getPreferredName().getId());
+            ps2.execute();
+        }
+    }
+
+    public static void insertPassedTest(int uid) {
+        // insert passed test
+        try (GigiPreparedStatement ps1 = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=?, language='en_EN', version='1'")) {
+            ps1.setInt(1, uid);
+            ps1.setInt(2, CATSType.AGENT_CHALLENGE.getId());
+            ps1.execute();
+        }
+    }
+
     public MailReceiver getMailReceiver() {
         throw new Error("Feature requires Business or ManagedTest.");
     }
@@ -406,4 +439,9 @@ public abstract class ConfiguredTest {
         c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION + 1);
         return sdf.format(new Date(c.getTimeInMillis()));
     }
+
+    public void signRAContract(User u) throws GigiApiException {
+        new Contract(u, ContractType.RA_AGENT_CONTRACT);
+        getMailReceiver().receive(u.getEmail());
+    }
 }
index 4028ebdaea80451673e7b7f8ca732048c16462be..6c6780e98703da1bb66aa3f6d573fb2d37f3532d 100644 (file)
@@ -12,6 +12,7 @@ import club.wpia.gigi.GigiApiException;
 import club.wpia.gigi.database.GigiPreparedStatement;
 import club.wpia.gigi.dbObjects.CATS;
 import club.wpia.gigi.dbObjects.CATS.CATSType;
+import club.wpia.gigi.dbObjects.Contract;
 import club.wpia.gigi.dbObjects.Country;
 import club.wpia.gigi.dbObjects.Country.CountryCodeType;
 import club.wpia.gigi.dbObjects.Group;
@@ -23,6 +24,7 @@ import club.wpia.gigi.dbObjects.User;
 import club.wpia.gigi.dbObjects.Verification.VerificationType;
 import club.wpia.gigi.output.DateSelector;
 import club.wpia.gigi.testUtils.BusinessTest;
+import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
 
 public class TestNotary extends BusinessTest {
 
@@ -167,6 +169,8 @@ public class TestNotary extends BusinessTest {
         assertEquals(100, applicant.getVerificationPoints());
         assertFalse(applicant.canVerify());
         CATS.enterResult(applicant, CATSType.AGENT_CHALLENGE, new Date(), "de", "1");
+        new Contract(applicant, Contract.ContractType.RA_AGENT_CONTRACT);
+        TestMail rc = getMailReceiver().receive(applicant.getEmail());
         assertTrue(applicant.canVerify());
     }
 }
index c9dba62f957dbd8462d835aedfa812d2b6fb5033..bd90d2629fb1c05901785bc190cedaff0671b72c 100644 (file)
@@ -38,6 +38,8 @@ import club.wpia.gigi.dbObjects.CATS.CATSType;
 import club.wpia.gigi.dbObjects.Certificate;
 import club.wpia.gigi.dbObjects.Certificate.CertificateStatus;
 import club.wpia.gigi.dbObjects.CertificateOwner;
+import club.wpia.gigi.dbObjects.Contract;
+import club.wpia.gigi.dbObjects.Contract.ContractType;
 import club.wpia.gigi.dbObjects.Country;
 import club.wpia.gigi.dbObjects.Digest;
 import club.wpia.gigi.dbObjects.Domain;
@@ -164,6 +166,7 @@ public class Manager extends Page {
                 ps.setString(6, getRandomCountry().getCode());
                 ps.execute();
             }
+            new Contract(u, ContractType.RA_AGENT_CONTRACT);
             return u;
         }
     }
@@ -406,33 +409,16 @@ public class Manager extends Page {
             }
 
             int vp = 0;
-            int agentNumber = 0;
 
             try {
-                try {
-                    vp = Integer.parseInt(verificationPoints);
-                } catch (NumberFormatException e) {
-                    throw new GigiApiException("No valid Verification Points entered.");
-                }
-
-                if (vp > 100) { // only allow max 100 Verification points
-                    vp = 100;
-                }
-
-                while (vp > 0) {
-                    int currentVP = 10;
-                    if (vp < 10) {
-                        currentVP = vp;
-                    }
-                    Notary.verify(getAgent(agentNumber), byEmail, byEmail.getPreferredName(), byEmail.getDoB(), currentVP, "Testmanager Verify up code", validVerificationDateString(), VerificationType.FACE_TO_FACE, getRandomCountry());
-                    agentNumber += 1;
-                    vp -= currentVP;
-                }
-
-            } catch (GigiApiException e) {
-                throw new Error(e);
+                vp = Integer.parseInt(verificationPoints);
+            } catch (NumberFormatException e) {
+                resp.getWriter().println("No valid Verification Points entered.</br>");
+                vp = 0;
             }
 
+            int agentNumber = addVerificationPoints(vp, byEmail);
+
             resp.getWriter().println("User has been verified " + agentNumber + " times.");
 
         } else if (req.getParameter("letverify") != null) {
@@ -500,10 +486,54 @@ public class Manager extends Page {
             pingExempt.remove(dom);
             resp.getWriter().println("Updated domains exempt from pings. Current set: <br/>");
             resp.getWriter().println(HTMLEncoder.encodeHTML(pingExempt.toString()));
+        } else if (req.getParameter("makeAgent") != null) {
+            User u = User.getByEmail(req.getParameter("agentEmail"));
+            if (u == null) {
+                resp.getWriter().println("User not found, or found user is not allowed to verify.");
+            } else {
+                if (u.getVerificationPoints() < 100) {
+                    addVerificationPoints(100, u);
+                }
+                if ( !u.hasPassedCATS()) {
+                    passCATS(u, CATSType.AGENT_CHALLENGE);
+                }
+                if ( !Contract.hasSignedContract(u, Contract.ContractType.RA_AGENT_CONTRACT)) {
+                    try {
+                        new Contract(u, Contract.ContractType.RA_AGENT_CONTRACT);
+                    } catch (GigiApiException e) {
+                        throw new Error(e);
+                    }
+                }
+                resp.getWriter().println("User has all requirements to be an RA Agent");
+            }
         }
         resp.getWriter().println("<br/><a href='" + PATH + "'>Go back</a>");
     }
 
+    private int addVerificationPoints(int vp, User byEmail) throws Error {
+        int agentNumber = 0;
+
+        try {
+            if (vp > 100) { // only allow max 100 Verification points
+                vp = 100;
+            }
+
+            while (vp > 0) {
+                int currentVP = 10;
+                if (vp < 10) {
+                    currentVP = vp;
+                }
+                Notary.verify(getAgent(agentNumber), byEmail, byEmail.getPreferredName(), byEmail.getDoB(), currentVP, "Testmanager Verify up code", validVerificationDateString(), VerificationType.FACE_TO_FACE, getRandomCountry());
+                agentNumber += 1;
+                vp -= currentVP;
+            }
+
+        } catch (GigiApiException e) {
+            throw new Error(e);
+        }
+        return agentNumber;
+    }
+
     private void fetchMails(HttpServletRequest req, HttpServletResponse resp, String mail) throws IOException {
         final LinkedList<String> mails = emails.get(mail);
         HashMap<String, Object> vars = new HashMap<>();
index 857a6d18da61656c2c7afda202bb2eee98792af2..89627aeea5fb50dfdfdda21378252e2d9e1ef5a1 100644 (file)
@@ -52,6 +52,17 @@ Email: <input type="text" name="catsEmail"/>
 <input type="submit" value="Add Challenge" name="cats"/>
 <input type="submit" value="Set Challenge expired" name="catsexpire"/>
 </td></tr>
+
+</td></tr>
+<tr><td>
+Make RA Agent:
+</td><td>
+Email: <input type="text" name="agentEmail"/>
+</td><td>
+Current requirements: 100 VP, passed Assurer Challenge, signed RA Agent Contract</br>
+<input type="submit" value="Add requirements" name="makeAgent"/>
+</td></tr>
+
 <tr><td>
 Add 100 Verification Points:
 </td><td>
@@ -59,7 +70,6 @@ Email: <input type="text" name="verifyEmail"/>
 </td><td>
 Verification Points to issue to preferred name: </br>
 <input type="text" name="verificationPoints" value="100"/> <input type="submit" value="Add Points" name="verify"/>
-
 </td></tr>
 
 <tr><td>