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