81ec4df561d2ab4c2adef673b2acab9531d4d5f3
[gigi.git] / tests / club / wpia / gigi / pages / wot / TestVerification.java
1 package club.wpia.gigi.pages.wot;
2
3 import static org.hamcrest.CoreMatchers.*;
4 import static org.junit.Assert.*;
5
6 import java.io.IOException;
7 import java.io.UnsupportedEncodingException;
8 import java.net.HttpURLConnection;
9 import java.net.MalformedURLException;
10 import java.net.URLConnection;
11 import java.net.URLEncoder;
12 import java.security.GeneralSecurityException;
13 import java.sql.SQLException;
14 import java.sql.Timestamp;
15 import java.text.SimpleDateFormat;
16 import java.util.Calendar;
17 import java.util.Date;
18 import java.util.regex.Pattern;
19
20 import org.hamcrest.Matcher;
21 import org.junit.Before;
22 import org.junit.Test;
23
24 import club.wpia.gigi.GigiApiException;
25 import club.wpia.gigi.database.GigiPreparedStatement;
26 import club.wpia.gigi.dbObjects.CATS.CATSType;
27 import club.wpia.gigi.dbObjects.Country;
28 import club.wpia.gigi.dbObjects.Group;
29 import club.wpia.gigi.dbObjects.User;
30 import club.wpia.gigi.pages.account.MyDetails;
31 import club.wpia.gigi.testUtils.IOUtils;
32 import club.wpia.gigi.testUtils.ManagedTest;
33 import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
34 import club.wpia.gigi.util.DayDate;
35 import club.wpia.gigi.util.Notary;
36
37 public class TestVerification extends ManagedTest {
38
39     private String agentM;
40
41     private String applicantM;
42
43     private int applicantName;
44
45     private int applicantId;
46
47     private String cookie;
48
49     @Before
50     public void setup() throws IOException, GeneralSecurityException, GigiApiException, InterruptedException {
51         clearCaches();
52         agentM = createUniqueName() + "@example.org";
53         applicantM = createUniqueName() + "@example.org";
54
55         createVerificationUser("a", "b", agentM, TEST_PASSWORD);
56         applicantId = createVerifiedUser("a", "c", applicantM, TEST_PASSWORD);
57         applicantName = User.getById(applicantId).getPreferredName().getId();
58
59         User users[] = User.findByEmail(agentM);
60         cookie = cookieWithCertificateLogin(users[0]);
61     }
62
63     private Matcher<String> isVerificationForm() {
64         return containsString("<select name=\"verificationType\">");
65     }
66
67     @Test
68     public void testVerifySearch() throws IOException {
69         String loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
70         assertThat(loc, isVerificationForm());
71     }
72
73     @Test
74     public void testVerifySearchEmail() throws IOException {
75         String loc = search("email=1" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
76         assertThat(loc, not(isVerificationForm()));
77     }
78
79     @Test
80     public void testVerifySearchDobInvalid() throws IOException {
81         String loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=mal");
82         assertThat(loc, not(isVerificationForm()));
83     }
84
85     @Test
86     public void testVerifySearchDob() throws IOException {
87         String loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=2&month=1&year=1910");
88         assertThat(loc, not(isVerificationForm()));
89         loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=2&year=1910");
90         assertThat(loc, not(isVerificationForm()));
91         loc = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1911");
92         assertThat(loc, not(isVerificationForm()));
93     }
94
95     private String search(String query) throws MalformedURLException, IOException, UnsupportedEncodingException {
96         URLConnection uc = get(cookie, VerifyPage.PATH);
97         uc.setDoOutput(true);
98         uc.getOutputStream().write(("search&" + query).getBytes("UTF-8"));
99         uc.getOutputStream().flush();
100
101         return IOUtils.readURL(uc);
102     }
103
104     @Test
105     public void testVerifyForm() throws IOException {
106         String body = executeSuccess("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
107         assertThat(body, containsString("10"));
108         assertThat(body, containsString(applicantM));
109         getMailReceiver().receive(applicantM);
110     }
111
112     @Test
113     public void testVerifyFormEmpty() throws IOException {
114         URLConnection uc = buildupVerifyFormConnection(true);
115         uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&rules=1&assertion=1&points=10").getBytes("UTF-8"));
116         uc.getOutputStream().flush();
117         String data = IOUtils.readURL(uc);
118         assertThat(data, hasError());
119     }
120
121     @Test
122     public void testVerifyFormContainsData() throws IOException {
123         URLConnection uc = buildupVerifyFormConnection(true);
124         uc.getOutputStream().write(("verifiedName=" + applicantName + "&date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&rules=1&assertion=1&points=10").getBytes("UTF-8"));
125         uc.getOutputStream().flush();
126         String data = IOUtils.readURL(uc);
127         assertThat(data, containsString(validVerificationDateString()));
128         assertThat(data, containsString("testcase"));
129     }
130
131     @Test
132     public void testVerifyFormNoCSRF() throws IOException {
133         // override csrf
134         HttpURLConnection uc = (HttpURLConnection) buildupVerifyFormConnection(false);
135         uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8"));
136         uc.getOutputStream().flush();
137         assertEquals(500, uc.getResponseCode());
138         uc.getErrorStream().close();
139     }
140
141     @Test
142     public void testVerifyFormWrongCSRF() throws IOException {
143         // override csrf
144         HttpURLConnection uc = (HttpURLConnection) buildupVerifyFormConnection(false);
145         uc.getOutputStream().write(("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10&csrf=aragc").getBytes("UTF-8"));
146         uc.getOutputStream().flush();
147         assertEquals(500, uc.getResponseCode());
148         uc.getErrorStream().close();
149     }
150
151     @Test
152     public void testVerifyFormRaceDoB() throws IOException, SQLException {
153         testVerifyFormRace(false);
154     }
155
156     @Test
157     public void testVerifyFormRaceDoBBlind() throws IOException, SQLException {
158         testVerifyFormRace(true);
159     }
160
161     public void testVerifyFormRace(boolean succeed) throws IOException, SQLException {
162         URLConnection uc = buildupVerifyFormConnection(true);
163
164         String applicantCookie = login(applicantM, TEST_PASSWORD);
165         String newDob = "day=1&month=1&year=" + ( !succeed ? 1911 : 1910);
166         loginCertificate = null;
167         assertNull(executeBasicWebInteraction(applicantCookie, MyDetails.PATH, newDob + "&action=updateDoB", 0));
168
169         uc.getOutputStream().write(("verifiedName=" + applicantName + "&date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10").getBytes("UTF-8"));
170         uc.getOutputStream().flush();
171         String error = fetchStartErrorMessage(IOUtils.readURL(uc));
172         if (succeed) {
173             assertNull(error);
174             getMailReceiver().receive(applicantM);
175         } else {
176             assertTrue(error, !error.startsWith("</div>"));
177             assertThat(error, containsString("changed his personal details"));
178         }
179     }
180
181     @Test
182     public void testVerifyFormFuture() throws IOException {
183         SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
184         int year = Integer.parseInt(sdf.format(new Date(System.currentTimeMillis()))) + 2;
185         executeFails("date=" + year + "-01-01&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
186     }
187
188     @Test
189     public void testVerifyFormFutureOK() throws IOException {
190         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
191         Calendar c = Calendar.getInstance();
192         c.setTimeInMillis(System.currentTimeMillis());
193         c.add(Calendar.HOUR_OF_DAY, 12);
194
195         executeSuccess("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
196         getMailReceiver().receive(applicantM);
197     }
198
199     @Test
200     public void testVerifyFormPastInRange() throws IOException {
201         executeSuccess("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
202         getMailReceiver().receive(applicantM);
203     }
204
205     @Test
206     public void testVerifyFormPastOnLimit() throws IOException {
207         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
208         Calendar c = Calendar.getInstance();
209         c.setTimeInMillis(System.currentTimeMillis());
210         c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION);
211         c.add(Calendar.DAY_OF_MONTH, 1);
212
213         executeSuccess("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
214         getMailReceiver().receive(applicantM);
215     }
216
217     @Test
218     public void testVerifyFormPastOutOfRange() throws IOException {
219         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
220         Calendar c = Calendar.getInstance();
221         c.setTimeInMillis(System.currentTimeMillis());
222         c.add(Calendar.MONTH, -Notary.LIMIT_MAX_MONTHS_VERIFICATION);
223
224         executeFails("date=" + sdf.format(new Date(c.getTimeInMillis())) + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
225     }
226
227     @Test
228     public void testVerifyFormNoLoc() throws IOException {
229         executeFails("date=" + validVerificationDateString() + "&location=a&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
230         executeFails("date=" + validVerificationDateString() + "&location=&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
231     }
232
233     @Test
234     public void testVerifyFormInvalDate() throws IOException {
235         executeFails("date=20000101&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
236         executeFails("date=&location=testcase&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
237     }
238
239     @Test
240     public void testVerifyFormBoxes() throws IOException {
241         executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=0&rules=1&assertion=1&points=10");
242         executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=&assertion=1&points=10");
243         executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=DE&certify=1&rules=1&assertion=z&points=10");
244     }
245
246     @Test
247     public void testVerifyListingValid() throws IOException, GigiApiException {
248         String uniqueLoc = createUniqueName();
249         executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
250         getMailReceiver().receive(applicantM);
251
252         String cookie = login(applicantM, TEST_PASSWORD);
253         loginCertificate = null;
254         URLConnection url = get(cookie, Points.PATH);
255         String resp = IOUtils.readURL(url);
256         resp = resp.split(Pattern.quote("</table>"))[1];
257         assertThat(resp, containsString(uniqueLoc));
258         assertThat(resp, containsString(Country.getCountryByCode("DE", Country.CountryCodeType.CODE_2_CHARS).getName()));
259     }
260
261     @Test
262     public void testAgentListingValid() throws IOException, GigiApiException {
263         String uniqueLoc = createUniqueName();
264         executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
265         getMailReceiver().receive(applicantM);
266
267         String cookie = login(agentM, TEST_PASSWORD);
268         loginCertificate = null;
269         URLConnection url = get(cookie, Points.PATH);
270         String resp = IOUtils.readURL(url);
271         resp = resp.split(Pattern.quote("</table>"))[2];
272         assertThat(resp, containsString(uniqueLoc));
273         assertThat(resp, containsString(Country.getCountryByCode("DE", Country.CountryCodeType.CODE_2_CHARS).getName()));
274     }
275
276     private void executeFails(String query) throws MalformedURLException, IOException {
277         assertThat(execute(query), hasError());
278
279     }
280
281     private String executeSuccess(String query) throws MalformedURLException, IOException {
282         String response = execute(query);
283         assertThat(response, hasNoError());
284         return response;
285     }
286
287     private String execute(String query) throws MalformedURLException, IOException {
288         URLConnection uc = buildupVerifyFormConnection(true);
289         uc.getOutputStream().write(("verifiedName=" + applicantName + "&" + query).getBytes("UTF-8"));
290         uc.getOutputStream().flush();
291         return IOUtils.readURL(uc);
292     }
293
294     private URLConnection buildupVerifyFormConnection(boolean doCSRF) throws MalformedURLException, IOException {
295         return buildupVerifyFormConnection(cookie, applicantM, doCSRF);
296     }
297
298     public static URLConnection buildupVerifyFormConnection(String cookie, String email, boolean doCSRF) throws MalformedURLException, IOException {
299         URLConnection uc = get(cookie, VerifyPage.PATH);
300         uc.setDoOutput(true);
301         uc.getOutputStream().write(("email=" + URLEncoder.encode(email, "UTF-8") + "&day=1&month=1&year=1910&search").getBytes("UTF-8"));
302
303         String csrf = getCSRF(uc);
304         uc = get(cookie, VerifyPage.PATH);
305         uc.setDoOutput(true);
306         if (doCSRF) {
307             uc.getOutputStream().write(("csrf=" + csrf + "&").getBytes("UTF-8"));
308         }
309         return uc;
310     }
311
312     @Test
313     public void testMultipleVerification() throws IOException, GeneralSecurityException, GigiApiException, InterruptedException {
314         User users[] = User.findByEmail(agentM);
315         int agentID = users[0].getId();
316
317         users = User.findByEmail(applicantM);
318         int applicantID = users[0].getId();
319
320         // enter first entry 200 days in the past
321         try (GigiPreparedStatement ps = new GigiPreparedStatement("INSERT INTO `notary` SET `from`=?, `to`=?, `points`=?, `location`=?, `date`=?, `when`=? ")) {
322             ps.setInt(1, agentID);
323             ps.setInt(2, applicantID);
324             ps.setInt(3, 10);
325             ps.setString(4, "test-location");
326             ps.setString(5, "2010-01-01");
327             ps.setTimestamp(6, new Timestamp(System.currentTimeMillis() - DayDate.MILLI_DAY * 200));
328             ps.execute();
329         }
330
331         // enter second entry
332         String uniqueLoc = createUniqueName();
333         executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
334         getMailReceiver().receive(applicantM);
335
336         // enter third entry on the same day
337         URLConnection uc = get(cookie, VerifyPage.PATH);
338         uc.setDoOutput(true);
339         uc.getOutputStream().write(("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910&search").getBytes("UTF-8"));
340         assertThat(IOUtils.readURL(uc), hasError());
341
342     }
343
344     @Test
345     public void testVerifyFormNoCountry() throws IOException {
346         executeFails("date=" + validVerificationDateString() + "&location=testcase&countryCode=&certify=1&rules=1&assertion=1&points=10");
347     }
348
349     @Test
350     public void testRANotificationSet() throws IOException, GigiApiException, GeneralSecurityException, InterruptedException {
351         getMailReceiver().assertEmpty();
352
353         User users[] = User.findByEmail(agentM);
354         assertTrue("user RA Agent not found", users != null && users.length > 0);
355
356         User u = users[0];
357         u.grantGroup(u, Group.VERIFY_NOTIFICATION);
358         clearCaches();
359         cookie = cookieWithCertificateLogin(users[0]);
360
361         // enter verification
362         String uniqueLoc = createUniqueName();
363         executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
364         getMailReceiver().receive(applicantM);
365
366         TestMail tm = getMailReceiver().receive(agentM);
367         assertThat(tm.getMessage(), containsString("You entered a verification for the account with email address " + applicantM));
368
369     }
370
371     @Test
372     public void testRANotificationNotSet() throws IOException, GigiApiException {
373         getMailReceiver().assertEmpty();
374
375         User users[] = User.findByEmail(agentM);
376         assertTrue("user RA Agent not found", users != null && users.length > 0);
377
378         User u = users[0];
379         u.revokeGroup(u, Group.VERIFY_NOTIFICATION);
380         clearCaches();
381
382         // enter verification
383         String uniqueLoc = createUniqueName();
384         executeSuccess("date=" + validVerificationDateString() + "&location=" + uniqueLoc + "&countryCode=DE&certify=1&rules=1&assertion=1&points=10");
385
386         TestMail tm = getMailReceiver().receive(applicantM);
387         assertThat(tm.getMessage(), not(containsString("You entered a verification for the account with email address " + applicantM)));
388
389     }
390
391     @Test
392     public void testVerifyWithoutCertLogin() throws IOException {
393         cookie = login(agentM, TEST_PASSWORD);
394         loginCertificate = null;
395         assertEquals(403, get(cookie, VerifyPage.PATH).getResponseCode());
396     }
397
398     @Test
399     public void testVerifyWithoutValidChallenge() throws IOException, GigiApiException {
400         cookie = cookieWithCertificateLogin(User.getById(applicantId));
401         add100Points(applicantId);
402         addChallengeInPast(applicantId, CATSType.AGENT_CHALLENGE);
403         assertEquals(403, get(cookie, VerifyPage.PATH).getResponseCode());
404         addChallenge(applicantId, CATSType.AGENT_CHALLENGE);
405         assertEquals(200, get(cookie, VerifyPage.PATH).getResponseCode());
406     }
407
408     @Test
409     public void testVerifyValidTTPChallenge() throws IOException, GigiApiException {
410         grant(User.getByEmail(agentM), Group.TTP_AGENT);
411         grant(User.getById(applicantId), Group.TTP_APPLICANT);
412         cookie = cookieWithCertificateLogin(User.getById(applicantId));
413         cookie = cookieWithCertificateLogin(User.getByEmail(agentM));
414
415         // test without valid challenge
416         String content = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
417         assertThat(content, containsString("you need to pass the TTP RA Agent Challenge"));
418
419         // test with valid challenge
420         addChallenge(User.getByEmail(agentM).getId(), CATSType.TTP_AGENT_CHALLENGE);
421         content = search("email=" + URLEncoder.encode(applicantM, "UTF-8") + "&day=1&month=1&year=1910");
422         assertThat(content, not(containsString("you need to pass the TTP RA Agent Challenge")));
423     }
424 }