]> WPIA git - gigi.git/blobdiff - tests/club/wpia/gigi/ping/TestSSL.java
upd: rename package name and all references to it
[gigi.git] / tests / club / wpia / gigi / ping / TestSSL.java
diff --git a/tests/club/wpia/gigi/ping/TestSSL.java b/tests/club/wpia/gigi/ping/TestSSL.java
new file mode 100644 (file)
index 0000000..9b93c77
--- /dev/null
@@ -0,0 +1,335 @@
+package club.wpia.gigi.ping;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URLEncoder;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import club.wpia.gigi.GigiApiException;
+import club.wpia.gigi.database.DatabaseConnection;
+import club.wpia.gigi.database.DatabaseConnection.Link;
+import club.wpia.gigi.dbObjects.Certificate;
+import club.wpia.gigi.dbObjects.CertificateProfile;
+import club.wpia.gigi.dbObjects.Digest;
+import club.wpia.gigi.dbObjects.Job;
+import club.wpia.gigi.dbObjects.User;
+import club.wpia.gigi.dbObjects.Certificate.CSRType;
+import club.wpia.gigi.testUtils.IOUtils;
+import club.wpia.gigi.testUtils.PingTest;
+import club.wpia.gigi.testUtils.TestEmailReceiver.TestMail;
+import club.wpia.gigi.util.SimpleSigner;
+
+@RunWith(Parameterized.class)
+public class TestSSL extends PingTest {
+
+    @Parameters(name = "self-signed = {0}")
+    public static Iterable<Object[]> genParams() throws IOException {
+        return Arrays.asList(new Object[] {
+                true
+        }, new Object[] {
+                false
+        });
+
+    }
+
+    @Parameter
+    public Boolean self = false;
+
+    public abstract static class AsyncTask<T> {
+
+        T res;
+
+        Thread runner;
+
+        Exception ex;
+
+        public T join() throws InterruptedException {
+            runner.join();
+            if (ex != null) {
+                throw new Error(ex);
+            }
+            return res;
+        }
+
+        public void start() {
+            runner = new Thread() {
+
+                @Override
+                public void run() {
+                    try {
+                        res = AsyncTask.this.run();
+                    } catch (Exception e) {
+                        ex = e;
+                    }
+                }
+            };
+            runner.start();
+        }
+
+        public abstract T run() throws Exception;
+
+    }
+
+    private KeyPair kp;
+
+    private X509Certificate c;
+
+    @Test(timeout = 70000)
+    public void sslAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        testEmailAndSSL(0, 0, true);
+    }
+
+    @Test(timeout = 70000)
+    public void sslWongTypeAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        testEmailAndSSL(1, 0, true);
+    }
+
+    @Test(timeout = 70000)
+    public void sslOneMissingAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        testEmailAndSSL(2, 0, true);
+    }
+
+    @Test(timeout = 70000)
+    public void sslBothMissingAndMailSuccess() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        testEmailAndSSL(3, 0, true);
+    }
+
+    @Test(timeout = 70000)
+    public void sslWrongTypeAndMailFail() throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        testEmailAndSSL(1, 1, false);
+    }
+
+    private void testEmailAndSSL(int sslVariant, int emailVariant, boolean successMail) throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        try (Link link = DatabaseConnection.newLink(false)) {
+            testEmailAndSSLWithLink(sslVariant, emailVariant, successMail);
+        }
+    }
+
+    /**
+     * @param sslVariant
+     *            <ul>
+     *            <li>0= all valid</li>
+     *            <li>1= wrong type</li>
+     *            <li>2= one server missing</li>
+     *            <li>3= both servers missing</li>
+     *            </ul>
+     * @param emailVariant
+     * @param successSSL
+     * @param successMail
+     * @throws IOException
+     * @throws InterruptedException
+     * @throws SQLException
+     * @throws GeneralSecurityException
+     * @throws GigiApiException
+     */
+
+    private void testEmailAndSSLWithLink(int sslVariant, int emailVariant, boolean successMail) throws IOException, InterruptedException, SQLException, GeneralSecurityException, GigiApiException {
+        String test = getTestProps().getProperty("domain.local");
+        assumeNotNull(test);
+        Matcher m = initailizeDomainForm();
+        String value = m.group(2);
+
+        if (self) {
+            createCertificateSelf(test, sslVariant == 1 ? "clientAuth" : "serverAuth", value);
+        } else {
+            createCertificate(test, CertificateProfile.getByName(sslVariant == 1 ? "client" : "server"));
+        }
+
+        final SSLServerSocket sss = createSSLServer(kp.getPrivate(), c);
+        int port = sss.getLocalPort();
+        final SSLServerSocket sss2 = createSSLServer(kp.getPrivate(), c);
+        int port2 = sss2.getLocalPort();
+        if (sslVariant == 3 || sslVariant == 2) {
+            sss2.close();
+            if (sslVariant == 3) {
+                sss.close();
+            }
+        }
+        String content = "adddomain&newdomain=" + URLEncoder.encode(test, "UTF-8") + //
+                "&emailType=y&email=2&SSLType=y" + //
+                "&ssl-type-0=direct&ssl-port-0=" + port + //
+                "&ssl-type-1=direct&ssl-port-1=" + port2 + //
+                "&ssl-type-2=direct&ssl-port-2=" + //
+                "&ssl-type-3=direct&ssl-port-3=" + //
+                "&adddomain&csrf=" + csrf;
+        String p2 = sendDomainForm(content);
+        boolean firstSucceeds = sslVariant != 0 && sslVariant != 2;
+        AsyncTask<Boolean> ass = new AsyncTask<Boolean>() {
+
+            @Override
+            public Boolean run() throws Exception {
+                return acceptSSLServer(sss);
+            }
+        };
+        ass.start();
+        System.out.println(port + " and " + port2 + " ready");
+        System.err.println(port + " and " + port2 + " ready");
+        boolean accept2 = acceptSSLServer(sss2);
+        boolean accept1 = ass.join();
+        // assertTrue(firstSucceeds ^ accept1);
+        boolean secondsSucceeds = sslVariant != 0;
+        // assertTrue(secondsSucceeds ^ accept2);
+
+        TestMail mail = getMailReceiver().receive();
+        if (emailVariant == 0) {
+            mail.verify();
+        }
+        waitForPings(3);
+
+        String newcontent = IOUtils.readURL(get(p2));
+        Pattern pat = Pattern.compile("<td>ssl</td>\\s*<td>success</td>");
+        Matcher matcher = pat.matcher(newcontent);
+        assertTrue(newcontent, firstSucceeds ^ matcher.find());
+        assertTrue(newcontent, secondsSucceeds ^ matcher.find());
+        assertFalse(newcontent, matcher.find());
+        pat = Pattern.compile("<td>email</td>\\s*<td>success</td>");
+        assertTrue(newcontent, !successMail ^ pat.matcher(newcontent).find());
+    }
+
+    private void createCertificate(String test, CertificateProfile profile) throws GeneralSecurityException, IOException, SQLException, InterruptedException, GigiApiException {
+        kp = generateKeypair();
+        String csr = generatePEMCSR(kp, "CN=" + test);
+        User u = User.getById(id);
+        Certificate c = new Certificate(u, u, Certificate.buildDN("CN", test), Digest.SHA256, csr, CSRType.CSR, profile);
+        Job j = c.issue(null, "2y", u);
+        await(j);
+        this.c = c.cert();
+    }
+
+    private void createCertificateSelf(String test, String eku, String tok) throws GeneralSecurityException, IOException, SQLException, InterruptedException, GigiApiException {
+        kp = generateKeypair();
+        HashMap<String, String> name = new HashMap<>();
+        name.put("CN", "");
+        name.put("OU", tok);
+
+        Date from = new Date();
+        Date to = new Date(from.getTime() + 1000 * 60 * 60 * 2);
+        List<Certificate.SubjectAlternateName> l = new LinkedList<>();
+
+        byte[] cert = SimpleSigner.generateCert(kp.getPublic(), kp.getPrivate(), name, new X500Principal(SimpleSigner.genX500Name(name).getEncoded()), l, from, to, Digest.SHA256, eku);
+        c = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(cert));
+    }
+
+    private boolean acceptSSLServer(SSLServerSocket sss) throws IOException {
+        try (Socket s = sss.accept()) {
+            s.getOutputStream().write('b');
+            s.getOutputStream().close();
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    private SSLServerSocket createSSLServer(final PrivateKey priv, final X509Certificate cert) throws Error, IOException {
+        SSLContext sc;
+        try {
+            sc = SSLContext.getInstance("SSL");
+            sc.init(new KeyManager[] {
+                    new X509KeyManager() {
+
+                        @Override
+                        public String[] getServerAliases(String keyType, Principal[] issuers) {
+                            return new String[] {
+                                    "server"
+                            };
+                        }
+
+                        @Override
+                        public PrivateKey getPrivateKey(String alias) {
+                            return priv;
+                        }
+
+                        @Override
+                        public String[] getClientAliases(String keyType, Principal[] issuers) {
+                            throw new Error();
+                        }
+
+                        @Override
+                        public X509Certificate[] getCertificateChain(String alias) {
+                            return new X509Certificate[] {
+                                    cert
+                            };
+                        }
+
+                        @Override
+                        public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
+                            throw new Error();
+                        }
+
+                        @Override
+                        public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+                            return "server";
+                        }
+
+                    }
+            }, new TrustManager[] {
+                    new X509TrustManager() {
+
+                        @Override
+                        public X509Certificate[] getAcceptedIssuers() {
+                            return null;
+                        }
+
+                        @Override
+                        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
+
+                        @Override
+                        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
+                    }
+            }, new SecureRandom());
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            throw new Error(e);
+        } catch (KeyManagementException e) {
+            e.printStackTrace();
+            throw new Error(e);
+        }
+
+        SSLServerSocketFactory sssf = sc.getServerSocketFactory();
+        return (SSLServerSocket) sssf.createServerSocket(0);
+    }
+
+    public static void main(String[] args) throws Exception {
+        initEnvironment();
+        TestSSL t1 = new TestSSL();
+        t1.sslAndMailSuccess();
+        tearDownServer();
+    }
+
+}