View Javadoc

1   /*
2    * Copyright (c) 2012, Maximilian Schmidt
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    * 
8    * Redistributions of source code must retain the above copyright notice, this 
9    * list of conditions and the following disclaimer.
10   * Redistributions in binary form must reproduce the above copyright notice, 
11   * this list of conditions and the following disclaimer in the documentation 
12   * and/or other materials provided with the distribution.
13   * 
14   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
16   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
17   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
18   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
19   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
20   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
21   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
22   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24   * 
25   */
26  package de.fub.mi.idenpa.jetty;
27  
28  import java.io.File;
29  import java.io.FileInputStream;
30  import java.io.FileNotFoundException;
31  import java.io.FileOutputStream;
32  import java.io.InputStream;
33  import java.io.OutputStream;
34  import java.math.BigInteger;
35  import java.security.KeyPair;
36  import java.security.KeyPairGenerator;
37  import java.security.KeyStore;
38  import java.security.SecureRandom;
39  import java.security.Security;
40  import java.security.cert.X509Certificate;
41  import java.util.Date;
42  
43  import org.bouncycastle.jce.X509Principal;
44  import org.bouncycastle.jce.provider.BouncyCastleProvider;
45  import org.bouncycastle.x509.X509V3CertificateGenerator;
46  import org.eclipse.jetty.server.Connector;
47  import org.eclipse.jetty.server.Server;
48  import org.eclipse.jetty.server.ssl.SslSocketConnector;
49  import org.eclipse.jetty.util.ssl.SslContextFactory;
50  import org.eclipse.jetty.webapp.WebAppContext;
51  
52  /**
53   * Provides a way to start the embedded Jetty-server, enabling SSL using a static keypair
54   */
55  public class ServerMain {
56  
57  	/** The context path. */
58  	private static String contextPath = "/";
59  	
60  	/** The resource base. */
61  	private static String resourceBase = "WebContent";
62  	
63  	/** The http port. */
64  	private static int httpPort = 8888;
65  	
66  	/** The Constant KS_SEC. */
67  	private static final String KS_SEC = "df7§j7y/!bn";
68  	
69  	/** The Constant KSFILE. */
70  	private static final String KSFILE = ".idemix/ssl.jks";
71  
72  	/**
73  	 * The main method.
74  	 *
75  	 * @param args the arguments
76  	 * @throws Exception the exception
77  	 */
78  	public static void main(String[] args) throws Exception {
79  		Server server = new Server();
80  		SslContextFactory factory = new SslContextFactory(true);
81  		KeyStore ks = KeyStore.getInstance("JKS");
82  		// String ksPass = UUID.randomUUID().toString();
83  		factory.setKeyStore(ks);
84  		factory.setKeyStore(getKeystore(KS_SEC));
85  		factory.setKeyStorePassword(KS_SEC);
86  		factory.setTrustAll(true);
87  		SslSocketConnector sslConnector = new SslSocketConnector(factory);
88  		sslConnector.setPort(httpPort);
89  
90  		// SelectChannelConnector selectChannelConnector = new
91  		// SelectChannelConnector();
92  		// selectChannelConnector.setPort(httpPort); // To accept connection
93  		// from 8080, otherwise the normal connection cannot be passed into 8080
94  		server.setConnectors(new Connector[] { sslConnector });
95  
96  		WebAppContext webapp = new WebAppContext();
97  		webapp.setContextPath(contextPath);
98  		webapp.setDefaultsDescriptor("WebContent/WEB-INF/web.xml");
99  		webapp.setResourceBase(resourceBase);
100 		webapp.setClassLoader(Thread.currentThread().getContextClassLoader());
101 		server.setHandler(webapp);
102 		server.start();
103 		server.join();
104 
105 		server.start();
106 		server.join();
107 	}
108 
109 	/**
110 	 * Gets the keystore.
111 	 *
112 	 * @param pass the pass
113 	 * @return the keystore
114 	 */
115 	private static KeyStore getKeystore(String pass) {
116 		KeyStore result = null;
117 
118 		Security.addProvider(new BouncyCastleProvider());
119 
120 		try {
121 			result = KeyStore.getInstance("JKS");
122 			result.load(getKsStream(), pass.toCharArray());
123 
124 			if (!isKsFileAvailable()) {
125 				KeyPairGenerator keyPairGenerator = KeyPairGenerator
126 						.getInstance("RSA");
127 				keyPairGenerator.initialize(1024);
128 				KeyPair KPair = keyPairGenerator.generateKeyPair();
129 				X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
130 				int serial = Math.abs(new SecureRandom().nextInt());
131 				v3CertGen.setSerialNumber(BigInteger.valueOf(serial));
132 				v3CertGen.setIssuerDN(new X509Principal(
133 						"CN=localhost, OU=None, O=None L=None, C=None"));
134 				v3CertGen.setNotBefore(new Date(System.currentTimeMillis()
135 						- 1000L * 60 * 60 * 24 * 30));
136 				v3CertGen.setNotAfter(new Date(System.currentTimeMillis()
137 						+ (1000L * 60 * 60 * 24 * 365 * 10)));
138 				v3CertGen.setSubjectDN(new X509Principal(
139 						"CN=localhost, OU=None, O=None L=None, C=None"));
140 				v3CertGen.setPublicKey(KPair.getPublic());
141 				v3CertGen.setSignatureAlgorithm("MD5WithRSAEncryption");
142 
143 				X509Certificate PKCertificate = v3CertGen
144 						.generateX509Certificate(KPair.getPrivate());
145 
146 				result.setKeyEntry("jetty", KPair.getPrivate(),
147 						pass.toCharArray(),
148 						new java.security.cert.Certificate[] { PKCertificate });
149 
150 				result.store(getKsOutStream(), pass.toCharArray());
151 			}
152 		} catch (Throwable t) {
153 			t.printStackTrace();
154 		}
155 
156 		return result;
157 	}
158 
159 	/**
160 	 * Gets the ks file.
161 	 *
162 	 * @return the ks file
163 	 */
164 	private static final String getKsFile() {
165 		String result = null;
166 		String uHome = System.getProperty("user.home");
167 		if (uHome != null) {
168 			result = uHome + File.separator + KSFILE;
169 		}
170 		return result;
171 	}
172 
173 	/**
174 	 * Checks if is ks file available.
175 	 *
176 	 * @return true, if is ks file available
177 	 */
178 	private static final boolean isKsFileAvailable() {
179 		boolean result = false;
180 
181 		File f = new File(getKsFile());
182 		result = f.exists();
183 
184 		return result;
185 	}
186 
187 	/**
188 	 * Gets the ks stream.
189 	 *
190 	 * @return the ks stream
191 	 */
192 	private static final InputStream getKsStream() {
193 		InputStream result = null;
194 
195 		if (isKsFileAvailable()) {
196 			try {
197 				result = new FileInputStream(new File(getKsFile()));
198 			} catch (FileNotFoundException e) {
199 			}
200 		}
201 
202 		return result;
203 	}
204 
205 	/**
206 	 * Gets the ks out stream.
207 	 *
208 	 * @return the ks out stream
209 	 */
210 	private static final OutputStream getKsOutStream() {
211 		OutputStream result = null;
212 
213 		try {
214 			File f = new File(getKsFile());
215 			if (!f.getParentFile().exists())
216 				f.getParentFile().mkdirs();
217 			
218 			result = new FileOutputStream(f);
219 		} catch (FileNotFoundException e) {
220 		}
221 
222 		return result;
223 	}
224 
225 }