]> WPIA git - gigi.git/blob - src/org/cacert/gigi/Launcher.java
[test-config] FIX: the ssl-pinger+ add various tests for that.
[gigi.git] / src / org / cacert / gigi / Launcher.java
1 package org.cacert.gigi;
2
3 import java.io.IOException;
4 import java.security.GeneralSecurityException;
5 import java.security.Key;
6 import java.security.KeyStore;
7 import java.security.KeyStoreException;
8 import java.security.NoSuchAlgorithmException;
9 import java.security.UnrecoverableKeyException;
10 import java.security.cert.Certificate;
11 import java.util.List;
12 import java.util.Properties;
13 import java.util.TimeZone;
14
15 import javax.net.ssl.ExtendedSSLSession;
16 import javax.net.ssl.SNIHostName;
17 import javax.net.ssl.SNIServerName;
18 import javax.net.ssl.SSLEngine;
19 import javax.net.ssl.SSLParameters;
20 import javax.net.ssl.SSLSession;
21
22 import org.cacert.gigi.api.GigiAPI;
23 import org.cacert.gigi.email.EmailProvider;
24 import org.cacert.gigi.natives.SetUID;
25 import org.cacert.gigi.util.CipherInfo;
26 import org.cacert.gigi.util.ServerConstants;
27 import org.eclipse.jetty.http.HttpVersion;
28 import org.eclipse.jetty.server.Connector;
29 import org.eclipse.jetty.server.Handler;
30 import org.eclipse.jetty.server.HttpConfiguration;
31 import org.eclipse.jetty.server.HttpConnectionFactory;
32 import org.eclipse.jetty.server.SecureRequestCustomizer;
33 import org.eclipse.jetty.server.Server;
34 import org.eclipse.jetty.server.ServerConnector;
35 import org.eclipse.jetty.server.SessionManager;
36 import org.eclipse.jetty.server.SslConnectionFactory;
37 import org.eclipse.jetty.server.handler.ContextHandler;
38 import org.eclipse.jetty.server.handler.HandlerList;
39 import org.eclipse.jetty.server.handler.HandlerWrapper;
40 import org.eclipse.jetty.server.handler.ResourceHandler;
41 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
42 import org.eclipse.jetty.servlet.ServletContextHandler;
43 import org.eclipse.jetty.servlet.ServletHolder;
44 import org.eclipse.jetty.util.log.Log;
45 import org.eclipse.jetty.util.ssl.SslContextFactory;
46
47 public class Launcher {
48
49     public static void main(String[] args) throws Exception {
50         TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
51         GigiConfig conf = GigiConfig.parse(System.in);
52         ServerConstants.init(conf.getMainProps());
53         initEmails(conf);
54
55         Server s = new Server();
56         HttpConfiguration httpsConfig = createHttpConfiguration();
57
58         // for client-cert auth
59         httpsConfig.addCustomizer(new SecureRequestCustomizer());
60
61         HttpConfiguration httpConfig = createHttpConfiguration();
62
63         s.setConnectors(new Connector[] {
64                 createConnector(conf, s, httpsConfig, true), createConnector(conf, s, httpConfig, false)
65         });
66
67         HandlerList hl = new HandlerList();
68         hl.setHandlers(new Handler[] {
69                 generateStaticContext(), generateGigiContexts(conf.getMainProps(), conf.getTrustStore()), generateAPIContext()
70         });
71         s.setHandler(hl);
72         s.start();
73         if ((ServerConstants.getSecurePort() <= 1024 || ServerConstants.getPort() <= 1024) && !System.getProperty("os.name").toLowerCase().contains("win")) {
74             SetUID uid = new SetUID();
75             if ( !uid.setUid(65536 - 2, 65536 - 2).getSuccess()) {
76                 Log.getLogger(Launcher.class).warn("Couldn't set uid!");
77             }
78         }
79     }
80
81     private static ServerConnector createConnector(GigiConfig conf, Server s, HttpConfiguration httpConfig, boolean doHttps) throws GeneralSecurityException, IOException {
82         ServerConnector connector;
83         if (doHttps) {
84             connector = new ServerConnector(s, createConnectionFactory(conf), new HttpConnectionFactory(httpConfig));
85         } else {
86             connector = new ServerConnector(s);
87         }
88         connector.setHost(conf.getMainProps().getProperty("host"));
89         if (doHttps) {
90             connector.setPort(ServerConstants.getSecurePort());
91         } else {
92             connector.setPort(ServerConstants.getPort());
93         }
94         connector.setAcceptQueueSize(100);
95         return connector;
96     }
97
98     private static HttpConfiguration createHttpConfiguration() {
99         // SSL HTTP Configuration
100         HttpConfiguration httpsConfig = new HttpConfiguration();
101         httpsConfig.setSendServerVersion(false);
102         httpsConfig.setSendXPoweredBy(false);
103         return httpsConfig;
104     }
105
106     private static void initEmails(GigiConfig conf) throws GeneralSecurityException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
107         KeyStore privateStore = conf.getPrivateStore();
108         Certificate mail = privateStore.getCertificate("mail");
109         Key k = privateStore.getKey("mail", conf.getPrivateStorePw().toCharArray());
110         EmailProvider.initSystem(conf.getMainProps(), mail, k);
111     }
112
113     private static SslConnectionFactory createConnectionFactory(GigiConfig conf) throws GeneralSecurityException, IOException {
114         final SslContextFactory sslContextFactory = generateSSLContextFactory(conf, "www");
115         final SslContextFactory secureContextFactory = generateSSLContextFactory(conf, "secure");
116         secureContextFactory.setWantClientAuth(true);
117         secureContextFactory.setNeedClientAuth(false);
118         final SslContextFactory staticContextFactory = generateSSLContextFactory(conf, "static");
119         final SslContextFactory apiContextFactory = generateSSLContextFactory(conf, "api");
120         try {
121             secureContextFactory.start();
122             staticContextFactory.start();
123             apiContextFactory.start();
124         } catch (Exception e) {
125             e.printStackTrace();
126         }
127         return new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()) {
128
129             @Override
130             public boolean shouldRestartSSL() {
131                 return true;
132             }
133
134             @Override
135             public SSLEngine restartSSL(SSLSession sslSession) {
136                 SSLEngine e2 = null;
137                 if (sslSession instanceof ExtendedSSLSession) {
138                     ExtendedSSLSession es = (ExtendedSSLSession) sslSession;
139                     List<SNIServerName> names = es.getRequestedServerNames();
140                     for (SNIServerName sniServerName : names) {
141                         if (sniServerName instanceof SNIHostName) {
142                             SNIHostName host = (SNIHostName) sniServerName;
143                             String hostname = host.getAsciiName();
144                             if (hostname.equals(ServerConstants.getWwwHostName())) {
145                                 e2 = sslContextFactory.newSSLEngine();
146                             } else if (hostname.equals(ServerConstants.getStaticHostName())) {
147                                 e2 = staticContextFactory.newSSLEngine();
148                             } else if (hostname.equals(ServerConstants.getSecureHostName())) {
149                                 e2 = secureContextFactory.newSSLEngine();
150                             } else if (hostname.equals(ServerConstants.getApiHostName())) {
151                                 e2 = apiContextFactory.newSSLEngine();
152                             }
153                             break;
154                         }
155                     }
156                 }
157                 if (e2 == null) {
158                     e2 = sslContextFactory.newSSLEngine(sslSession.getPeerHost(), sslSession.getPeerPort());
159                 }
160                 e2.setUseClientMode(false);
161                 return e2;
162             }
163         };
164     }
165
166     private static Handler generateGigiContexts(Properties conf, KeyStore trust) {
167         ServletHolder webAppServlet = new ServletHolder(new Gigi(conf, trust));
168
169         ContextHandler ch = generateGigiServletContext(webAppServlet);
170         ch.setVirtualHosts(new String[] {
171             ServerConstants.getWwwHostName()
172         });
173         ContextHandler chSecure = generateGigiServletContext(webAppServlet);
174         chSecure.setVirtualHosts(new String[] {
175             ServerConstants.getSecureHostName()
176         });
177
178         HandlerList hl = new HandlerList();
179         hl.setHandlers(new Handler[] {
180                 ch, chSecure
181         });
182         return hl;
183     }
184
185     private static ContextHandler generateGigiServletContext(ServletHolder webAppServlet) {
186         final ResourceHandler rh = new ResourceHandler();
187         rh.setResourceBase("static/www");
188
189         HandlerWrapper hw = new PolicyRedirector();
190         hw.setHandler(rh);
191
192         ServletContextHandler servlet = new ServletContextHandler(ServletContextHandler.SESSIONS);
193         servlet.setInitParameter(SessionManager.__SessionCookieProperty, "CACert-Session");
194         servlet.addServlet(webAppServlet, "/*");
195         ErrorPageErrorHandler epeh = new ErrorPageErrorHandler();
196         epeh.addErrorPage(404, "/error");
197         servlet.setErrorHandler(epeh);
198
199         HandlerList hl = new HandlerList();
200         hl.setHandlers(new Handler[] {
201                 hw, servlet
202         });
203
204         ContextHandler ch = new ContextHandler();
205         ch.setHandler(hl);
206         return ch;
207     }
208
209     private static Handler generateStaticContext() {
210         final ResourceHandler rh = new ResourceHandler();
211         rh.setResourceBase("static/static");
212
213         ContextHandler ch = new ContextHandler();
214         ch.setHandler(rh);
215         ch.setVirtualHosts(new String[] {
216             ServerConstants.getStaticHostName()
217         });
218
219         return ch;
220     }
221
222     private static Handler generateAPIContext() {
223         ServletContextHandler sch = new ServletContextHandler();
224
225         sch.addVirtualHosts(new String[] {
226             ServerConstants.getApiHostName()
227         });
228         sch.addServlet(new ServletHolder(new GigiAPI()), "/*");
229         return sch;
230     }
231
232     private static SslContextFactory generateSSLContextFactory(GigiConfig conf, String alias) throws GeneralSecurityException, IOException {
233         SslContextFactory scf = new SslContextFactory() {
234
235             String[] ciphers = null;
236
237             @Override
238             public void customize(SSLEngine sslEngine) {
239                 super.customize(sslEngine);
240
241                 SSLParameters ssl = sslEngine.getSSLParameters();
242                 ssl.setUseCipherSuitesOrder(true);
243                 if (ciphers == null) {
244                     ciphers = CipherInfo.filter(sslEngine.getSupportedCipherSuites());
245                 }
246
247                 ssl.setCipherSuites(ciphers);
248                 sslEngine.setSSLParameters(ssl);
249
250             }
251
252         };
253         scf.setRenegotiationAllowed(false);
254
255         scf.setProtocol("TLS");
256         scf.setTrustStore(conf.getTrustStore());
257         KeyStore privateStore = conf.getPrivateStore();
258         scf.setKeyStorePassword(conf.getPrivateStorePw());
259         scf.setKeyStore(privateStore);
260         scf.setCertAlias(alias);
261         return scf;
262     }
263 }