]> WPIA git - gigi.git/blobdiff - src/org/cacert/gigi/Launcher.java
Support reading configuration from file
[gigi.git] / src / org / cacert / gigi / Launcher.java
index a7ba8a17bde3511a10b58ca5e0862315267d60ed..cff94772eff804d85593d9f537858ea887dd4254 100644 (file)
@@ -1,6 +1,12 @@
 package org.cacert.gigi;
 
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
 import java.security.GeneralSecurityException;
 import java.security.Key;
 import java.security.KeyStore;
@@ -8,6 +14,9 @@ import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.util.List;
 import java.util.Locale;
 import java.util.Properties;
@@ -19,18 +28,23 @@ import javax.net.ssl.SNIServerName;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLSession;
+import javax.servlet.http.HttpServletResponse;
 
 import org.cacert.gigi.api.GigiAPI;
 import org.cacert.gigi.email.EmailProvider;
 import org.cacert.gigi.natives.SetUID;
 import org.cacert.gigi.util.CipherInfo;
+import org.cacert.gigi.util.PEM;
 import org.cacert.gigi.util.ServerConstants;
+import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConfiguration.Customizer;
 import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.SecureRequestCustomizer;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
@@ -44,40 +58,74 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 
 public class Launcher {
 
+    class ExtendedForwarded implements Customizer {
+
+        @Override
+        public void customize(Connector connector, HttpConfiguration config, Request request) {
+            HttpFields httpFields = request.getHttpFields();
+
+            String ip = httpFields.getStringField("X-Real-IP");
+            String proto = httpFields.getStringField("X-Real-Proto");
+            String cert = httpFields.getStringField("X-Client-Cert");
+            request.setSecure("https".equals(proto));
+            request.setScheme(proto);
+            if ( !"https".equals(proto)) {
+                cert = null;
+
+            }
+            if (cert != null) {
+                X509Certificate[] certs = new X509Certificate[1];
+                try {
+                    certs[0] = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(PEM.decode("CERTIFICATE", cert)));
+                    request.setAttribute("javax.servlet.request.X509Certificate", certs);
+                } catch (CertificateException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (ip != null) {
+                String[] parts = ip.split(":");
+                if (parts.length == 2) {
+                    request.setRemoteAddr(InetSocketAddress.createUnresolved(parts[0], Integer.parseInt(parts[1])));
+                }
+            }
+
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         System.setProperty("jdk.tls.ephemeralDHKeySize", "4096");
-        boot();
+        InputStream in;
+        if (args.length >= 1) {
+            in = new FileInputStream(new File(args[0]));
+        } else {
+            in = System.in;
+        }
+        new Launcher().boot(in);
     }
 
-    public static void boot() throws Exception {
+    Server s;
+
+    GigiConfig conf;
+
+    public synchronized void boot(InputStream in) throws Exception {
         Locale.setDefault(Locale.ENGLISH);
         TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+        HttpURLConnection.setFollowRedirects(false);
 
-        GigiConfig conf = GigiConfig.parse(System.in);
+        conf = GigiConfig.parse(in);
         ServerConstants.init(conf.getMainProps());
         initEmails(conf);
 
-        Server s = new Server();
-        HttpConfiguration httpsConfig = createHttpConfiguration();
-
-        // for client-cert auth
-        httpsConfig.addCustomizer(new SecureRequestCustomizer());
-
-        HttpConfiguration httpConfig = createHttpConfiguration();
+        s = new Server();
 
-        s.setConnectors(new Connector[] {
-                createConnector(conf, s, httpsConfig, true), createConnector(conf, s, httpConfig, false)
-        });
+        initConnectors();
+        initHandlers();
 
-        HandlerList hl = new HandlerList();
-        hl.setHandlers(new Handler[] {
-                generateStaticContext(), generateGigiContexts(conf.getMainProps(), conf.getTrustStore()), generateAPIContext()
-        });
-        s.setHandler(hl);
         s.start();
         if ((ServerConstants.getSecurePort() <= 1024 || ServerConstants.getPort() <= 1024) && !System.getProperty("os.name").toLowerCase().contains("win")) {
             SetUID uid = new SetUID();
@@ -85,29 +133,9 @@ public class Launcher {
                 Log.getLogger(Launcher.class).warn("Couldn't set uid!");
             }
         }
-        if (conf.getMainProps().containsKey("testrunner")) {
-            DevelLauncher.addDevelPage();
-        }
     }
 
-    private static ServerConnector createConnector(GigiConfig conf, Server s, HttpConfiguration httpConfig, boolean doHttps) throws GeneralSecurityException, IOException {
-        ServerConnector connector;
-        if (doHttps) {
-            connector = new ServerConnector(s, createConnectionFactory(conf), new HttpConnectionFactory(httpConfig));
-        } else {
-            connector = new ServerConnector(s, new HttpConnectionFactory(httpConfig));
-        }
-        connector.setHost(conf.getMainProps().getProperty("host"));
-        if (doHttps) {
-            connector.setPort(ServerConstants.getSecurePort());
-        } else {
-            connector.setPort(ServerConstants.getPort());
-        }
-        connector.setAcceptQueueSize(100);
-        return connector;
-    }
-
-    private static HttpConfiguration createHttpConfiguration() {
+    private HttpConfiguration createHttpConfiguration() {
         // SSL HTTP Configuration
         HttpConfiguration httpsConfig = new HttpConfiguration();
         httpsConfig.setSendServerVersion(false);
@@ -115,176 +143,235 @@ public class Launcher {
         return httpsConfig;
     }
 
-    private static void initEmails(GigiConfig conf) throws GeneralSecurityException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+    private void initConnectors() throws GeneralSecurityException, IOException {
+        HttpConfiguration httpConfig = createHttpConfiguration();
+        if (conf.getMainProps().getProperty("proxy", "false").equals("true")) {
+            httpConfig.addCustomizer(new ExtendedForwarded());
+            s.setConnectors(new Connector[] {
+                    ConnectorsLauncher.createConnector(conf, s, httpConfig, false)
+            });
+        } else {
+            HttpConfiguration httpsConfig = createHttpConfiguration();
+            // for client-cert auth
+            httpsConfig.addCustomizer(new SecureRequestCustomizer());
+            s.setConnectors(new Connector[] {
+                    ConnectorsLauncher.createConnector(conf, s, httpsConfig, true), ConnectorsLauncher.createConnector(conf, s, httpConfig, false)
+            });
+        }
+    }
+
+    private void initEmails(GigiConfig conf) throws GeneralSecurityException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
         KeyStore privateStore = conf.getPrivateStore();
-        Certificate mail = privateStore.getCertificate("mail");
-        Key k = privateStore.getKey("mail", conf.getPrivateStorePw().toCharArray());
+        Certificate mail = null;
+        Key k = null;
+        if (privateStore != null && privateStore.containsAlias("mail")) {
+            mail = privateStore.getCertificate("mail");
+            k = privateStore.getKey("mail", conf.getPrivateStorePw().toCharArray());
+        }
         EmailProvider.initSystem(conf.getMainProps(), mail, k);
     }
 
-    private static SslConnectionFactory createConnectionFactory(GigiConfig conf) throws GeneralSecurityException, IOException {
-        final SslContextFactory sslContextFactory = generateSSLContextFactory(conf, "www");
-        final SslContextFactory secureContextFactory = generateSSLContextFactory(conf, "secure");
-        secureContextFactory.setWantClientAuth(true);
-        secureContextFactory.setNeedClientAuth(false);
-        final SslContextFactory staticContextFactory = generateSSLContextFactory(conf, "static");
-        final SslContextFactory apiContextFactory = generateSSLContextFactory(conf, "api");
-        try {
-            secureContextFactory.start();
-            staticContextFactory.start();
-            apiContextFactory.start();
-        } catch (Exception e) {
-            e.printStackTrace();
+    private static class ConnectorsLauncher {
+
+        private ConnectorsLauncher() {}
+
+        protected static ServerConnector createConnector(GigiConfig conf, Server s, HttpConfiguration httpConfig, boolean doHttps) throws GeneralSecurityException, IOException {
+            ServerConnector connector;
+            if (doHttps) {
+                connector = new ServerConnector(s, createConnectionFactory(conf), new HttpConnectionFactory(httpConfig));
+            } else {
+                connector = new ServerConnector(s, new HttpConnectionFactory(httpConfig));
+            }
+            connector.setHost(conf.getMainProps().getProperty("host"));
+            if (doHttps) {
+                connector.setPort(ServerConstants.getSecurePort());
+            } else {
+                connector.setPort(ServerConstants.getPort());
+            }
+            connector.setAcceptQueueSize(100);
+            return connector;
         }
-        return new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()) {
 
-            @Override
-            public boolean shouldRestartSSL() {
-                return true;
+        private static SslConnectionFactory createConnectionFactory(GigiConfig conf) throws GeneralSecurityException, IOException {
+            final SslContextFactory sslContextFactory = generateSSLContextFactory(conf, "www");
+            final SslContextFactory secureContextFactory = generateSSLContextFactory(conf, "secure");
+            secureContextFactory.setWantClientAuth(true);
+            secureContextFactory.setNeedClientAuth(true);
+            final SslContextFactory staticContextFactory = generateSSLContextFactory(conf, "static");
+            final SslContextFactory apiContextFactory = generateSSLContextFactory(conf, "api");
+            apiContextFactory.setWantClientAuth(true);
+            try {
+                secureContextFactory.start();
+                staticContextFactory.start();
+                apiContextFactory.start();
+            } catch (Exception e) {
+                e.printStackTrace();
             }
+            return new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()) {
+
+                @Override
+                public boolean shouldRestartSSL() {
+                    return true;
+                }
 
-            @Override
-            public SSLEngine restartSSL(SSLSession sslSession) {
-                SSLEngine e2 = null;
-                if (sslSession instanceof ExtendedSSLSession) {
-                    ExtendedSSLSession es = (ExtendedSSLSession) sslSession;
-                    List<SNIServerName> names = es.getRequestedServerNames();
-                    for (SNIServerName sniServerName : names) {
-                        if (sniServerName instanceof SNIHostName) {
-                            SNIHostName host = (SNIHostName) sniServerName;
-                            String hostname = host.getAsciiName();
-                            if (hostname.equals(ServerConstants.getWwwHostName())) {
-                                e2 = sslContextFactory.newSSLEngine();
-                            } else if (hostname.equals(ServerConstants.getStaticHostName())) {
-                                e2 = staticContextFactory.newSSLEngine();
-                            } else if (hostname.equals(ServerConstants.getSecureHostName())) {
-                                e2 = secureContextFactory.newSSLEngine();
-                            } else if (hostname.equals(ServerConstants.getApiHostName())) {
-                                e2 = apiContextFactory.newSSLEngine();
+                @Override
+                public SSLEngine restartSSL(SSLSession sslSession) {
+                    SSLEngine e2 = null;
+                    if (sslSession instanceof ExtendedSSLSession) {
+                        ExtendedSSLSession es = (ExtendedSSLSession) sslSession;
+                        List<SNIServerName> names = es.getRequestedServerNames();
+                        for (SNIServerName sniServerName : names) {
+                            if (sniServerName instanceof SNIHostName) {
+                                SNIHostName host = (SNIHostName) sniServerName;
+                                String hostname = host.getAsciiName();
+                                if (hostname.equals(ServerConstants.getWwwHostName())) {
+                                    e2 = sslContextFactory.newSSLEngine();
+                                } else if (hostname.equals(ServerConstants.getStaticHostName())) {
+                                    e2 = staticContextFactory.newSSLEngine();
+                                } else if (hostname.equals(ServerConstants.getSecureHostName())) {
+                                    e2 = secureContextFactory.newSSLEngine();
+                                } else if (hostname.equals(ServerConstants.getApiHostName())) {
+                                    e2 = apiContextFactory.newSSLEngine();
+                                }
+                                break;
                             }
-                            break;
                         }
                     }
+                    if (e2 == null) {
+                        e2 = sslContextFactory.newSSLEngine(sslSession.getPeerHost(), sslSession.getPeerPort());
+                    }
+                    e2.setUseClientMode(false);
+                    return e2;
                 }
-                if (e2 == null) {
-                    e2 = sslContextFactory.newSSLEngine(sslSession.getPeerHost(), sslSession.getPeerPort());
-                }
-                e2.setUseClientMode(false);
-                return e2;
-            }
-        };
-    }
+            };
+        }
 
-    private static Handler generateGigiContexts(Properties conf, KeyStore trust) {
-        ServletHolder webAppServlet = new ServletHolder(new Gigi(conf, trust));
+        private static SslContextFactory generateSSLContextFactory(GigiConfig conf, String alias) throws GeneralSecurityException, IOException {
+            SslContextFactory scf = new SslContextFactory() {
 
-        ContextHandler ch = generateGigiServletContext(webAppServlet);
-        ch.setVirtualHosts(new String[] {
-            ServerConstants.getWwwHostName()
-        });
-        ContextHandler chSecure = generateGigiServletContext(webAppServlet);
-        chSecure.setVirtualHosts(new String[] {
-            ServerConstants.getSecureHostName()
-        });
+                String[] ciphers = null;
 
-        HandlerList hl = new HandlerList();
-        hl.setHandlers(new Handler[] {
-                ch, chSecure
-        });
-        return hl;
-    }
+                @Override
+                public void customize(SSLEngine sslEngine) {
+                    super.customize(sslEngine);
+
+                    SSLParameters ssl = sslEngine.getSSLParameters();
+                    ssl.setUseCipherSuitesOrder(true);
+                    if (ciphers == null) {
+                        ciphers = CipherInfo.filter(sslEngine.getSupportedCipherSuites());
+                    }
 
-    private static ContextHandler generateGigiServletContext(ServletHolder webAppServlet) {
-        final ResourceHandler rh = generateResourceHandler();
-        rh.setResourceBase("static/www");
+                    ssl.setCipherSuites(ciphers);
+                    sslEngine.setSSLParameters(ssl);
 
-        HandlerWrapper hw = new PolicyRedirector();
-        hw.setHandler(rh);
+                }
 
-        ServletContextHandler servlet = new ServletContextHandler(ServletContextHandler.SESSIONS);
-        servlet.setInitParameter(SessionManager.__SessionCookieProperty, "CACert-Session");
-        servlet.addServlet(webAppServlet, "/*");
-        ErrorPageErrorHandler epeh = new ErrorPageErrorHandler();
-        epeh.addErrorPage(404, "/error");
-        epeh.addErrorPage(403, "/denied");
-        servlet.setErrorHandler(epeh);
+            };
+            scf.setRenegotiationAllowed(false);
+
+            scf.setProtocol("TLS");
+            scf.setIncludeProtocols("TLSv1", "TLSv1.1", "TLSv1.2");
+            scf.setTrustStore(conf.getTrustStore());
+            KeyStore privateStore = conf.getPrivateStore();
+            scf.setKeyStorePassword(conf.getPrivateStorePw());
+            scf.setKeyStore(privateStore);
+            scf.setCertAlias(alias);
+            return scf;
+        }
+    }
 
+    private void initHandlers() throws GeneralSecurityException, IOException {
         HandlerList hl = new HandlerList();
         hl.setHandlers(new Handler[] {
-                hw, servlet
+                ContextLauncher.generateStaticContext(), ContextLauncher.generateGigiContexts(conf.getMainProps(), conf.getTrustStore()), ContextLauncher.generateAPIContext()
         });
-
-        ContextHandler ch = new ContextHandler();
-        ch.setHandler(hl);
-        return ch;
+        s.setHandler(hl);
     }
 
-    private static Handler generateStaticContext() {
-        final ResourceHandler rh = generateResourceHandler();
-        rh.setResourceBase("static/static");
+    private static class ContextLauncher {
 
-        ContextHandler ch = new ContextHandler();
-        ch.setHandler(rh);
-        ch.setVirtualHosts(new String[] {
-            ServerConstants.getStaticHostName()
-        });
+        private ContextLauncher() {}
 
-        return ch;
-    }
+        protected static Handler generateGigiContexts(Properties conf, KeyStore trust) {
+            ServletHolder webAppServlet = new ServletHolder(new Gigi(conf, trust));
 
-    private static ResourceHandler generateResourceHandler() {
-        ResourceHandler rh = new ResourceHandler() {
+            ContextHandler ch = generateGigiServletContext(webAppServlet);
+            ch.setVirtualHosts(new String[] {
+                    ServerConstants.getWwwHostName()
+            });
+            ContextHandler chSecure = generateGigiServletContext(webAppServlet);
+            chSecure.setVirtualHosts(new String[] {
+                    ServerConstants.getSecureHostName()
+            });
 
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws IOException, javax.servlet.ServletException {
-                response.setDateHeader(HttpHeader.EXPIRES.asString(), System.currentTimeMillis() + 1000L * 60 * 60 * 24 * 7);
-                super.handle(target, baseRequest, request, response);
-            }
-        };
-        rh.setEtags(true);
-        return rh;
-    }
+            HandlerList hl = new HandlerList();
+            hl.setHandlers(new Handler[] {
+                    ch, chSecure
+            });
+            return hl;
+        }
 
-    private static Handler generateAPIContext() {
-        ServletContextHandler sch = new ServletContextHandler();
+        private static ContextHandler generateGigiServletContext(ServletHolder webAppServlet) {
+            final ResourceHandler rh = generateResourceHandler();
+            rh.setResourceBase("static/www");
+
+            HandlerWrapper hw = new PolicyRedirector();
+            hw.setHandler(rh);
+
+            ServletContextHandler servlet = new ServletContextHandler(ServletContextHandler.SESSIONS);
+            servlet.setInitParameter(SessionManager.__SessionCookieProperty, "SomeCA-Session");
+            servlet.addServlet(webAppServlet, "/*");
+            ErrorPageErrorHandler epeh = new ErrorPageErrorHandler();
+            epeh.addErrorPage(404, "/error");
+            epeh.addErrorPage(403, "/denied");
+            servlet.setErrorHandler(epeh);
+
+            HandlerList hl = new HandlerList();
+            hl.setHandlers(new Handler[] {
+                    hw, servlet
+            });
+
+            ContextHandler ch = new ContextHandler();
+            ch.setHandler(hl);
+            return ch;
+        }
 
-        sch.addVirtualHosts(new String[] {
-            ServerConstants.getApiHostName()
-        });
-        sch.addServlet(new ServletHolder(new GigiAPI()), "/*");
-        return sch;
-    }
+        protected static Handler generateStaticContext() {
+            final ResourceHandler rh = generateResourceHandler();
+            rh.setResourceBase("static/static");
 
-    private static SslContextFactory generateSSLContextFactory(GigiConfig conf, String alias) throws GeneralSecurityException, IOException {
-        SslContextFactory scf = new SslContextFactory() {
+            ContextHandler ch = new ContextHandler();
+            ch.setHandler(rh);
+            ch.setVirtualHosts(new String[] {
+                    ServerConstants.getStaticHostName()
+            });
 
-            String[] ciphers = null;
+            return ch;
+        }
 
-            @Override
-            public void customize(SSLEngine sslEngine) {
-                super.customize(sslEngine);
+        private static ResourceHandler generateResourceHandler() {
+            ResourceHandler rh = new ResourceHandler() {
 
-                SSLParameters ssl = sslEngine.getSSLParameters();
-                ssl.setUseCipherSuitesOrder(true);
-                if (ciphers == null) {
-                    ciphers = CipherInfo.filter(sslEngine.getSupportedCipherSuites());
+                @Override
+                protected void doResponseHeaders(HttpServletResponse response, Resource resource, String mimeType) {
+                    super.doResponseHeaders(response, resource, mimeType);
+                    response.setDateHeader(HttpHeader.EXPIRES.asString(), System.currentTimeMillis() + 1000L * 60 * 60 * 24 * 7);
                 }
+            };
+            rh.setEtags(true);
+            return rh;
+        }
 
-                ssl.setCipherSuites(ciphers);
-                sslEngine.setSSLParameters(ssl);
+        protected static Handler generateAPIContext() {
+            ServletContextHandler sch = new ServletContextHandler();
 
-            }
-
-        };
-        scf.setRenegotiationAllowed(false);
+            sch.addVirtualHosts(new String[] {
+                    ServerConstants.getApiHostName()
+            });
+            sch.addServlet(new ServletHolder(new GigiAPI()), "/*");
+            return sch;
+        }
 
-        scf.setProtocol("TLS");
-        scf.setIncludeProtocols("TLSv1", "TLSv1.1", "TLSv1.2");
-        scf.setTrustStore(conf.getTrustStore());
-        KeyStore privateStore = conf.getPrivateStore();
-        scf.setKeyStorePassword(conf.getPrivateStorePw());
-        scf.setKeyStore(privateStore);
-        scf.setCertAlias(alias);
-        return scf;
     }
+
 }