ebfd73b9d605a15d1d72402d2840a8b52c440a54
[gigi.git] / util-testing / org / cacert / gigi / pages / Manager.java
1 package org.cacert.gigi.pages;
2
3 import java.io.IOException;
4 import java.io.PrintWriter;
5 import java.lang.reflect.Field;
6 import java.security.GeneralSecurityException;
7 import java.security.KeyPair;
8 import java.security.KeyPairGenerator;
9 import java.security.Signature;
10 import java.sql.Date;
11 import java.util.Base64;
12 import java.util.Calendar;
13 import java.util.GregorianCalendar;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.LinkedList;
17 import java.util.Locale;
18 import java.util.Map;
19 import java.util.Properties;
20 import java.util.TreeSet;
21
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse;
24
25 import org.cacert.gigi.Gigi;
26 import org.cacert.gigi.GigiApiException;
27 import org.cacert.gigi.crypto.SPKAC;
28 import org.cacert.gigi.database.GigiPreparedStatement;
29 import org.cacert.gigi.dbObjects.Assurance.AssuranceType;
30 import org.cacert.gigi.dbObjects.Certificate;
31 import org.cacert.gigi.dbObjects.Certificate.CertificateStatus;
32 import org.cacert.gigi.dbObjects.CertificateOwner;
33 import org.cacert.gigi.dbObjects.Digest;
34 import org.cacert.gigi.dbObjects.Domain;
35 import org.cacert.gigi.dbObjects.DomainPingType;
36 import org.cacert.gigi.dbObjects.EmailAddress;
37 import org.cacert.gigi.dbObjects.Group;
38 import org.cacert.gigi.dbObjects.Name;
39 import org.cacert.gigi.dbObjects.User;
40 import org.cacert.gigi.email.EmailProvider;
41 import org.cacert.gigi.localisation.Language;
42 import org.cacert.gigi.output.template.IterableDataset;
43 import org.cacert.gigi.output.template.Template;
44 import org.cacert.gigi.pages.account.certs.CertificateRequest;
45 import org.cacert.gigi.ping.DomainPinger;
46 import org.cacert.gigi.ping.PingerDaemon;
47 import org.cacert.gigi.util.AuthorizationContext;
48 import org.cacert.gigi.util.Notary;
49
50 import sun.security.x509.X509Key;
51
52 public class Manager extends Page {
53
54     public static final String PATH = "/manager";
55
56     Field f;
57
58     private static HashMap<DomainPingType, DomainPinger> dps;
59
60     private Manager() {
61         super("Test Manager");
62         try {
63             f = EmailAddress.class.getDeclaredField("hash");
64             f.setAccessible(true);
65         } catch (ReflectiveOperationException e) {
66             // TODO
67             System.out.println("I don't have 'hash', we are working probably in layered mode. Test Manager may not work.");
68             // throw new Error(e);
69         }
70
71         try {
72             Field gigiInstance = Gigi.class.getDeclaredField("instance");
73             gigiInstance.setAccessible(true);
74             Gigi g = (Gigi) gigiInstance.get(null);
75
76             Field gigiPinger = Gigi.class.getDeclaredField("pinger");
77             gigiPinger.setAccessible(true);
78             PingerDaemon pd = (PingerDaemon) gigiPinger.get(g);
79
80             Field f = PingerDaemon.class.getDeclaredField("pingers");
81             f.setAccessible(true);
82             dps = (HashMap<DomainPingType, DomainPinger>) f.get(pd);
83             HashMap<DomainPingType, DomainPinger> pingers = new HashMap<>();
84             for (DomainPingType dpt : DomainPingType.values()) {
85                 pingers.put(dpt, new PingerFetcher(dpt));
86             }
87             f.set(pd, pingers);
88         } catch (ReflectiveOperationException e) {
89             e.printStackTrace();
90         }
91     }
92
93     public User[] getAssurers() {
94         if (assurers != null) {
95             return assurers;
96         }
97         assurers = new User[10];
98         try {
99             try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?")) {
100                 for (int i = 0; i < assurers.length; i++) {
101                     String mail = "test-assurer" + i + "@example.com";
102                     User u = User.getByEmail(mail);
103                     if (u == null) {
104                         System.out.println("Creating assurer");
105                         createUser(mail);
106                         u = User.getByEmail(mail);
107                         passCATS(u);
108                         ps.setInt(1, u.getId());
109                         ps.setInt(2, u.getId());
110                         ps.setInt(3, 100);
111                         ps.setString(4, "Manager init code");
112                         ps.setString(5, "1990-01-01");
113                         ps.execute();
114                     }
115                     assurers[i] = u;
116
117                 }
118             }
119         } catch (ReflectiveOperationException | GigiApiException e) {
120             e.printStackTrace();
121         }
122         return assurers;
123     }
124
125     private void passCATS(User u) {
126         try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO cats_passed SET user_id=?, variant_id=1")) {
127             ps.setInt(1, u.getId());
128             ps.execute();
129         }
130     }
131
132     private static Manager instance;
133
134     Template t = new Template(Manager.class.getResource("ManagerMails.templ"));
135
136     HashMap<String, LinkedList<String>> emails = new HashMap<>();
137
138     private static TreeSet<String> pingExempt = new TreeSet<>();
139
140     public static Manager getInstance() {
141         if (instance == null) {
142             instance = new Manager();
143         }
144         return instance;
145     }
146
147     public static class MailFetcher extends EmailProvider {
148
149         public MailFetcher(Properties p) {}
150
151         @Override
152         public String checkEmailServer(int forUid, String address) throws IOException {
153             return OK;
154         }
155
156         @Override
157         public synchronized void sendmail(String to, String subject, String message, String from, String replyto, String toname, String fromname, String errorsto, boolean extra) throws IOException {
158             HashMap<String, LinkedList<String>> mails = Manager.getInstance().emails;
159             LinkedList<String> hismails = mails.get(to);
160             if (hismails == null) {
161                 mails.put(to, hismails = new LinkedList<>());
162             }
163             hismails.addFirst(subject + "\n" + message);
164         }
165
166     }
167
168     public class PingerFetcher extends DomainPinger {
169
170         private DomainPingType dpt;
171
172         public PingerFetcher(DomainPingType dpt) {
173             this.dpt = dpt;
174         }
175
176         @Override
177         public void ping(Domain domain, String configuration, CertificateOwner target, int confId) {
178             System.out.println("Test: " + domain);
179             if (pingExempt.contains(domain.getSuffix())) {
180                 enterPingResult(confId, DomainPinger.PING_SUCCEDED, "Succeeded by TestManager pass-by", null);
181             } else {
182                 dps.get(dpt).ping(domain, configuration, target, confId);
183             }
184         }
185
186     }
187
188     public void batchCreateUsers(String mailPrefix, String domain, int amount, PrintWriter out) {
189
190         try {
191             if (amount > 100) {
192                 out.print("100 at most, please.");
193                 return;
194             }
195             for (int i = 0; i < amount; i++) {
196                 String email = mailPrefix + i + "@" + domain;
197                 createUser(email);
198             }
199         } catch (ReflectiveOperationException e) {
200             out.println("failed");
201             e.printStackTrace();
202         } catch (GigiApiException e) {
203             out.println("failed: " + e.getMessage());
204             e.printStackTrace();
205         }
206     }
207
208     private void createUser(String email) throws GigiApiException, IllegalAccessException {
209         Calendar gc = GregorianCalendar.getInstance();
210         gc.set(1990, 0, 1);
211         User u = new User(email, "xvXV12°§", new Name("Först", "Läst", "Müddle", "Süffix"), new Date(gc.getTime().getTime()), Locale.ENGLISH);
212         EmailAddress ea = u.getEmails()[0];
213         if (f == null) {
214             System.out.println("verification failed");
215             return;
216         }
217         String hash = (String) f.get(ea);
218
219         ea.verify(hash);
220     }
221
222     User[] assurers;
223
224     @Override
225     public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
226         if (req.getParameter("create") != null) {
227             batchCreateUsers(req.getParameter("prefix"), req.getParameter("suffix"), Integer.parseInt(req.getParameter("amount")), resp.getWriter());
228             resp.getWriter().println("User batch created.");
229         } else if (req.getParameter("addpriv") != null || req.getParameter("delpriv") != null) {
230             User u = User.getByEmail(req.getParameter("email"));
231             if (u == null) {
232                 resp.getWriter().println("User not found.");
233                 return;
234             }
235             if (req.getParameter("addpriv") != null) {
236                 u.grantGroup(u, Group.getByString(req.getParameter("priv")));
237                 resp.getWriter().println("Privilege granted");
238             } else {
239                 u.revokeGroup(u, Group.getByString(req.getParameter("priv")));
240                 resp.getWriter().println("Privilege revoked");
241             }
242         } else if (req.getParameter("fetch") != null) {
243             String mail = req.getParameter("femail");
244             fetchMails(req, resp, mail);
245         } else if (req.getParameter("cats") != null) {
246             String mail = req.getParameter("catsEmail");
247             User byEmail = User.getByEmail(mail);
248             if (byEmail == null) {
249                 resp.getWriter().println("User not found.");
250                 return;
251             }
252             passCATS(byEmail);
253             resp.getWriter().println("User has been passed CATS");
254         } else if (req.getParameter("assure") != null) {
255             String mail = req.getParameter("assureEmail");
256             User byEmail = User.getByEmail(mail);
257             if (byEmail == null) {
258                 resp.getWriter().println("User not found.");
259                 return;
260             }
261             try {
262                 for (int i = 0; i < getAssurers().length; i++) {
263                     Notary.assure(getAssurers()[i], byEmail, byEmail.getName(), byEmail.getDoB(), 10, "Testmanager Assure up code", "2014-11-06", AssuranceType.FACE_TO_FACE);
264                 }
265             } catch (GigiApiException e) {
266                 throw new Error(e);
267             }
268             resp.getWriter().println("User has been assured.");
269         } else if (req.getParameter("addEmail") != null) {
270             User u = User.getByEmail(req.getParameter("addEmailEmail"));
271             try {
272                 EmailAddress ea = new EmailAddress(u, req.getParameter("addEmailNew"), Locale.ENGLISH);
273                 if (f != null) {
274                     String hash = (String) f.get(ea);
275                     ea.verify(hash);
276                     resp.getWriter().println("Email added and verified");
277                 } else {
278                     resp.getWriter().println("Email added but verificatio failed.");
279                 }
280             } catch (IllegalArgumentException e) {
281                 e.printStackTrace();
282                 resp.getWriter().println("An internal error occured.");
283             } catch (IllegalAccessException e) {
284                 e.printStackTrace();
285                 resp.getWriter().println("An internal error occured.");
286             } catch (GigiApiException e) {
287                 e.format(resp.getWriter(), Language.getInstance(Locale.ENGLISH));
288             }
289         } else if (req.getParameter("addCert") != null) {
290             User u = User.getByEmail(req.getParameter("addCertEmail"));
291             try {
292                 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
293                 kpg.initialize(4096);
294                 KeyPair kp = kpg.generateKeyPair();
295                 SPKAC s = new SPKAC((X509Key) kp.getPublic(), "challange");
296                 Signature sign = Signature.getInstance("SHA512withRSA");
297                 sign.initSign(kp.getPrivate());
298
299                 byte[] res = s.getEncoded(sign);
300
301                 CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), Base64.getEncoder().encodeToString(res), "challange");
302                 cr.update(CertificateRequest.DEFAULT_CN, Digest.SHA512.toString(), "client", null, "", "email:" + u.getEmail(), resp.getWriter(), req);
303                 Certificate draft = cr.draft();
304                 draft.issue(null, "2y", u).waitFor(10000);
305                 if (draft.getStatus() == CertificateStatus.ISSUED) {
306                     resp.getWriter().println("added certificate");
307                 } else {
308                     resp.getWriter().println("signer failed");
309                 }
310             } catch (GeneralSecurityException e1) {
311                 e1.printStackTrace();
312                 resp.getWriter().println("error");
313             } catch (GigiApiException e) {
314                 e.format(resp.getWriter(), Language.getInstance(Locale.ENGLISH));
315             } catch (InterruptedException e) {
316                 e.printStackTrace();
317                 resp.getWriter().println("interrupted");
318             }
319
320         } else if (req.getParameter("addExDom") != null) {
321             String dom = req.getParameter("exemtDom");
322             pingExempt.add(dom);
323             resp.getWriter().println("Updated domains exempt from pings. Current set: <br/>");
324             resp.getWriter().println(pingExempt);
325         } else if (req.getParameter("delExDom") != null) {
326             String dom = req.getParameter("exemtDom");
327             pingExempt.remove(dom);
328             resp.getWriter().println("Updated domains exempt from pings. Current set: <br/>");
329             resp.getWriter().println(pingExempt);
330         }
331     }
332
333     private void fetchMails(HttpServletRequest req, HttpServletResponse resp, String mail) throws IOException {
334         final LinkedList<String> mails = emails.get(mail);
335         HashMap<String, Object> vars = new HashMap<>();
336         vars.put("mail", mail);
337         if (mails != null) {
338             vars.put("mails", new IterableDataset() {
339
340                 Iterator<String> s = mails.iterator();
341
342                 @Override
343                 public boolean next(Language l, Map<String, Object> vars) {
344                     if ( !s.hasNext()) {
345                         return false;
346                     }
347                     vars.put("body", s.next().replaceAll("(https?://\\S+)", "<a href=\"$1\">$1</a>"));
348                     return true;
349                 }
350             });
351         }
352         t.output(resp.getWriter(), getLanguage(req), vars);
353         if (mails == null) {
354             resp.getWriter().println("No mails");
355
356         }
357     }
358
359     private Template form = new Template(Manager.class.getResource("Manager.templ"));
360
361     @Override
362     public boolean needsLogin() {
363         return false;
364     }
365
366     @Override
367     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
368         getAssurers();
369         String pi = req.getPathInfo().substring(PATH.length());
370         if (pi.length() > 1 && pi.startsWith("/fetch-")) {
371             String mail = pi.substring(pi.indexOf('-', 2) + 1);
372             fetchMails(req, resp, mail);
373             return;
374         }
375
376         form.output(resp.getWriter(), getLanguage(req), new HashMap<String, Object>());
377     }
378 }