]> WPIA git - gigi.git/blob - tests/org/cacert/gigi/testUtils/ManagedTest.java
Merge branch 'changePasswordForm'
[gigi.git] / tests / org / cacert / gigi / testUtils / ManagedTest.java
1 package org.cacert.gigi.testUtils;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertTrue;
5
6 import java.io.BufferedReader;
7 import java.io.DataOutputStream;
8 import java.io.FileInputStream;
9 import java.io.IOException;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.io.UnsupportedEncodingException;
13 import java.net.HttpURLConnection;
14 import java.net.InetSocketAddress;
15 import java.net.MalformedURLException;
16 import java.net.Socket;
17 import java.net.URL;
18 import java.net.URLConnection;
19 import java.net.URLEncoder;
20 import java.nio.file.Files;
21 import java.nio.file.Paths;
22 import java.security.KeyManagementException;
23 import java.security.NoSuchAlgorithmException;
24 import java.security.Principal;
25 import java.security.PrivateKey;
26 import java.security.cert.X509Certificate;
27 import java.sql.PreparedStatement;
28 import java.sql.ResultSet;
29 import java.sql.SQLException;
30 import java.util.Properties;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 import javax.net.ssl.HttpsURLConnection;
35 import javax.net.ssl.KeyManager;
36 import javax.net.ssl.SSLContext;
37 import javax.net.ssl.X509KeyManager;
38
39 import org.cacert.gigi.DevelLauncher;
40 import org.cacert.gigi.database.DatabaseConnection;
41 import org.cacert.gigi.testUtils.TestEmailReciever.TestMail;
42 import org.cacert.gigi.util.DatabaseManager;
43 import org.cacert.gigi.util.SimpleSigner;
44 import org.junit.After;
45 import org.junit.AfterClass;
46 import org.junit.BeforeClass;
47
48 public class ManagedTest {
49         /**
50          * Some password that fullfills the password criteria.
51          */
52         protected static final String TEST_PASSWORD = "xvXV12°§";
53
54         private final String registerService = "/register";
55
56         private static TestEmailReciever ter;
57         private static Process gigi;
58         private static String url = "localhost:4443";
59
60         public static String getServerName() {
61                 return url;
62         }
63
64         static Properties testProps = new Properties();
65         static {
66                 InitTruststore.run();
67                 HttpURLConnection.setFollowRedirects(false);
68         }
69
70         @BeforeClass
71         public static void connectToServer() {
72                 try {
73                         testProps.load(new FileInputStream("config/test.properties"));
74                         if (!DatabaseConnection.isInited()) {
75                                 DatabaseConnection.init(testProps);
76                         }
77                         System.out.println("... purging Database");
78                         DatabaseManager.run(new String[] { testProps.getProperty("sql.driver"), testProps.getProperty("sql.url"),
79                                         testProps.getProperty("sql.user"), testProps.getProperty("sql.password") });
80
81                         String type = testProps.getProperty("type");
82                         if (type.equals("local")) {
83                                 url = testProps.getProperty("name.www") + ":" + testProps.getProperty("serverPort");
84                                 String[] parts = testProps.getProperty("mail").split(":", 2);
85                                 ter = new TestEmailReciever(new InetSocketAddress(parts[0], Integer.parseInt(parts[1])));
86                                 return;
87                         }
88                         url = testProps.getProperty("name.www") + ":" + testProps.getProperty("serverPort");
89                         gigi = Runtime.getRuntime().exec(testProps.getProperty("java"));
90                         DataOutputStream toGigi = new DataOutputStream(gigi.getOutputStream());
91                         System.out.println("... starting server");
92                         Properties mainProps = new Properties();
93                         mainProps.setProperty("host", "127.0.0.1");
94                         mainProps.setProperty("name.secure", testProps.getProperty("name.secure"));
95                         mainProps.setProperty("name.www", testProps.getProperty("name.www"));
96                         mainProps.setProperty("name.static", testProps.getProperty("name.static"));
97
98                         mainProps.setProperty("port", testProps.getProperty("serverPort"));
99                         mainProps.setProperty("emailProvider", "org.cacert.gigi.email.TestEmailProvider");
100                         mainProps.setProperty("emailProvider.port", "8473");
101                         mainProps.setProperty("sql.driver", testProps.getProperty("sql.driver"));
102                         mainProps.setProperty("sql.url", testProps.getProperty("sql.url"));
103                         mainProps.setProperty("sql.user", testProps.getProperty("sql.user"));
104                         mainProps.setProperty("sql.password", testProps.getProperty("sql.password"));
105
106                         byte[] cacerts = Files.readAllBytes(Paths.get("config/cacerts.jks"));
107                         byte[] keystore = Files.readAllBytes(Paths.get("config/keystore.pkcs12"));
108
109                         DevelLauncher.writeGigiConfig(toGigi, "changeit".getBytes(), "changeit".getBytes(), mainProps, cacerts,
110                                 keystore);
111                         toGigi.flush();
112
113                         final BufferedReader br = new BufferedReader(new InputStreamReader(gigi.getErrorStream()));
114                         String line;
115                         while ((line = br.readLine()) != null && !line.contains("Server:main: Started")) {
116                         }
117                         new Thread() {
118                                 @Override
119                                 public void run() {
120                                         String line;
121                                         try {
122                                                 while ((line = br.readLine()) != null) {
123                                                         System.err.println(line);
124                                                 }
125                                         } catch (IOException e) {
126                                                 e.printStackTrace();
127                                         }
128                                 }
129                         }.start();
130                         if (line == null) {
131                                 throw new Error("Server startup failed");
132                         }
133                         ter = new TestEmailReciever(new InetSocketAddress("localhost", 8473));
134                         SimpleSigner.runSigner();
135                 } catch (IOException e) {
136                         throw new Error(e);
137                 } catch (ClassNotFoundException e1) {
138                         e1.printStackTrace();
139                 } catch (SQLException e1) {
140                         e1.printStackTrace();
141                 } catch (InterruptedException e) {
142                         e.printStackTrace();
143                 }
144
145         }
146
147         @AfterClass
148         public static void tearDownServer() {
149                 String type = testProps.getProperty("type");
150                 ter.destroy();
151                 if (type.equals("local")) {
152                         return;
153                 }
154                 gigi.destroy();
155                 try {
156                         SimpleSigner.stopSigner();
157                 } catch (InterruptedException e) {
158                         e.printStackTrace();
159                 }
160         }
161
162         @After
163         public void removeMails() {
164                 ter.reset();
165         }
166
167         public TestMail waitForMail() {
168                 try {
169                         return ter.recieve();
170                 } catch (InterruptedException e) {
171                         throw new Error(e);
172                 }
173         }
174
175         public static TestEmailReciever getMailReciever() {
176                 return ter;
177         }
178
179         public String runRegister(String param) throws IOException {
180                 URL regist = new URL("https://" + getServerName() + registerService);
181                 HttpURLConnection uc = (HttpURLConnection) regist.openConnection();
182                 HttpURLConnection csrfConn = (HttpURLConnection) regist.openConnection();
183
184                 String headerField = csrfConn.getHeaderField("Set-Cookie");
185                 headerField = stripCookie(headerField);
186
187                 String csrf = getCSRF(csrfConn);
188                 uc.addRequestProperty("Cookie", headerField);
189                 uc.setDoOutput(true);
190                 uc.getOutputStream().write((param + "&csrf=" + csrf).getBytes());
191                 String d = IOUtils.readURL(uc);
192                 return d;
193         }
194
195         public String fetchStartErrorMessage(String d) throws IOException {
196                 String formFail = "<div class='formError'>";
197                 int idx = d.indexOf(formFail);
198                 if (idx == -1) {
199                         return null;
200                 }
201                 String startError = d.substring(idx + formFail.length(), idx + 100).trim();
202                 return startError;
203         }
204
205         public void registerUser(String firstName, String lastName, String email, String password) {
206                 try {
207                         String query = "fname=" + URLEncoder.encode(firstName, "UTF-8") + "&lname="
208                                 + URLEncoder.encode(lastName, "UTF-8") + "&email=" + URLEncoder.encode(email, "UTF-8") + "&pword1="
209                                 + URLEncoder.encode(password, "UTF-8") + "&pword2=" + URLEncoder.encode(password, "UTF-8")
210                                 + "&day=1&month=1&year=1910&cca_agree=1";
211                         String data = fetchStartErrorMessage(runRegister(query));
212                         assertTrue(data, data.startsWith("</div>"));
213                 } catch (UnsupportedEncodingException e) {
214                         throw new Error(e);
215                 } catch (IOException e) {
216                         throw new Error(e);
217                 }
218         }
219
220         public int createVerifiedUser(String firstName, String lastName, String email, String password) {
221                 registerUser(firstName, lastName, email, password);
222                 try {
223                         TestMail tm = ter.recieve();
224                         String verifyLink = tm.extractLink();
225                         String[] parts = verifyLink.split("\\?");
226                         URL u = new URL("https://" + getServerName() + "/verify?" + parts[1]);
227                         u.openStream().close();
228                         ;
229                         PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id FROM users where email=?");
230                         ps.setString(1, email);
231                         ResultSet rs = ps.executeQuery();
232                         if (rs.next()) {
233                                 return rs.getInt(1);
234                         }
235                         throw new Error();
236                 } catch (InterruptedException e) {
237                         throw new Error(e);
238                 } catch (IOException e) {
239                         throw new Error(e);
240                 } catch (SQLException e) {
241                         throw new Error(e);
242                 }
243         }
244
245         /**
246          * Creates a new user with 100 Assurance points given by an (invalid)
247          * assurance.
248          * 
249          * @param firstName
250          *            the first name
251          * @param lastName
252          *            the last name
253          * @param email
254          *            the email
255          * @param password
256          *            the password
257          * @return a new userid.
258          */
259         public int createAssuranceUser(String firstName, String lastName, String email, String password) {
260                 int uid = createVerifiedUser(firstName, lastName, email, password);
261                 try {
262                         PreparedStatement ps = DatabaseConnection.getInstance().prepare(
263                                 "INSERT INTO `cats_passed` SET `user_id`=?, `variant_id`=?");
264                         ps.setInt(1, uid);
265                         ps.setInt(2, 0);
266                         ps.execute();
267                         ps = DatabaseConnection.getInstance().prepare("INSERT INTO `notary` SET `from`=?, `to`=?, points='100'");
268                         ps.setInt(1, uid);
269                         ps.setInt(2, uid);
270                         ps.execute();
271
272                 } catch (SQLException e) {
273                         throw new Error(e);
274                 }
275                 return uid;
276         }
277
278         static int count = 0;
279
280         public String createUniqueName() {
281                 return "test" + System.currentTimeMillis() + "a" + (count++);
282         }
283
284         private String stripCookie(String headerField) {
285                 return headerField.substring(0, headerField.indexOf(';'));
286         }
287
288         public static final String SECURE_REFERENCE = "/account/certs/email";
289
290         public boolean isLoggedin(String cookie) throws IOException {
291                 URL u = new URL("https://" + getServerName() + SECURE_REFERENCE);
292                 HttpURLConnection huc = (HttpURLConnection) u.openConnection();
293                 huc.addRequestProperty("Cookie", cookie);
294                 return huc.getResponseCode() == 200;
295         }
296
297         public String login(String email, String pw) throws IOException {
298                 URL u = new URL("https://" + getServerName() + "/login");
299                 HttpURLConnection huc = (HttpURLConnection) u.openConnection();
300                 huc.setDoOutput(true);
301                 OutputStream os = huc.getOutputStream();
302                 String data = "username=" + URLEncoder.encode(email, "UTF-8") + "&password=" + URLEncoder.encode(pw, "UTF-8");
303                 os.write(data.getBytes());
304                 os.flush();
305                 String headerField = huc.getHeaderField("Set-Cookie");
306                 return stripCookie(headerField);
307         }
308
309         public String login(final PrivateKey pk, final X509Certificate ce) throws NoSuchAlgorithmException,
310                 KeyManagementException, IOException, MalformedURLException {
311
312                 HttpURLConnection connection = (HttpURLConnection) new URL("https://"
313                         + getServerName().replaceFirst("^www.", "secure.") + "/login").openConnection();
314                 authenticateClientCert(pk, ce, connection);
315                 if (connection.getResponseCode() == 302) {
316                         assertEquals("https://" + getServerName().replaceFirst("^www.", "secure.").replaceFirst(":443$", "") + "/",
317                                 connection.getHeaderField("Location").replaceFirst(":443$", ""));
318                         return stripCookie(connection.getHeaderField("Set-Cookie"));
319                 } else {
320                         return null;
321                 }
322         }
323
324         public void authenticateClientCert(final PrivateKey pk, final X509Certificate ce, HttpURLConnection connection)
325                 throws NoSuchAlgorithmException, KeyManagementException {
326                 KeyManager km = new X509KeyManager() {
327
328                         @Override
329                         public String chooseClientAlias(String[] arg0, Principal[] arg1, Socket arg2) {
330                                 return "client";
331                         }
332
333                         @Override
334                         public String chooseServerAlias(String arg0, Principal[] arg1, Socket arg2) {
335                                 return null;
336                         }
337
338                         @Override
339                         public X509Certificate[] getCertificateChain(String arg0) {
340                                 return new X509Certificate[] { ce };
341                         }
342
343                         @Override
344                         public String[] getClientAliases(String arg0, Principal[] arg1) {
345                                 return new String[] { "client" };
346                         }
347
348                         @Override
349                         public PrivateKey getPrivateKey(String arg0) {
350                                 if (arg0.equals("client")) {
351                                         return pk;
352                                 }
353                                 return null;
354                         }
355
356                         @Override
357                         public String[] getServerAliases(String arg0, Principal[] arg1) {
358                                 return new String[] { "client" };
359                         }
360                 };
361                 SSLContext sc = SSLContext.getInstance("TLS");
362                 sc.init(new KeyManager[] { km }, null, null);
363                 if (connection instanceof HttpsURLConnection) {
364                         ((HttpsURLConnection) connection).setSSLSocketFactory(sc.getSocketFactory());
365                 }
366         }
367
368         public String getCSRF(URLConnection u) throws IOException {
369                 String content = IOUtils.readURL(u);
370                 Pattern p = Pattern.compile("<input type='hidden' name='csrf' value='([^']+)'>");
371                 Matcher m = p.matcher(content);
372                 if (!m.find()) {
373                         throw new Error("No CSRF Token");
374                 }
375                 return m.group(1);
376         }
377
378         public static String[] generateCSR(String dn) throws IOException {
379                 Process p = Runtime.getRuntime().exec(
380                         new String[] { "openssl", "req", "-newkey", "rsa:1024", "-nodes", "-subj", dn, "-config",
381                                         "keys/selfsign.config" });
382                 String csr = IOUtils.readURL(new InputStreamReader(p.getInputStream()));
383
384                 String[] parts = csr.split("(?<=-----)\n(?=-----)");
385                 if (parts.length != 2) {
386                         System.err.println(IOUtils.readURL(new InputStreamReader(p.getErrorStream())));
387                         throw new Error();
388                 }
389                 return parts;
390         }
391
392 }