Merged branch 'jetty-9.4.x' into 'master'.

This commit is contained in:
Simone Bordet 2016-05-24 12:42:41 +02:00
commit ba8e0bb828
17 changed files with 709 additions and 1279 deletions

View File

@ -19,7 +19,6 @@
package org.eclipse.jetty.client;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException;
@ -109,23 +108,10 @@ public class HostnameVerificationTest
}
catch (ExecutionException x)
{
// The test may fail in 2 ways, since the CertificateException thrown because of the hostname
// verification failure is not rethrown immediately by the JDK SSL implementation, but only
// rethrown on the next read or write.
// Therefore this test may catch a SSLHandshakeException, or a ClosedChannelException.
// If it is the former, we verify that its cause is a CertificateException.
// ExecutionException wraps an SSLHandshakeException
Throwable cause = x.getCause();
if (cause==null)
{
x.printStackTrace();
Assert.fail("No cause?");
}
if (cause instanceof SSLHandshakeException)
Assert.assertThat(cause.getCause().getCause(), Matchers.instanceOf(CertificateException.class));
else
Assert.assertThat(cause, Matchers.instanceOf(ClosedChannelException.class));
Assert.assertThat(cause, Matchers.instanceOf(SSLHandshakeException.class));
Throwable root = cause.getCause().getCause();
Assert.assertThat(root, Matchers.instanceOf(CertificateException.class));
}
}
@ -134,7 +120,7 @@ public class HostnameVerificationTest
* work fine.
*
* @throws Exception on test failure
*
*
*/
@Test
public void simpleGetWithHostnameVerificationDisabledTest() throws Exception

View File

@ -26,7 +26,6 @@ import java.io.OutputStream;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@ -105,13 +104,10 @@ public class SslBytesClientTest extends SslBytesTest
final SSLSocket server = (SSLSocket)acceptor.accept();
server.setUseClientMode(false);
Future<Object> handshake = threadPool.submit(new Callable<Object>()
Future<Object> handshake = threadPool.submit(() ->
{
public Object call() throws Exception
{
server.startHandshake();
return null;
}
server.startHandshake();
return null;
});
// Client Hello
@ -185,13 +181,10 @@ public class SslBytesClientTest extends SslBytesTest
final SSLSocket server = (SSLSocket)acceptor.accept();
server.setUseClientMode(false);
Future<Object> handshake = threadPool.submit(new Callable<Object>()
Future<Object> handshake = threadPool.submit(() ->
{
public Object call() throws Exception
{
server.startHandshake();
return null;
}
server.startHandshake();
return null;
});
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
@ -222,13 +215,10 @@ public class SslBytesClientTest extends SslBytesTest
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
// Renegotiate
Future<Object> renegotiation = threadPool.submit(new Callable<Object>()
Future<Object> renegotiation = threadPool.submit(() ->
{
public Object call() throws Exception
{
server.startHandshake();
return null;
}
server.startHandshake();
return null;
});
// Renegotiation Handshake
@ -307,13 +297,10 @@ public class SslBytesClientTest extends SslBytesTest
final SSLSocket server = (SSLSocket)acceptor.accept();
server.setUseClientMode(false);
Future<Object> handshake = threadPool.submit(new Callable<Object>()
Future<Object> handshake = threadPool.submit(() ->
{
public Object call() throws Exception
{
server.startHandshake();
return null;
}
server.startHandshake();
return null;
});
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
@ -344,13 +331,10 @@ public class SslBytesClientTest extends SslBytesTest
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
// Renegotiate
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
public Object call() throws Exception
{
server.startHandshake();
return null;
}
server.startHandshake();
return null;
});
// Renegotiation Handshake
@ -358,6 +342,9 @@ public class SslBytesClientTest extends SslBytesTest
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
proxy.flushToClient(record);
// Client sends close alert.
record = proxy.readFromClient();
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
record = proxy.readFromClient();
Assert.assertNull(record);

View File

@ -30,7 +30,6 @@ import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -242,14 +241,10 @@ public class SslBytesServerTest extends SslBytesTest
{
final SSLSocket client = newClient();
Future<Object> handshake = threadPool.submit(new Callable<Object>()
Future<Object> handshake = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Client Hello
@ -316,14 +311,10 @@ public class SslBytesServerTest extends SslBytesTest
final SSLSocket client2 = newClient(proxy);
Future<Object> handshake = threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client2.startHandshake();
return null;
}
client2.startHandshake();
return null;
});
// Client Hello with SessionID
@ -366,19 +357,14 @@ public class SslBytesServerTest extends SslBytesTest
System.arraycopy(doneBytes, 0, chunk, recordBytes.length, doneBytes.length);
System.arraycopy(closeRecordBytes, 0, chunk, recordBytes.length + doneBytes.length, closeRecordBytes.length);
proxy.flushToServer(0, chunk);
// Close the raw socket
proxy.flushToServer(null);
// Expect the server to send a FIN as well
// Expect the server to send a TLS Alert.
record = proxy.readFromServer();
Assert.assertNotNull(record);
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
record = proxy.readFromServer();
if (record!=null)
{
// Close alert snuck out // TODO check if this is acceptable
Assert.assertEquals(Type.ALERT,record.getType());
record = proxy.readFromServer();
}
Assert.assertNull(record);
// Check that we did not spin
@ -393,14 +379,10 @@ public class SslBytesServerTest extends SslBytesTest
{
final SSLSocket client = newClient();
Future<Object> handshake = threadPool.submit(new Callable<Object>()
Future<Object> handshake = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Client Hello
@ -486,7 +468,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -498,14 +480,10 @@ public class SslBytesServerTest extends SslBytesTest
{
final SSLSocket client = newClient();
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Client Hello
@ -531,14 +509,10 @@ public class SslBytesServerTest extends SslBytesTest
{
final SSLSocket client = newClient();
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Client Hello
@ -586,19 +560,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -628,19 +598,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -677,14 +643,10 @@ public class SslBytesServerTest extends SslBytesTest
{
final SSLSocket client = newClient();
Future<Object> handshake = threadPool.submit(new Callable<Object>()
Future<Object> handshake = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Client Hello
@ -721,19 +683,15 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertNull(handshake.get(1, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -782,7 +740,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -801,19 +759,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -844,7 +798,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -876,19 +830,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -919,7 +869,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -946,19 +896,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -981,7 +927,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -1005,19 +951,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -1038,7 +980,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -1058,7 +1000,7 @@ public class SslBytesServerTest extends SslBytesTest
{
// Don't run on Windows (buggy JVM)
Assume.assumeTrue(!OS.IS_WINDOWS);
final SSLSocket client = newClient();
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
@ -1068,21 +1010,17 @@ public class SslBytesServerTest extends SslBytesTest
byte[] data = new byte[128 * 1024];
Arrays.fill(data, (byte)'X');
final String content = new String(data, StandardCharsets.UTF_8);
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET /echo HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET /echo HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Nine TLSRecords will be generated for the request
@ -1119,7 +1057,7 @@ public class SslBytesServerTest extends SslBytesTest
{
// Don't run on Windows (buggy JVM)
Assume.assumeTrue(!OS.IS_WINDOWS);
final SSLSocket client = newClient();
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
@ -1129,21 +1067,17 @@ public class SslBytesServerTest extends SslBytesTest
byte[] data = new byte[128 * 1024];
Arrays.fill(data, (byte)'X');
final String content = new String(data, StandardCharsets.UTF_8);
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET /echo_suppress_exception HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET /echo_suppress_exception HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Nine TLSRecords will be generated for the request,
@ -1193,19 +1127,15 @@ public class SslBytesServerTest extends SslBytesTest
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -1245,7 +1175,7 @@ public class SslBytesServerTest extends SslBytesTest
if (record!=null)
{
Assert.assertEquals(record.getType(),Type.ALERT);
// Now should be a raw close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
@ -1269,22 +1199,18 @@ public class SslBytesServerTest extends SslBytesTest
final String content = "0123456789ABCDEF";
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Application data
@ -1335,22 +1261,18 @@ public class SslBytesServerTest extends SslBytesTest
Arrays.fill(data, (byte)'X');
final String content = new String(data, StandardCharsets.UTF_8);
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("" +
"POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: " + content.length() + "\r\n" +
"\r\n" +
content).getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Nine TLSRecords will be generated for the request
@ -1434,14 +1356,10 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
// Renegotiate
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Renegotiation Handshake
@ -1458,15 +1376,11 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertNull(record);
// Write the rest of the request
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
clientOutput.write(content2.getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
clientOutput.write(content2.getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Trying to write more application data results in an exception since the server closed
@ -1481,6 +1395,7 @@ public class SslBytesServerTest extends SslBytesTest
}
catch (IOException expected)
{
// Expected
}
// Check that we did not spin
@ -1525,14 +1440,10 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
// Renegotiate
Future<Object> renegotiation = threadPool.submit(new Callable<Object>()
Future<Object> renegotiation = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Renegotiation Handshake
@ -1580,15 +1491,11 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS));
// Write the rest of the request
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
clientOutput.write(content2.getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
clientOutput.write(content2.getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Three TLSRecords will be generated for the remainder of the content
@ -1659,14 +1566,10 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
// Renegotiate
Future<Object> renegotiation = threadPool.submit(new Callable<Object>()
Future<Object> renegotiation = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Renegotiation Handshake
@ -1732,15 +1635,11 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS));
// Write the rest of the request
Future<Object> request = threadPool.submit(new Callable<Object>()
Future<Object> request = threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
clientOutput.write(content2.getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
}
clientOutput.write(content2.getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
return null;
});
// Three TLSRecords will be generated for the remainder of the content
@ -1847,25 +1746,21 @@ public class SslBytesServerTest extends SslBytesTest
{
final SSLSocket client = newClient();
threadPool.submit(new Callable<Object>()
threadPool.submit(() ->
{
@Override
public Object call() throws Exception
{
client.startHandshake();
return null;
}
client.startHandshake();
return null;
});
// Instead of passing the Client Hello, we simulate plain text was passed in
proxy.flushToServer(0, "GET / HTTP/1.1\r\n".getBytes(StandardCharsets.UTF_8));
// We expect that the server sends an alert message and closes.
// We expect that the server sends the TLS Alert.
TLSRecord record = proxy.readFromServer();
Assert.assertNotNull(record);
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
Assert.assertNull(record);
// Check that we did not spin
TimeUnit.MILLISECONDS.sleep(500);
@ -1883,27 +1778,24 @@ public class SslBytesServerTest extends SslBytesTest
final OutputStream clientOutput = client.getOutputStream();
final CountDownLatch latch = new CountDownLatch(1);
idleHook = new Runnable()
idleHook = () ->
{
public void run()
if (latch.getCount()==0)
return;
try
{
if (latch.getCount()==0)
return;
try
{
// Send request
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
latch.countDown();
}
catch (Exception x)
{
// Latch won't trigger and test will fail
x.printStackTrace();
}
// Send request
clientOutput.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n").getBytes(StandardCharsets.UTF_8));
clientOutput.flush();
latch.countDown();
}
catch (Exception x)
{
// Latch won't trigger and test will fail
x.printStackTrace();
}
};
@ -1983,6 +1875,6 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertEquals(record.getType(),Type.ALERT);
record = proxy.readFromServer();
}
Assert.assertThat(record, Matchers.nullValue());
Assert.assertNull(record);
}
}

View File

@ -17,18 +17,14 @@
[[jetty-connectors]]
=== Connector Configuration Overview
Connectors are the mechanism through which Jetty accepts network
connections for various protocols. Configuring a connector is a
combination of configuring the following:
Connectors are the mechanism through which Jetty accepts network connections for various protocols.
Configuring a connector is a combination of configuring the following:
* Network parameters on the connector itself (for example: the listening
port).
* Network parameters on the connector itself (for example: the listening port).
* Services the connector uses (for example: executors, schedulers).
* Connection factories that instantiate and configure the protocol for
an accepted connection.
* Connection factories that instantiate and configure the protocol for an accepted connection.
Jetty primarily uses a single connector type called
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[ServerConnector].
Jetty primarily uses a single connector type called link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[ServerConnector].
____
[NOTE]
@ -36,65 +32,27 @@ Prior to Jetty 9, the type of the connector specified both the protocol and the
Jetty 9 has only a selector-based non blocking I/O connector, and a collection of link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactories`] now configure the protocol on the connector.
____
The standard Jetty distribution comes with the following Jetty XML files
that create and configure connectors; you should examine them as you
read this section:
The standard Jetty distribution comes with the following Jetty XML files that create and configure connectors; you should examine them as you read this section:
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-http.xml[`jetty-http.xml`]::
Instantiates a
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
that accepts HTTP connections (that may be upgraded to WebSocket
connections).
Instantiates a link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] that accepts HTTP connections (that may be upgraded to WebSocket connections).
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-ssl.xml[`jetty-ssl.xml`]::
Instantiates a
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
that accepts SSL/TLS connections. On it's own, this connector is not
functional and requires one or more of the following files to also be
configured to add
link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactories`]
to make the connector functional.
Instantiates a link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] that accepts SSL/TLS connections.
On it's own, this connector is not functional and requires one or more of the following files to also be configured to add link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactories`] to make the connector functional.
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-https.xml[`jetty-https.xml`]::
Adds a
link:{JDURL}/org/eclipse/jetty/server/HttpConnectionFactory.html[`HttpConnectionFactory`]
to the
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
configured by `jetty-ssl.xml` which combine to provide support for
HTTPS.
Adds a link:{JDURL}/org/eclipse/jetty/server/HttpConnectionFactory.html[`HttpConnectionFactory`] to the link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] configured by `jetty-ssl.xml` which combine to provide support for HTTPS.
link:{SRCDIR}/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml[`jetty-http2.xml`]::
Adds a
link:{JDURL}/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.html[`Http2ServerConnectionFactory`]
to the
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
configured by `jetty-ssl.xml to support the http2
protocol.` Also prepends either `protonego-alpn.xml` or
`protonego-npn.xml` so that the next protocol can be negotiated, which
allows the same SSL port to handle multiple protocols.
Adds a link:{JDURL}/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.html[`Http2ServerConnectionFactory`] to the link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] configured by `jetty-ssl.xml` to support the http2 protocol. Also prepends either `protonego-alpn.xml` or `protonego-npn.xml` so that the next protocol can be negotiated, which allows the same SSL port to handle multiple protocols.
link:{SRCDIR}/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml[`jetty-alpn.xml`]::
Adds an
link:{JDURL}/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.html[`ALPNServerConnectionFactory`]
to the
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
configured by `jetty-ssl.xml` which allows the one SSL connector to
support multiple protocols with the ALPN extension used to select the
protocol to be used for each connection.
Adds an link:{JDURL}/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.html[`ALPNServerConnectionFactory`] to the link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] configured by `jetty-ssl.xml` which allows the one SSL connector to support multiple protocols with the ALPN extension used to select the protocol to be used for each connection.
Typically you need to configure very little on connectors other than set
the listening port (see link:#jetty-connectors-network-settings[Network
Settings]), and perhaps enable `X-Forwarded-For` customization (see
link:#jetty-connectors-http-configuration[HTTP Configuration]). Most
other settings are for expert configuration only.
Typically you need to configure very little on connectors other than set the listening port (see link:#jetty-connectors-network-settings[Network Settings]), and perhaps enable `X-Forwarded-For` customization (see link:#jetty-connectors-http-configuration[HTTP Configuration]).
Most other settings are for expert configuration only.
==== Constructing a `ServerConnector`
The services a
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
instance uses are set by constructor injection and once instantiated
cannot be changed. Most of the services may be defaulted with null or 0
values so that a reasonable default is used, thus for most purposes only
the Server and the connection factories need to be passed to the
connector constructor. In Jetty XML (that is, in
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-http.xml[`jetty-http.xml`]),
you can do this with:
The services a link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] instance uses are set by constructor injection and once instantiated cannot be changed.
Most of the services may be defaulted with null or 0 values so that a reasonable default is used, thus for most purposes only the Server and the connection factories need to be passed to the connector constructor. In Jetty XML (that is, in link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-http.xml[`jetty-http.xml`]), you can do this by:
[source,xml]
----
@ -109,17 +67,14 @@ you can do this with:
</New>
----
You can see the other arguments that can be passed when constructing a
`ServerConnector` in the
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html#ServerConnector%28org.eclipse.jetty.server.Server,%20java.util.concurrent.Executor,%20org.eclipse.jetty.util.thread.Scheduler,%20org.eclipse.jetty.io.ByteBufferPool,%20int,%20int,%20org.eclipse.jetty.server.ConnectionFactory...%29[Javadoc].
You can see the other arguments that can be passed when constructing a `ServerConnector` in the link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html#ServerConnector%28org.eclipse.jetty.server.Server,%20java.util.concurrent.Executor,%20org.eclipse.jetty.util.thread.Scheduler,%20org.eclipse.jetty.io.ByteBufferPool,%20int,%20int,%20org.eclipse.jetty.server.ConnectionFactory...%29[Javadoc].
Typically the defaults are sufficient for almost all deployments.
[[jetty-connectors-network-settings]]
==== Network Settings.
You configure connector network settings by calling setters on the
connector before it is started. For example, you can set the port with
the Jetty XML:
You configure connector network settings by calling setters on the connector before it is started.
For example, you can set the port with the Jetty XML:
[source,xml]
----
@ -131,10 +86,8 @@ the Jetty XML:
</New>
----
Values in Jetty XML can also be parameterized so that they may be passed
from property files or set on the command line. Thus typically the port
is set within Jetty XML, but uses the `Property` element to be
customizable:
Values in Jetty XML can also be parameterized so that they may be passed from property files or set on the command line.
Thus typically the port is set within Jetty XML, but uses the `Property` element to be customizable:
[source,xml]
----
@ -146,70 +99,43 @@ customizable:
</New>
----
The network settings that you can set on the
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
include:
The network settings that you can set on the link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] include:
.Connector Configuration
[width="100%",cols="22%,78%",options="header",]
|=======================================================================
|Field |Description
|host |The network interface this connector binds to as an IP address or
a hostname. If null or 0.0.0.0, bind to all interfaces.
|host |The network interface this connector binds to as an IP address or a hostname.
If null or 0.0.0.0, bind to all interfaces.
|port |The configured port for the connector or 0 a random available
port may be used (selected port available via `getLocalPort()`).
|port |The configured port for the connector or 0 a random available port may be used (selected port available via `getLocalPort()`).
|idleTimeout |The time in milliseconds that the connection can be idle
before it is closed.
|idleTimeout |The time in milliseconds that the connection can be idle before it is closed.
|defaultProtocol |The name of the default protocol used to select a
`ConnectionFactory` instance. This defaults to the first
`ConnectionFactory` added to the connector.
|defaultProtocol |The name of the default protocol used to select a `ConnectionFactory` instance. This defaults to the first `ConnectionFactory` added to the connector.
|stopTimeout |The time in milliseconds to wait before gently stopping a
connector.
|stopTimeout |The time in milliseconds to wait before gently stopping a connector.
|acceptQueueSize |The size of the pending connection backlog. The exact
interpretation is JVM and operating system specific and you can ignore
it. Higher values allow more connections to wait pending an acceptor
thread. Because the exact interpretation is deployment dependent, it is
best to keep this value as the default unless there is a specific
connection issue for a specific OS that you need to address.
|acceptQueueSize |The size of the pending connection backlog.
The exact interpretation is JVM and operating system specific and you can ignore it.
Higher values allow more connections to wait pending an acceptor thread.
Because the exact interpretation is deployment dependent, it is best to keep this value as the default unless there is a specific connection issue for a specific OS that you need to address.
|reuseAddress |Allow the server socket to be rebound even if in
http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html[TIME_WAIT]. For
servers it is typically OK to leave this as the default true.
|reuseAddress |Allow the server socket to be rebound even if in http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html[TIME_WAIT].
For servers it is typically OK to leave this as the default true.
|soLingerTime |A value >=0 set the socket
http://stackoverflow.com/questions/3757289/tcp-option-so-linger-zero-when-its-required[SO_LINGER]
value in milliseconds. Jetty attempts to gently close all TCP/IP
connections with proper half close semantics, so a linger timeout should
not be required and thus the default is -1.
|soLingerTime |A value greater than zero sets the socket http://stackoverflow.com/questions/3757289/tcp-option-so-linger-zero-when-its-required[SO_LINGER] value in milliseconds.
Jetty attempts to gently close all TCP/IP connections with proper half close semantics, so a linger timeout should not be required and thus the default is -1.
|=======================================================================
[[jetty-connectors-http-configuration]]
==== HTTP Configuration
The
link:{JDURL}/org/eclipse/jetty/server/HttpConfiguration.html[HttpConfiguration]
class holds the configuration for
link:{JDURL}/org/eclipse/jetty/server/HttpChannel.html[`HTTPChannel`]s,
which you can create 1:1 with each HTTP connection or 1:n on a
multiplexed HTTP/2 connection. Thus a `HTTPConfiguration` object is
injected into both the HTTP and HTTP/2 connection factories. To avoid
duplicate configuration, the standard Jetty distribution creates the
common `HttpConfiguration` instance in
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty.xml[`jetty.xml`],
which is a `Ref` element then used in
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-http.xml[`jetty-http.xml`],
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-https.xml[`jetty-https.xml`]
and in
link:{SRCDIR}/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml[`jetty-http2.xml`]
The link:{JDURL}/org/eclipse/jetty/server/HttpConfiguration.html[HttpConfiguration] class holds the configuration for link:{JDURL}/org/eclipse/jetty/server/HttpChannel.html[`HTTPChannel`]s, which you can create 1:1 with each HTTP connection or 1:n on a multiplexed HTTP/2 connection.
Thus a `HTTPConfiguration` object is injected into both the HTTP and HTTP/2 connection factories.
To avoid duplicate configuration, the standard Jetty distribution creates the common `HttpConfiguration` instance in link:{SRCDIR}/jetty-server/src/main/config/etc/jetty.xml[`jetty.xml`], which is a `Ref` element then used in link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-http.xml[`jetty-http.xml`], link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-https.xml[`jetty-https.xml`] and in link:{SRCDIR}/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml[`jetty-http2.xml`].
A typical configuration of
link:{JDURL}/org/eclipse/jetty/server/HttpConfiguration.html[HttpConfiguration]
is:
A typical configuration of link:{JDURL}/org/eclipse/jetty/server/HttpConfiguration.html[HttpConfiguration] is:
[source,xml]
----
@ -222,8 +148,7 @@ is:
</New>
----
This example HttpConfiguration may be used by reference to the ID
"httpConfig":
This example HttpConfiguration may be used by reference to the ID "`httpConfig`":
[source,xml]
----
@ -246,9 +171,7 @@ This example HttpConfiguration may be used by reference to the ID
</Call>
----
For SSL based connectors (in `jetty-https.xml` and `jetty-http2.xml`),
the common "httpConfig" instance is used as the basis to create an SSL
specific configuration with ID "sslHttpConfig":
For SSL based connectors (in `jetty-https.xml` and `jetty-http2.xml`), the common "`httpConfig`" instance is used as the basis to create an SSL specific configuration with ID "`sslHttpConfig`":
[source,xml]
----
@ -260,38 +183,22 @@ specific configuration with ID "sslHttpConfig":
</New>
----
This adds a `SecureRequestCustomizer` which adds SSL Session IDs and
certificate information as request attributes.
This adds a `SecureRequestCustomizer` which adds SSL Session IDs and certificate information as request attributes.
==== SSL Context Configuration
The SSL/TLS connectors for HTTPS and HTTP/2 require a certificate to
establish a secure connection. Jetty holds certificates in standard JVM
keystores and are configured as keystore and truststores on a
link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[`SslContextFactory`]
instance that is injected into an
link:{JDURL}/org/eclipse/jetty/server/SslConnectionFactory.html[`SslConnectionFactory`]
instance. An example using the keystore distributed with Jetty
(containing a self signed test certificate) is in
link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-https.xml[`jetty-https.xml`].
The SSL/TLS connectors for HTTPS and HTTP/2 require a certificate to establish a secure connection.
Jetty holds certificates in standard JVM keystores and are configured as keystore and truststores on a link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[`SslContextFactory`] instance that is injected into an link:{JDURL}/org/eclipse/jetty/server/SslConnectionFactory.html[`SslConnectionFactory`] instance.
An example using the keystore distributed with Jetty (containing a self signed test certificate) is in link:{SRCDIR}/jetty-server/src/main/config/etc/jetty-https.xml[`jetty-https.xml`].
Read more about SSL keystores in link:#configuring-ssl[Configuring SSL].
==== Proxy / Load Balancer Connection Configuration
Often a Connector needs to be configured to accept connections from an
intermediary such as a Reverse Proxy and/or Load Balancer deployed in
front of the server. In such environments, the TCP/IP connection
terminating on the server does not originate from the client, but from
the intermediary, so that the Remote IP and port number can be reported
incorrectly in logs and in some circumstances the incorrect server
address and port may be used.
Often a Connector needs to be configured to accept connections from an intermediary such as a Reverse Proxy and/or Load Balancer deployed in front of the server.
In such environments, the TCP/IP connection terminating on the server does not originate from the client, but from the intermediary, so that the Remote IP and port number can be reported incorrectly in logs and in some circumstances the incorrect server address and port may be used.
Thus Intermediaries typically implement one of several de facto
standards to communicate to the server information about the orginal
client connection terminating on the intermediary. Jetty supports the
`X-Forwarded-For` header and the
http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt[Proxy
Protocol] mechanisms as described below.
Thus Intermediaries typically implement one of several de facto standards to communicate to the server information about the orginal client connection terminating on the intermediary.
Jetty supports the `X-Forwarded-For` header and the http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt[Proxy Protocol] mechanisms as described below.
____
[NOTE]
@ -302,12 +209,8 @@ ____
===== X-Forward-for Configuration
The `X-Forwarded-for` header and associated headers are a defacto
standard where intermediaries add HTTP headers to each request they
forward to describe the originating connection. These headers can be
interpreted by an instance of
link:{JDURL}/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[`ForwardedRequestCustomizer`]
which can be added to a HttpConfiguration as follows:
The `X-Forwarded-for` header and associated headers are a de facto standard where intermediaries add HTTP headers to each request they forward to describe the originating connection.
These headers can be interpreted by an instance of link:{JDURL}/org/eclipse/jetty/server/ForwardedRequestCustomizer.html[`ForwardedRequestCustomizer`] which can be added to a `HttpConfiguration` as follows:
[source,xml]
----
@ -324,20 +227,12 @@ which can be added to a HttpConfiguration as follows:
===== Proxy Protocol
The http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt[Proxy
Protocol] is a defacto standard created by HAProxy and used by
environments such as Amazon Elastic Cloud. This mechanism is independent
of any protocol, so it can be used for HTTP2, TLS etc. The information
about the client connection is sent as a small data frame on each newly
established connection. In Jetty, this protocol can be handled by the
link:{JDURL}/org/eclipse/jetty/server/ProxyConnectionFactory.html[`ProxyConnectionFactory`]
which parses the data frame and then instantiates the next
ConnectionFactory on the connection with and EndPoint that has been
customized with the data obtained about the orginal client connection.
The connection factory can be added to any
link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`]
and should be the first
link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactory`].
The http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt[Proxy Protocol] is a de facto standard created by HAProxy and used by environments such as Amazon Elastic Cloud.
This mechanism is independent of any protocol, so it can be used for HTTP2, TLS etc.
The information about the client connection is sent as a small data frame on each newly established connection.
In Jetty, this protocol can be handled by the link:{JDURL}/org/eclipse/jetty/server/ProxyConnectionFactory.html[`ProxyConnectionFactory`] which parses the data frame and then instantiates the next `ConnectionFactory` on the connection with an end point that has been customized with the data obtained about the original client connection.
The connection factory can be added to any link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[`ServerConnector`] and should be the first link:{JDURL}/org/eclipse/jetty/server/ConnectionFactory.html[`ConnectionFactory`].
An example of adding the factory to a HTTP connector is:
[source,xml]

View File

@ -17,60 +17,43 @@
[[configuring-ssl]]
=== Configuring SSL/TLS
This document provides an overview of how to configure SSL and TLS for
Jetty.
This document provides an overview of how to configure SSL and TLS for Jetty.
[[tls-and-ssl-versions]]
==== TLS and SSL versions
Which browser/OS supports which protocols can be
https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers[found
on Wikipedia]
Which browser/OS supports which protocols can be https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers[found on Wikipedia].
* TLS v1.1 and v1.2: The protocols which should be used wherever
possible. All CBC based ciphers are supported since Java 7, the new GCM
modes are supported since Java 8.
* TLS v1.0: still OK but affected by the POODLE attack too. To support
older browsers this protocol version is still needed.
* SSL v3: is now deprecated and should only be enabled if you still need
to support very old browsers like Internet Explorer 6 on Windows XP
which does not support TLS 1.0 (or is disabled by default).
* TLS v1.1 and v1.2: The protocols which should be used wherever possible.
All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8.
* TLS v1.0: still supported but is affected by the POODLE attack.
To support older browsers this protocol version is still needed.
* SSL v3: is now deprecated and should only be enabled if you still need to support very old browsers like Internet Explorer 6 on Windows XP which does not support TLS 1.0 (or is disabled by default).
[[understanding-certificates-and-keys]]
==== Understanding Certificates and Keys
Configuring SSL can be a confusing experience of keys, certificates,
protocols and formats, thus it helps to have a reasonable understanding
of the basics. The following links provide some good starting points:
Configuring SSL can be a confusing experience of keys, certificates, protocols and formats, thus it helps to have a reasonable understanding of the basics.
The following links provide some good starting points:
* Certificates:
** http://en.tldp.org/HOWTO/SSL-Certificates-HOWTO/index.html[SSL
Certificates HOWTO]
** http://mindprod.com/jgloss/certificate.html[Mindprod Java Glossary:
Certificates]
** http://en.tldp.org/HOWTO/SSL-Certificates-HOWTO/index.html[SSL Certificates HOWTO]
** http://mindprod.com/jgloss/certificate.html[Mindprod Java Glossary: Certificates]
* Keytool:
** http://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html[Keytool
for Unix]
** http://docs.oracle.com/javase/8/docs/technotes/tools/windows/keytool.html[Keytool
for Windows]
** http://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html[Keytool for Unix]
** http://docs.oracle.com/javase/8/docs/technotes/tools/windows/keytool.html[Keytool for Windows]
* Other tools:
** https://www.ibm.com/developerworks/mydeveloperworks/groups/service/html/communityview?communityUuid=6fb00498-f6ea-4f65-bf0c-adc5bd0c5fcc[IBM
Keyman]
** https://www.ibm.com/developerworks/mydeveloperworks/groups/service/html/communityview?communityUuid=6fb00498-f6ea-4f65-bf0c-adc5bd0c5fcc[IBM Keyman]
* OpenSSL:
** http://www.openssl.org/support/faq.html[OpenSSL FAQ]
[[openssl-vs-keytool]]
===== OpenSSL vs. Keytool
For testing, the `keytool` utility bundled with the JDK provides the
simplest way to generate the key and certificate you need.
For testing, the `keytool` utility bundled with the JDK provides the simplest way to generate the key and certificate you need.
You can also use the OpenSSL tools to generate keys and certificates, or
to convert those that you have used with Apache or other servers. Since
Apache and other servers commonly use the OpenSSL tool suite to generate
and manipulate keys and certificates, you might already have some keys
and certificates created by OpenSSL, or you might also prefer the
formats OpenSSL produces.
You can also use the OpenSSL tools to generate keys and certificates, or to convert those that you have used with Apache or other servers.
Since Apache and other servers commonly use the OpenSSL tool suite to generate and manipulate keys and certificates, you might already have some keys and certificates created by OpenSSL, or you might also prefer the formats OpenSSL produces.
If you want the option of using the same certificate with Jetty or a web
server such as Apache not written in Java, you might prefer to generate
@ -79,8 +62,7 @@ your private key and certificate with OpenSSL.
[[configuring-jetty-for-ssl]]
===== Configuring Jetty for SSL
To configure Jetty for SSL, complete the tasks in the following
sections:
To configure Jetty for SSL, complete the tasks in the following sections:
* xref:generating-key-pairs-and-certificates[]
* xref:requesting-trusted-certificate[]
@ -90,33 +72,28 @@ sections:
[[generating-key-pairs-and-certificates]]
===== Generating Key Pairs and Certificates
The simplest way to generate keys and certificates is to use the
`keytool` application that comes with the JDK, as it generates keys and
certificates directly into the keystore. See
xref:generating-key-pairs-and-certificates-JDK-keytool[].
The simplest way to generate keys and certificates is to use the `keytool` application that comes with the JDK, as it generates keys and certificates directly into the keystore.
See xref:generating-key-pairs-and-certificates-JDK-keytool[].
If you already have keys and certificates, see
xref:loading-keys-and-certificates[] to load them into a
JSSE keystore. This section also applies if you have a renewal
certificate to replace one that is expiring.
If you already have keys and certificates, see xref:loading-keys-and-certificates[] to load them into a JSSE keystore.
This section also applies if you have a renewal certificate to replace one that is expiring.
The examples below generate only basic keys and certificates. You should
read the full manuals of the tools you are using if you want to specify:
The examples below generate only basic keys and certificates.
You should read the full manuals of the tools you are using if you want to specify:
* the key size
* the certificate expiration date
* alternate security providers
* The key size
* The certificate expiration date
* Alternate security providers
[[generating-key-pairs-and-certificates-JDK-keytool]]
====== Generating Keys and Certificates with JDK's keytool
The following command generates a key pair and certificate directly into
file `keystore`:
The following command generates a key pair and certificate directly into file `keystore`:
[source, screen]
....
----
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA
....
----
____
[NOTE]
@ -125,13 +102,12 @@ In a browser, it displays a message "Could not establish an encrypted connection
The solution is to use RSA for the key algorithm.
____
This command prompts for information about the certificate and for
passwords to protect both the keystore and the keys within it. The only
mandatory response is to provide the fully qualified host name of the
server at the "first and last name" prompt. For example:
This command prompts for information about the certificate and for passwords to protect both the keystore and the keys within it.
The only mandatory response is to provide the fully qualified host name of the server at the "first and last name" prompt.
For example:
[source, screen]
....
----
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA -sigalg SHA256withRSA
Enter keystore password: password
What is your first and last name?
@ -153,28 +129,21 @@ $ keytool -keystore keystore -alias jetty -genkey -keyalg RSA -sigalg SHA256with
Enter key password for <jetty>
(RETURN if same as keystore password):
$
....
----
You now have the minimal requirements to run an SSL connection and could
proceed directly to link:#configuring-sslcontextfactory[configure an SSL
connector]. However the browser will not trust the certificate you have
generated, and prompts the user to this effect. While what you have at
this point is often sufficient for testing, most public sites need a
trusted certificate, as shown in the section
link:#generating-csr-from-keytool[generating a CSR with keytool].
You now have the minimal requirements to run an SSL connection and could proceed directly to link:#configuring-sslcontextfactory[configure an SSL connector].
However, the browser will not trust the certificate you have generated, and prompts the user to this effect.
While what you have at this point is often sufficient for testing, most public sites need a trusted certificate, as shown in the section link:#generating-csr-from-keytool[generating a CSR with keytool].
If you want to use only a self signed certificate for some kind of
internal admin panel add -validity <days> to the keytool call above,
otherwise your certificate is only valid for one month.
If you want to use only a self signed certificate for some kind of internal admin panel add -validity <days> to the keytool call above, otherwise your certificate is only valid for one month.
If you are using java 8 or later, then you may also use the SAN
extension to set one or more names that the certificate applies to:
If you are using Java 8 or later, then you may also use the SAN extension to set one or more names that the certificate applies to:
[source, screen]
....
----
$ keytool -keystore keystore -alias jetty -genkey -keyalg RSA -sigalg SHA256withRSA -ext 'SAN=dns:jetty.eclipse.org,dns:*.jetty.org'
...
....
----
[[generating-keys-and-certificates-openssl]]
====== Generating Keys and Certificates with OpenSSL
@ -182,32 +151,27 @@ $ keytool -keystore keystore -alias jetty -genkey -keyalg RSA -sigalg SHA256with
The following command generates a key pair in the file `jetty.key`:
[source, screen]
....
----
$ openssl genrsa -aes128 -out jetty.key
....
----
You might also want to use the `-rand` file argument to provide an
arbitrary file that helps seed the random number generator.
You might also want to use the `-rand` file argument to provide an arbitrary file that helps seed the random number generator.
The following command generates a certificate for the key into the file
` jetty.crt`:
The following command generates a certificate for the key into the file `jetty.crt`:
[source, screen]
....
----
$ openssl req -new -x509 -newkey rsa:2048 -sha256 -key jetty.key -out jetty.crt
....
----
Adding -sha256 ensures to get a certificate with the now recommended
SHA-256 signature algorithm. For the paranoid ones add -b4096 to get a
4069bits long key.
Adding -sha256 ensures to get a certificate with the now recommended SHA-256 signature algorithm.
For the those with heightened security in mind, add -b4096 to get a 4069 bit key.
The next command prompts for information about the certificate and for
passwords to protect both the keystore and the keys within it. The only
mandatory response is to provide the fully qualified host name of the
server at the "Common Name" prompt. For example:
The next command prompts for information about the certificate and for passwords to protect both the keystore and the keys within it.
The only mandatory response is to provide the fully qualified host name of the server at the "Common Name" prompt. For example:
[source, screen]
....
----
$ openssl genrsa -aes128 -out jetty.key
Generating RSA private key, 2048 bit long modulus
..............+++
@ -218,13 +182,12 @@ Verifying - Enter pass phrase for jetty.key:
$ openssl req -new -x509 -newkey rsa:2048 -sha256 -key jetty.key -out jetty.crt
Enter pass phrase for jetty.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
There are quite a few fields but you can leave some blank.
For some fields there will be a default value.
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
@ -234,89 +197,68 @@ Common Name (e.g. server FQDN or YOUR name) []:jetty.eclipse.org
Email Address []:
$
....
----
You now have the minimal requirements to run an SSL connection and could
proceed directly to xref:loading-keys-and-certificates[]
to load these keys and certificates into a JSSE keystore. However the
browser will not trust the certificate you have generated, and prompts
the user to this effect. While what you have at this point is often
sufficient for testing, most public sites need a trusted certificate, as
shown in the section, xref:generating-csr-from-openssl[]
to obtain a certificate.
You now have the minimal requirements to run an SSL connection and could proceed directly to xref:loading-keys-and-certificates[] to load these keys and certificates into a JSSE keystore.
However the browser will not trust the certificate you have generated, and prompts the user to this effect.
While what you have at this point is often sufficient for testing, most public sites need a trusted certificate, as shown in the section, xref:generating-csr-from-openssl[] to obtain a certificate.
[[using-keys-and-certificates-from-other-sources]]
====== Using Keys and Certificates from Other Sources
If you have keys and certificates from other sources, you can proceed
directly to xref:loading-keys-and-certificates[].
If you have keys and certificates from other sources, you can proceed directly to xref:loading-keys-and-certificates[].
[[requesting-trusted-certificate]]
===== Requesting a Trusted Certificate
The keys and certificates generated with JDK's `keytool` and OpenSSL are
sufficient to run an SSL connector. However the browser will not trust
the certificate you have generated, and it will prompt the user to this
effect.
The keys and certificates generated with JDK's `keytool` and OpenSSL are sufficient to run an SSL connector.
However the browser will not trust the certificate you have generated, and it will prompt the user to this effect.
To obtain a certificate that most common browsers will trust, you need
to request a well-known certificate authority (CA) to sign your
key/certificate. Such trusted CAs include: AddTrust, Entrust, GeoTrust,
RSA Data Security, Thawte, VISA, ValiCert, Verisign, and beTRUSTed,
among others. Each CA has its own instructions (look for JSSE or OpenSSL
sections), but all involve a step that generates a certificate signing
request (CSR).
To obtain a certificate that most common browsers will trust, you need to request a well-known certificate authority (CA) to sign your key/certificate.
Such trusted CAs include: AddTrust, Entrust, GeoTrust, RSA Data Security, Thawte, VISA, ValiCert, Verisign, and beTRUSTed, among others.
Each CA has its own instructions (look for JSSE or OpenSSL sections), but all involve a step that generates a certificate signing request (CSR).
[[generating-csr-from-keytool]]
====== Generating a CSR with keytool
The following command generates the file `jetty.csr` using `keytool` for
a key/cert already in the keystore:
The following command generates the file `jetty.csr` using `keytool` for a key/cert already in the keystore:
[source, screen]
....
----
$ keytool -certreq -alias jetty -keystore keystore -file jetty.csr
....
----
[[generating-csr-from-openssl]]
====== Generating a CSR from OpenSSL
The following command generates the file `jetty.csr` using OpenSSL for a
key in the file `jetty.key`:
The following command generates the file `jetty.csr` using OpenSSL for a key in the file `jetty.key`:
[source, screen]
....
----
$ openssl req -new -key jetty.key -out jetty.csr
....
----
Notice that this command uses only the existing key from `jetty.key`
file, and not a certificate in `jetty.crt` as generated with OpenSSL.
Notice that this command uses only the existing key from `jetty.key` file, and not a certificate in `jetty.crt` as generated with OpenSSL.
You need to enter the details for the certificate again.
[[loading-keys-and-certificates]]
===== Loading Keys and Certificates
Once a CA has sent you a certificate, or if you generated your own
certificate without `keytool`, you need to load it into a JSSE keystore.
Once a CA has sent you a certificate, or if you generated your own certificate without `keytool`, you need to load it into a JSSE keystore.
____
[NOTE]
You need both the private key and the certificate in the JSSE keystore.
You should load the certificate into the keystore used to generate the
CSR with `keytool`. If your key pair is not already in a keystore (for
example, because it has been generated with OpenSSL), you need to use
the PKCS12 format to load both key and certificate (see
link:#loading-keys-and-certificates-via-pkcks12[PKCKS12 Keys &
Certificates]).
You should load the certificate into the keystore used to generate the CSR with `keytool`.
If your key pair is not already in a keystore (for example, because it has been generated with OpenSSL), you need to use the PKCS12 format to load both key and certificate (see link:#loading-keys-and-certificates-via-pkcks12[PKCKS12 Keys &Certificates]).
____
[[loading-certificates-with-keytool]]
====== Loading Certificates with keytool
You can use `keytool` to load a certificate in PEM form directly into a
keystore. The PEM format is a text encoding of certificates; it is
produced by OpenSSL, and is returned by some CAs. An example PEM file
is:
You can use `keytool` to load a certificate in PEM form directly into a keystore.
The PEM format is a text encoding of certificates; it is produced by OpenSSL, and is returned by some CAs.
An example PEM file is:
....
jetty.crt
@ -337,159 +279,118 @@ Rcz6oCRvCGCe5kDB
-----END CERTIFICATE-----
....
The following command loads a PEM encoded certificate in the `jetty.crt`
file into a JSSE keystore:
The following command loads a PEM encoded certificate in the `jetty.crt` file into a JSSE keystore:
[source, screen]
....
----
$ keytool -keystore keystore -import -alias jetty -file jetty.crt -trustcacerts
....
----
If the certificate you receive from the CA is not in a format that
`keytool` understands, you can use the `openssl` command to convert
formats:
If the certificate you receive from the CA is not in a format that `keytool` understands, you can use the `openssl` command to convert formats:
[source, screen]
....
----
$ openssl x509 -in jetty.der -inform DER -outform PEM -out jetty.crt
....
----
[[loading-keys-and-certificates-via-pkcks12]]
====== Loading Keys and Certificates via PKCS12
If you have a key and certificate in separate files, you need to combine
them into a PKCS12 format file to load into a new keystore. The
certificate can be one you generated yourself or one returned from a CA
in response to your CSR.
If you have a key and certificate in separate files, you need to combine them into a PKCS12 format file to load into a new keystore.
The certificate can be one you generated yourself or one returned from a CA in response to your CSR.
The following OpenSSL command combines the keys in `jetty.key` and the
certificate in the `jetty.crt` file into the `jetty.pkcs12` file:
The following OpenSSL command combines the keys in `jetty.key` and the certificate in the `jetty.crt` file into the `jetty.pkcs12` file:
[source, screen]
....
----
$ openssl pkcs12 -inkey jetty.key -in jetty.crt -export -out jetty.pkcs12
....
----
If you have a chain of certificates, because your CA is an intermediary,
build the PKCS12 file as follows:
If you have a chain of certificates, because your CA is an intermediary, build the PKCS12 file as follows:
[source, screen]
....
----
$ cat example.crt intermediate.crt [intermediate2.crt] ... rootCA.crt > cert-chain.txt
$ openssl pkcs12 -export -inkey example.key -in cert-chain.txt -out example.pkcs12
....
----
The order of certificates must be from server to rootCA, as per RFC2246
section 7.4.2.
The order of certificates must be from server to rootCA, as per RFC2246 section 7.4.2.
OpenSSL asks for an __export password__. A non-empty password is
required to make the next step work. Then load the resulting PKCS12 file
into a JSSE keystore with `keytool`:
OpenSSL asks for an __export password__.
A non-empty password is required to make the next step work.
Then load the resulting PKCS12 file into a JSSE keystore with `keytool`:
[source, screen]
....
----
$ keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destkeystore keystore
....
----
[[renewing-certificates]]
===== Renewing Certificates
If you are updating your configuration to use a newer certificate, as
when the old one is expiring, just load the newer certificate as
described in the section,
xref:loading-keys-and-certificates[]. If you imported the
key and certificate originally using the PKCS12 method, use an alias of
"1" rather than "jetty", because that is the alias the PKCS12 process
enters into the keystore.
If you are updating your configuration to use a newer certificate, as when the old one is expiring, just load the newer certificate as described in the section, xref:loading-keys-and-certificates[].
If you imported the key and certificate originally using the PKCS12 method, use an alias of "1" rather than "jetty", because that is the alias the PKCS12 process enters into the keystore.
[[configuring-sslcontextfactory]]
==== Configuring the Jetty SslContextFactory
==== Configuring the Jetty `SslContextFactory`
The generated SSL certificates from above are held in the key store are
configured in an instance of
link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[SslContextFactory]
object.
The generated SSL certificates from above are held in the key store are configured in an instance of link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html[SslContextFactory] object.
The SslContextFactory is responsible for:
The `SslContextFactory` is responsible for:
* Creating the Java `SslEngine` used by Jetty's Connectors and Jetty's
Clients (HTTP/1, HTTP/2, and WebSocket).
* Creating the Java `SslEngine` used by Jetty's Connectors and Jetty's Clients (HTTP/1, HTTP/2, and WebSocket).
* Managing Keystore Access
* Managing Truststore Access
* Managing Protocol selection via Excludes / Includes list
* Managing Cipher Suite selection via Excludes / Includes list
* Managing order of Ciphers offered (important for TLS/1.2 and HTTP/2
support)
* Managing order of Ciphers offered (important for TLS/1.2 and HTTP/2 support)
* SSL Session Caching options
* Certificate https://en.wikipedia.org/wiki/Revocation_list[Revocation
Lists] and Distribution Points (CRLDP)
* https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol[OCSP]
Support
* Certificate https://en.wikipedia.org/wiki/Revocation_list[Revocation Lists] and Distribution Points (CRLDP)
* https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol[OCSP] Support
* Client Authentication Support
For Jetty Connectors, the configured `SslContextFactory` is injected
into a specific `ServerConnector` `SslConnectionFactory`.
For Jetty Connectors, the configured `SslContextFactory` is injected into a specific `ServerConnector` `SslConnectionFactory`.
For Jetty Clients, the various constructors support using a configured
`SslContextFactory`.
For Jetty Clients, the various constructors support using a configured `SslContextFactory`.
While the SslContextFactory can operate without a keystore (this mode is
most suitable for the various Jetty Clients) it is best if you at least
configure the Keystore you are using.
While the `SslContextFactory` can operate without a keystore (this mode is most suitable for the various Jetty Clients) it is best if you at least configure the keystore you are using.
setKeyStorePath::
The configured keystore to use for all SSL/TLS in configured Jetty
Connector (or Client).
+
The configured keystore to use for all SSL/TLS in configured Jetty Connector (or Client).
____
[NOTE]
as a keystore is vital security information, it can be desirable to locate the file in a directory with very restricted access.
As a keystore is vital security information, it can be desirable to locate the file in a directory with very restricted access.
____
setKeyStorePassword::
The keystore password may be set here in plain text, or as some
protection from casual observation, it may be obfuscated using the
link:{JDURL}/org/eclipse/jetty/util/security/Password.html[Password]
class.
The keystore password may be set here in plain text, or as some protection from casual observation, it may be obfuscated using the link:{JDURL}/org/eclipse/jetty/util/security/Password.html[Password] class.
setTrustStorePath::
This is used if validating client certificates and is typically set to
the same path as the keystore.
This is used if validating client certificates and is typically set to the same path as the keystore.
setKeyManagerPassword::
is a password that is passed to the `KeyManagerFactory.init(...)`. If
there is no keymanagerpassword, then the keystorepassword is used
instead. If there is no trustmanager set, then the keystore is used as
the trust store and the keystorepassword is used as the truststore
password
Password that is passed to the `KeyManagerFactory.init(...)`.
If there is no `keymanagerpassword`, then the `keystorepassword` is used instead.
If there is no `trustmanager` set, then the keystore is used as the trust store and the `keystorepassword` is used as the truststore password.
setExcludeCipherSuites / setIncludeCipherSuites::
This allows for the customization of the selected Cipher Suites that
will be used by SSL/TLS
This allows for the customization of the selected Cipher Suites that will be used by SSL/TLS.
setExcludeProtocols / setIncludeProtocols::
This allows for the customization of the selected Protocols that will
be used by SSL/TLS
This allows for the customization of the selected Protocols that will be used by SSL/TLS.
____
[NOTE]
When working with Includes / Excludes, it is important to know that Excludes will always win.
+
The selection process is to process the JVM list of available Cipher Suites or Protocols against the include list, then remove the excluded ones.
+
Be aware that each Include / Exclude list has a Set method (replace the
list) or Add method (append the list)
Be aware that each Include / Exclude list has a Set method (replace the list) or Add method (append the list).
____
____
[CAUTION]
The key and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` `org.eclipse.jetty.ssl.password`.
+
This is _not_ a recommended usage.
____
==== Configuring SSL in Jetty Distribution
For those of you using the Jetty Distribution, the provided modules for
https and http2 will automatically setup the SslContextFactory, the
appropriate SslConnectionFactory, and associated ServerConnectors for
you, in the correct order.
For those of you using the Jetty Distribution, the provided modules for https and http2 will automatically setup the `SslContextFactory`, the appropriate `SslConnectionFactory`, and associated `ServerConnectors` for you in the correct order.
An example of this setup:
@ -507,53 +408,36 @@ $ ls -l etc
-rw-rw-r--. 1 user group 3697 Feb 2 11:47 keystore
----
When you check your start.ini, you'll see many commented properties
ready for you to configure the SslContextFactory basics.
When you check the `start.ini`, you'll see many commented properties ready for you to configure the `SslContextFactory` basics.
To highlight some of the more commonly used properties:
jetty.ssl.host::
Configures which interfaces the SSL/TLS Connector should listen on
Configures which interfaces the SSL/TLS Connector should listen on.
jetty.ssl.port::
Configures which port the SSL/TLS Connector should listen on
Configures which port the SSL/TLS Connector should listen on.
jetty.httpConfig.securePort::
If a webapp needs to redirect to a secure version of the same
resource, then this is the port reported back on the Response
`Location` line (Having this be separate is useful if you have
something sitting in front of Jetty, such as a Load Balancer or proxy)
If a webapp needs to redirect to a secure version of the same resource, then this is the port reported back on the response `location` line (having this be separate is useful if you have something sitting in front of Jetty, such as a Load Balancer or proxy).
jetty.sslContext.keyStorePath::
Sets the location of the `keystore` that you configured with your
certificates
Sets the location of the `keystore` that you configured with your certificates.
jetty.sslContext.keyStorePassword::
Sets the Password for the `keystore`
Sets the Password for the `keystore`.
==== Configuring SNI
From java8, the JVM contains support for the
http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name
Indicator (SNI)] extension, which allows a SSL connection handshake to
indicate one or more DNS names that it applies to. To support this, the
ExtendedSslContextFactory is used that will look for multiple X509
certificates within the keystore, each of which may have multiple DNS
names (including wildcards) associated with the
http://en.wikipedia.org/wiki/SubjectAltName[Subject Alternate Name]
extension. When using the ExtendedSSlContextFactory, the correct
certificate is automatically selected if the SNI extension is present in
the handshake.
From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows a SSL connection handshake to indicate one or more DNS names that it applies to.
To support this, the `ExtendedSslContextFactory` is used that will look for multiple X509 certificates within the keystore, each of which may have multiple DNS names (including wildcards) associated with the http://en.wikipedia.org/wiki/SubjectAltName[Subject Alternate Name] extension.
When using the `ExtendedSSlContextFactory`, the correct certificate is automatically selected if the SNI extension is present in the handshake.
[[configuring-sslcontextfactory-cipherSuites]]
==== Disabling/Enabling Specific Cipher Suites
For example to avoid the BEAST attack it is necessary to configure a
specific set of cipher suites. This can either be done via
link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html#setIncludeCipherSuites(java.lang.String...)[SslContext.setIncludeCipherSuites(java.lang.String...)]
or
vialink:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html#setExcludeCipherSuites(java.lang.String...)[SslContext.setExcludeCipherSuites(java.lang.String...)].
For example to avoid the BEAST attack it is necessary to configure a specific set of cipher suites. This can either be done via link:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html#setIncludeCipherSuites(java.lang.String...)[SslContext.setIncludeCipherSuites(java.lang.String...)] or vialink:{JDURL}/org/eclipse/jetty/util/ssl/SslContextFactory.html#setExcludeCipherSuites(java.lang.String...)[SslContext.setExcludeCipherSuites(java.lang.String...)].
____
[NOTE]
It's crucial that you use the exact names of the cipher suites as used/known by the JDK.
You can get them by obtaining an instance of SSLEngine and call getSupportedCipherSuites().
You can get them by obtaining an instance of SSLEngine and call `getSupportedCipherSuites()`.
Tools like ssllabs.com might report slightly different names which will be ignored.
____
@ -561,19 +445,14 @@ ____
[NOTE]
It's recommended to install the Java Cryptography Extension (JCE) Unlimited Strength policy files in your JRE to get full strength ciphers like AES-256.
They can be found on the http://www.oracle.com/technetwork/java/javase/downloads/index.html[Java download page].
Just overwrite the two present JAR files in `<JRE_HOME>/lib/security/`
Just overwrite the two present JAR files in `<JRE_HOME>/lib/security/`.
____
Both setIncludeCipherSuites and setExcludeCipherSuites can be feed by
the exact cipher suite name used in the JDK or by using regular
expressions.
Both `setIncludeCipherSuites` and `setExcludeCipherSuites` can be fed by the exact cipher suite name used in the JDK or by using regular expressions.
If you have a need to adjust the Includes or Excludes, then this is best
done with a custom blow-in XML that configures the SslContextFactory to
suit your needs.
If you have a need to adjust the Includes or Excludes, then this is best done with a custom blow-in XML that configures the `SslContextFactory` to suit your needs.
To do this, first create a new `${jetty.base}/etc/tweak-ssl.xml` (this
can be any name, just avoid prefixing it with "jetty-")
To do this, first create a new `${jetty.base}/etc/tweak-ssl.xml` (thiscan be any name, just avoid prefixing it with "jetty-").
[source,xml]
----
@ -594,14 +473,10 @@ can be any name, just avoid prefixing it with "jetty-")
</Configure>
----
This new XML will configure the id `sslContextFactory` some more (this
id is first created by the `ssl` module and its associated
`${jetty.home}/etc/jetty-ssl-context.xml`). You can do anything you want
with the `SslContextFactory` in use by the Jetty Distribution from this
tweak XML.
This new XML will configure the id `sslContextFactory` some more (this id is first created by the `ssl` module and its associated `${jetty.home}/etc/jetty-ssl-context.xml`).
You can do anything you want with the `SslContextFactory` in use by the Jetty Distribution from this tweaked XML.
To make sure that your `${jetty.base}` uses this new XML, add it to the
end of your `${jetty.base}/start.ini`
To make sure that your `${jetty.base}` uses this new XML, add it to the end of your `${jetty.base}/start.ini`
[source,plain]
----
@ -618,24 +493,19 @@ $
____
[NOTE]
The default SslContextFactory implementation applies the latest SSL/TLS recommendations surrounding vulnerabilities in SSL/TLS.
The default `SslContextFactory` implementation applies the latest SSL/TLS recommendations surrounding vulnerabilities in SSL/TLS.
Check the release notes (The `VERSION.txt` found in the root of the Jetty Distribution, or the http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.eclipse.jetty%22%20AND%20a%3A%22jetty-project%22[alternate (classified 'version') artifacts for the `jetty-project` component]on Maven Central) for updates.
+
The Java JVM is also applying exclusions at the JVM level, and as such, if you have a need to enable something that is generally accepted by the industry as being insecure or vulnerable you will likely have to enable it in BOTH the Java JVM and the Jetty configuration.
____
____
[TIP]
You can enable the `org.eclipse.jetty.util.ssl` named logger at DEBUG
level to see what the list of selected Protocols and Cipher suites are
at startup of Jetty.
You can enable the `org.eclipse.jetty.util.ssl` named logger at DEBUG level to see what the list of selected Protocols and Cipher suites are at startup of Jetty.
____
Some other Include / Exclude examples:
Example: Include all ciphers which support
https://en.wikipedia.org/wiki/Forward_secrecy[Forward Secrecy] using
regex:
Example: Include all ciphers which support https://en.wikipedia.org/wiki/Forward_secrecy[Forward Secrecy] using regex:
[source,xml]
----
@ -649,7 +519,7 @@ regex:
</Set>
----
Example: Exclude all old, insecure or anonymous cipher suites:
*Example*: Exclude all old, insecure or anonymous cipher suites:
[source,xml]
----
@ -667,7 +537,7 @@ Example: Exclude all old, insecure or anonymous cipher suites:
</Call>
----
Example: Since 2014 SSLv3 is considered insecure and should be disabled.
*Example*: Since 2014 SSLv3 is considered insecure and should be disabled.
[source,xml]
----
@ -689,7 +559,7 @@ ____
Note that disabling SSLv3 prevents very old browsers like Internet Explorer 6 on Windows XP from connecting.
____
Example: TLS renegotiation could be disabled too to prevent an attack based on this feature.
*Example*: TLS renegotiation could be disabled too to prevent an attack based on this feature.
[source,xml]
----

View File

@ -17,87 +17,61 @@
[[setting-port80-access]]
=== Setting Port 80 Access for a Non-Root User
On Unix-based systems, port 80 is protected; typically only the
superuser root can open it. For security reasons, it is not desirable to
run the server as root. This page presents several options to access
port 80 as a non-root user, including using ipchains, iptables, Jetty's
SetUID feature, xinetd, and the Solaris 10 User Rights Management
Framework.
On Unix-based systems, port 80 is protected; typically only the superuser root can open it. For security reasons, it is not desirable to run the server as root.
This page presents several options to access port 80 as a non-root user, including using ipchains, iptables, Jetty's SetUID feature, xinetd, and the Solaris 10 User Rights Management Framework.
[[using-ipchains]]
==== Using ipchains
On some Linux systems you can use the _ipchains REDIRECT_ mechanism to
redirect from one port to another inside the kernel (if ipchains is not
available, then usually iptables is):
On some Linux systems you can use the _ipchains REDIRECT_ mechanism to redirect from one port to another inside the kernel (if ipchains is not available, then usually iptables is):
[source, screen]
....
----
# /sbin/ipchains -I input --proto TCP --dport 80 -j REDIRECT 8080
....
----
This command instructs the system as follows: "Insert into the kernel's
packet filtering the following as the first rule to check on incoming
packets: if the protocol is TCP and the destination port is 80, redirect
the packet to port 8080". Be aware that your kernel must be compiled
with support for ipchains (virtually all stock kernels are). You must
also have the ipchains command-line utility installed. You can run this
command at any time, preferably just once, since it inserts another copy
of the rule every time you run it.
This command instructs the system as follows: "Insert into the kernel's packet filtering the following as the first rule to check on incoming packets: if the protocol is TCP and the destination port is 80, redirect the packet to port 8080".
Be aware that your kernel must be compiled with support for ipchains (virtually all stock kernels are).
You must also have the ipchains command-line utility installed.
You can run this command at any time, preferably just once, since it inserts another copy of the rule every time you run it.
[[using-iptables]]
==== Using iptables
On many Linux systems you can use the iptables REDIRECT mechanism to
redirect from one port to another inside the kernel (if iptables is not
available, then usually ipchains is).
On many Linux systems you can use the iptables REDIRECT mechanism to redirect from one port to another inside the kernel (if iptables is not available, then usually ipchains is).
You need to add something like the following to the startup scripts or
your firewall rules:
You need to add something like the following to the startup scripts or your firewall rules:
[source, screen]
....
----
# /sbin/iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
....
----
The underlying model of iptables is different from ipchains, so the
forwarding normally happens only to packets originating off-box. You
also need to allow incoming packets to port 8080 if you use iptables as
a local firewall.
The underlying model of iptables is different from ipchains, so the forwarding normally happens only to packets originating off-box.
You also need to allow incoming packets to port 8080 if you use iptables as a local firewall.
Be careful to place rules like this one early in your _input_ chain.
Such rules must precede any rule that accepts the packet, otherwise the
redirection won't occur. You can insert as many rules as required if
your server needs to listen on multiple ports, as for HTTPS.
Be careful to place rules like this one early in your _input_ chain.
Such rules must precede any rule that accepts the packet, otherwise the redirection won't occur.
You can insert as many rules as required if your server needs to listen on multiple ports, as for HTTPS.
[[configuring-jetty-setuid-feature]]
==== Configuring Jetty's SetUID Feature
http://en.wikipedia.org/wiki/Setuid[SetUID] is a technique that uses
Unix-like file system access right to allow users to run an executable
that would otherwise require higher privileges.
http://en.wikipedia.org/wiki/Setuid[SetUID] is a technique that uses Unix-like file system access right to allow users to run an executable that would otherwise require higher privileges.
Jetty's SetUID module allows you to run Jetty as a normal user even when
you need to run Jetty on port 80 or 443.
Jetty's `SetUID` module allows you to run Jetty as a normal user even when you need to run Jetty on port 80 or 443.
To use it with the jetty distribution:
To use it with the Jetty distribution:
1. Ensure that you have the http.mod (and
link:#quickstart-starting-https[https.mod] if you are using SSL)
link:#startup-modules[modules enabled] for the
link:#creating-jetty-base[base] you are using. The http.mod is enabled
by default in the distribution, while the
link:#quickstart-starting-https[https.mod] is only enabled in the
link:#demo-webapps-base[demo-base] directory.
2. Ensure that you have link:#quickstart-changing-jetty-port[changed
the http port] to 80 (and link:#quickstart-changing-https-port[changed
the https port] to 443 if you are using SSL).
3. Enable the setuid.mod module:
1. Ensure that you have the `http.mod` (and link:#quickstart-starting-https[https.mod] if you are using SSL) link:#startup-modules[modules enabled] for the link:#creating-jetty-base[base] you are using.
The `http.mod` is enabled by default in the distribution, while the link:#quickstart-starting-https[https.mod] is only enabled in the link:#demo-webapps-base[demo-base] directory.
2. Ensure that you have link:#quickstart-changing-jetty-port[changed the http port] to 80 (and link:#quickstart-changing-https-port[changed the https port] to 443 if you are using SSL).
3. Enable the `setuid.mod` module:
+
[source, screen]
....
----
# java -jar start.jar --add-to-start=setuid
....
----
+
____
[NOTE]
@ -105,9 +79,10 @@ The --add-to-start command will enable the setuid module for this and all subseq
There are other ways to enable the module, such as just for this execution.
For more information on the alternatives see the section on link:#startup-modules[Managing Startup Modules].
____
4. Edit the configuration for the setuid module to substitute the userid and groupid of the user to switch to after starting.
4. Edit the configuration for the `setuid` module to substitute the `userid` and `groupid` of the user to switch to after starting.
If you used the `--add-to-start` command, this configuration is in the `start.ini` file.
If you used the `--add-to-startd` command instead, this configuration is in the `start.d/setuid.ini `file instead.
Here are the lines to configure:
+
[source,text]
@ -122,50 +97,38 @@ ____
[NOTE]
As well as opening the connectors as root, you can also have jetty start the Server as root before changing to the non-root user.
____
5. You now need a native code library to do the user switching. This
code is hosted as part of the Jetty ToolChain project and it is released
independently from Jetty itself. You can find the source code
https://github.com/eclipsejetty.toolchain[here] in the
https://github.com/eclipse/jetty.toolchain/jetty-setuid[jetty-setuid]
project. Build it locally, which will produce a native library
appropriate for the operating system:
5. You now need a native code library to do the user switching.
This code is hosted as part of the Jetty ToolChain project and it is released independently from Jetty itself.
You can find the source code https://github.com/eclipsejetty.toolchain[here] in the https://github.com/eclipse/jetty.toolchain/jetty-setuid[jetty-setuid] project.
Build it locally, which will produce a native library appropriate for the operating system:
+
[source, screen]
....
----
# mvn clean install
....
----
+
If you built on a linux machine you will find the native library in
`jetty-setuid/libsetuid-linux/target/libsetuid-linux.so`. If you built
on a different operating system you will find the library in a different
subdirectory, with the name containing the name of the operating system.
You might like to copy this file into your jetty distribution's lib
directory.
6. Start jetty as the root user in your base directory, providing the
location of the native library to java. Here's an example of how to do
it on the command line, assuming were are in the
link:#demo-webapps-base[demo-base] directory:
If you built on a linux machine you will find the native library in `jetty-setuid/libsetuid-linux/target/libsetuid-linux.so`.
If you built on a different operating system you will find the library in a different subdirectory, with the name containing the name of the operating system.
You might like to copy this file into your jetty distribution's lib directory.
6. Start jetty as the root user in your base directory, providing the location of the native library to java.
Here's an example of how to do it on the command line, assuming were are in the link:#demo-webapps-base[demo-base] directory:
+
[source, screen]
....
----
# sudo java -Djava.library.path=libsetuid-linux -jar $JETTY_HOME/start.jar
....
----
[[using-solaris10-user-rights-management-framework]]
==== Using the Solaris 10 User Rights Management Framework
Solaris 10 provides a User Rights Management framework that can permit
users and processes superuser-like abilities:
Solaris 10 provides a User Rights Management framework that can permit users and processes superuser-like abilities:
[source, screen]
....
----
usermod -K defaultpriv=basic,net_privaddr myself
....
----
Now the `myself` user can bind to port 80.
Refer to the
http://docs.oracle.com/cd/E23823_01/html/816-4557/prbactm-1.html#scrolltoc[Solaris
10] and
http://docs.oracle.com/cd/E23824_01/html/821-1456/prbactm-1.html#scrolltoc[Solaris
11 Security Services documentation] for more information.
Refer to the http://docs.oracle.com/cd/E23823_01/html/816-4557/prbactm-1.html#scrolltoc[Solaris 10] and http://docs.oracle.com/cd/E23824_01/html/821-1456/prbactm-1.html#scrolltoc[Solaris 11 Security Services documentation] for more information.

View File

@ -17,33 +17,15 @@
[[configuring-virtual-hosts]]
=== Configuring Virtual Hosts
A virtual host is an alternative name, registered in DNS, for an IP
address such that multiple domain names will resolve to the same IP of a
shared server instance. If the content to be served to the aliases names
is link:#different-virtual-hosts-different-contexts[different], then a
virtual host needs to be configured for each deployed
link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html[context]
to indicate which names a context will respond to.
A virtual host is an alternative name, registered in DNS, for an IP address such that multiple domain names will resolve to the same IP of a shared server instance.
If the content to be served to the aliases names is link:#different-virtual-hosts-different-contexts[different], then a virtual host needs to be configured for each deployed link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html[context] to indicate which names a context will respond to.
Virtual hosts are set on a
link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html[context]
by calling the
link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html#setVirtualHosts-java.lang.String:A-[`setVirtualHosts`]
or
link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html#addVirtualHosts-java.lang.String:A-[`addVirtualHost`]
method which can be done either
Virtual hosts are set on a link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html[context] by calling the link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html#setVirtualHosts-java.lang.String:A-[`setVirtualHosts`] or link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html#addVirtualHosts-java.lang.String:A-[`addVirtualHost`] method which can be done in several ways:
* Using a link:#deployable-descriptor-file[context XML] file in the
webapps directory (see the example in
link:{SRCDIR}/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/webapps/test.xml[test.xml]
in the jetty distribution).
* Using a link:#deployable-descriptor-file[context XML] file in the webapps directory (see the example in link:{SRCDIR}/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/webapps/test.xml[test.xml] in the Jetty distribution).
* Using a `WEB-INF/jetty-web.xml` file (deprecated).
* Creating a link:#deployment-architecture[custom deployer] with a
binding to configure virtual hosts for all contexts found in the same
webapps directory.
* Calling the
link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html#setVirtualHosts-java.lang.String:A-[API]
directly on an link:#advanced-embedding[embedded] usage.
* Creating a link:#deployment-architecture[custom deployer] with a binding to configure virtual hosts for all contexts found in the same `webapps` directory.
* Calling the link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html#setVirtualHosts-java.lang.String:A-[API] directly on an link:#advanced-embedding[embedded] usage.
[[configuring-a-virtual-host]]
==== Virtual Host Names
@ -51,44 +33,23 @@ directly on an link:#advanced-embedding[embedded] usage.
Jetty supports the following styles of virtual host name:
www.hostname.com::
A fully qualified host name. It is important to list all variants as a
site may receive traffic from both www.hostname.com and just
hostname.com
A fully qualified host name. It is important to list all variants as a site may receive traffic from both www.hostname.com and just hostname.com
*.hostname.com::
A wildcard qualified host which will match only one level of arbitrary
names. *.foo.com will match www.foo.com and m.foo.com, but not
www.other.foo.com
A wildcard qualified host which will match only one level of arbitrary names.
*.foo.com will match www.foo.com and m.foo.com, but not www.other.foo.com
10.0.0.2::
An IP address may be given as a virtual host name to indicate that a
context should handle requests received on that server port that do
not have a host name specified (HTTP/0.9 or HTTP/1.0)
An IP address may be given as a virtual host name to indicate that a context should handle requests received on that server port that do not have a host name specified (HTTP/0.9 or HTTP/1.0).
@ConnectorName::
A connector name, which is not strictly a virtual host, but instead
will only match requests that are received on connectors that have a
matching name set with
link:{JDURL}/org/eclipse/jetty/server/AbstractConnector.html#setName(java.lang.String)[Connector.setName(String)].
A connector name, which is not strictly a virtual host, but instead will only match requests that are received on connectors that have a matching name set with link:{JDURL}/org/eclipse/jetty/server/AbstractConnector.html#setName(java.lang.String)[Connector.setName(String)].
www.√integral.com::
Non ascii and
http://en.wikipedia.org/wiki/Internationalized_domain_name[IDN] domain
names can be set as virtual hosts using
http://en.wikipedia.org/wiki/Punycode[Puny Code] equivalents that may
be obtained from a
http://network-tools.com/idn-convert.asp[Punycode/IDN converters]. For
example if the non ascii domain name `www.√integral.com` is given to a
browser, then it will make a request that uses the domain name
`www.xn--integral-7g7d.com`, which is the name that should be added as
the virtual host name.
Non-ASCII and http://en.wikipedia.org/wiki/Internationalized_domain_name[IDN] domain names can be set as virtual hosts using http://en.wikipedia.org/wiki/Punycode[Puny Code] equivalents that may be obtained from a http://network-tools.com/idn-convert.asp[Punycode/IDN converters].
For example if the non-ASCII domain name `www.√integral.com` is given to a browser, then it will make a request that uses the domain name `www.xn--integral-7g7d.com`, which is the name that should be added as the virtual host name.
==== Example Virtual Host Configuration
Virtual hosts can be used with any context that is a subclass of
link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html[ContextHandler].
Lets look at an example where we configure a web application -
represented by the
link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html[WebAppContext]
class - with virtual hosts. You supply a list of IP addresses and names
at which the web application is reachable. Suppose you have a machine
with these IP addresses and these DNS resolvable names:
Virtual hosts can be used with any context that is a subclass of link:{JDURL}/org/eclipse/jetty/server/handler/ContextHandler.html[ContextHandler].
Lets look at an example where we configure a web application -represented by the link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html[WebAppContext] class - with virtual hosts.
You supply a list of IP addresses and names at which the web application is reachable, such as the following:
* `333.444.555.666`
* `127.0.0.1`
@ -96,10 +57,8 @@ with these IP addresses and these DNS resolvable names:
* `www.blah.net`
* `www.blah.org`
Suppose you have a webapp called `blah.war`, that you want all of the
above names and addresses to be served at path "`/blah`". Here's how you
would configure the virtual hosts with a
link:#deployable-descriptor-file[context XML] file:
Suppose you have a webapp called `blah.war`, that you want all of the above names and addresses to be served at path "`/blah`".
Here's how you would configure the virtual hosts with a link:#deployable-descriptor-file[context XML] file:
[source,xml]
----
@ -124,8 +83,7 @@ link:#deployable-descriptor-file[context XML] file:
[[different-virtual-hosts-different-contexts]]
==== Using Different Sets of Virtual Hosts to Select Different Contexts
You can configure different contexts to respond on different virtual
hosts by supplying a specific list of virtual hosts for each one.
You can configure different contexts to respond on different virtual hosts by supplying a specific list of virtual hosts for each one.
For example, suppose your imaginary machine has these DNS names:
@ -134,14 +92,11 @@ For example, suppose your imaginary machine has these DNS names:
* `www.blah.org`
* `www.other.com`
* `www.other.net`
* `www.other.org `
* `www.other.org`
Suppose also you have 2 webapps, one called `blah.war` that you would
like served from the `*.blah.*` names, and one called `other.war` that
you want served only from the `*.other.*` names.
Suppose also you have 2 webapps, one called `blah.war` that you would like served from the `*.blah.*` names, and one called `other.war` that you want served only from the `*.other.*` names.
Using the method of preparing link:#deployable-descriptor-files[context
XML] files, one for each webapp yields the following:
Using the method of preparing link:#deployable-descriptor-files[contextXML] files, one for each webapp yields the following:
For `blah` webapp:
@ -163,7 +118,7 @@ For `blah` webapp:
</Configure>
----
These urls now resolve to the blah context (ie `blah.war`):
These URLs now resolve to the blah context (ie `blah.war`):
* `http://www.blah.com/blah`
* `http://www.blah.net/blah`
@ -189,7 +144,7 @@ For `other` webapp:
</Configure>
----
These urls now resolve to the other context (ie other.war):
These URLs now resolve to the other context (i.e. `other.war`):
* `http://www.other.com/other`
* `http://www.other.net/other`
@ -198,34 +153,25 @@ These urls now resolve to the other context (ie other.war):
[[different-virtual-hosts-different-context-same-path]]
==== Using Different Sets of Virtual Hosts to Select Different Contexts at the Same Context Path
In the previous section we setup 2 different contexts to be served from
different virtual hosts at _different_ context paths. However, there is
no requirement that the context paths must be distinct: you may use the
same context path for multiple contexts, and use virtual hosts to
determine which one is served for a given request.
In the previous section we setup 2 different contexts to be served from different virtual hosts at _different_ context paths.
However, there is no requirement that the context paths must be distinct: you may use the same context path for multiple contexts, and use virtual hosts to determine which one is served for a given request.
Consider an example where we have the same set of DNS names as before,
and the same webapps `blah.war` and `other.war`. We still want
`blah.war` to be served in response to hostnames of `*.blah.*`, and we
still want `other.war` to be served in response to `*.other.*` names.
However, we would like__all__ of our clients to use the `"/"` context
path, no matter which context is being targeted.
Consider an example where we have the same set of DNS names as before, and the same webapps `blah.war` and `other.war`. We still want `blah.war` to be served in response to hostnames of `*.blah.*`, and we still want `other.war` to be served in response to `*.other.*` names.
However, we would like__all__ of our clients to use the `"/"` context path, no matter which context is being targeted.
In other words, we want all of the following urls to map to `blah.war`:
In other words, we want all of the following URLs to map to `blah.war`:
* `http://www.blah.com/`
* `http://www.blah.net/`
* `http://www.blah.org/`
Similarly, we want the following urls to map to `other.war`:
Similarly, we want the following URLs to map to `other.war`:
* `http://www.other.com/`
* `http://www.other.net/`
* `http://www.other.org/`
To achieve this, we simply use the same context path of "/" for each of
our webapps, whilst still applying our different set of virtual host
names.
To achieve this, we simply use the same context path of `/` for each of our webapps, while still applying our different set of virtual host names.
For foo webapp:

View File

@ -17,21 +17,16 @@
[[custom-error-pages]]
=== Creating Custom Error Pages
The following sections describe several ways to create custom error
pages in Jetty.
The following sections describe several ways to create custom error pages in Jetty.
==== Defining error pages in web.xml
You can use the standard webapp configuration file located in
`webapp/WEB-INF/web.xml` to map errors to specific URLs with the
error-page element. This element creates a mapping between the
error-code or exception-type to the location of a resource in the web
application.
You can use the standard webapp configuration file located in `webapp/WEB-INF/web.xml` to map errors to specific URLs with the `error-page` element.
This element creates a mapping between the error-code or exception-type to the location of a resource in the web application.
* error-code - an integer value
* exception-type - a fully qualified class name of a Java Exception type
* location - location of the resource in the webapp relative to the root
of the web application. Value should start with "/".
* `error-code` - an integer value
* `exception-type` - a fully qualified class name of a Java Exception type
* `location` - location of the resource in the webapp relative to the root of the web application. Value should start with `/`.
Error code example:
@ -55,36 +50,27 @@ Exception example:
----
The error page mappings created with the error-page element will
redirect to a normal URL within the web application and will be handled
as a normal request to that location and thus may be static content, a
JSP or a filter and/or servlet. When handling a request generated by an
error redirection, the following request attributes are set and are
available to generate dynamic content:
The error page mappings created with the error-page element will redirect to a normal URL within the web application and will be handled as a normal request to that location and thus may be static content, a JSP or a filter and/or servlet.
When handling a request generated by an error redirection, the following request attributes are set and are available to generate dynamic content:
javax.servlet.error.exception::
The exception instance that caused the error (or null)
The exception instance that caused the error (or null).
javax.servlet.error.exception_type::
The class name of the exception instance that caused the error (or
null)
The class name of the exception instance that caused the error (or null).
javax.servlet.error.message::
The error message.
javax.servlet.error.request_uri::
The URI of the errored request.
The URI of the request with an error.
javax.servlet.error.servlet_name::
The Servlet name of the servlet that the errored request was
dispatched to/
The Servlet name of the servlet that the request was
dispatched to.
javax.servlet.error.status_code::
The status code of the error (e.g. 404, 500 etc.)
The status code of the error (e.g. 404, 500 etc.).
==== Configuring error pages context files
You can use context IoC XML files to configure the default error page
mappings with more flexibility than is available with `web.xml`,
specifically with the support of error code ranges. Context files are
normally located in `${jetty.home}/webapps/` (see DeployerManager for
more details) and an example of more flexible error page mapping is
below:
You can use context IoC XML files to configure the default error page mappings with more flexibility than is available with `web.xml`, specifically with the support of error code ranges.
Context files are normally located in `${jetty.home}/webapps/` (see `DeployerManager` for more details) and an example of more flexible error page mapping is below:
[source,xml]
----
@ -131,12 +117,8 @@ below:
==== Custom ErrorHandler class
If no error page mapping is defined, or if the error page resource
itself has an error, then the error page will be generated by an
instance of ErrorHandler configured either the Context or the Server. An
ErrorHandler may extend the ErrorHandler class and may totally replace
the handle method to generate an error page, or it can implement some or
all of the following methods to partially modify the error pages:
If no error page mapping is defined, or if the error page resource itself has an error, then the error page will be generated by an instance of `ErrorHandler` configured either the Context or the Server.
An `ErrorHandler` may extend the `ErrorHandler` class and may totally replace the handle method to generate an error page, or it can implement some or all of the following methods to partially modify the error pages:
[source,java]
----
@ -147,56 +129,43 @@ void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, Str
void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks) throws IOException
void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message, String uri) throws IOException
void writeErrorPageStacks(HttpServletRequest request, Writer writer) throws IOException
----
An ErrorHandler instance may be set on a Context by calling the
ContextHandler.setErrorHandler method. This can be done by embedded code
or via context IoC XML. For example:
An `ErrorHandler` instance may be set on a Context by calling the `ContextHandler.setErrorHandler` method. This can be done by embedded code or via context IoC XML.
For example:
[source,xml]
----
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
...
<Set name="errorHandler">
<New class="com.acme.handler.MyErrorHandler"/>
</Set>
...
</Configure>
----
An ErrorHandler instance may be set on the entire server by setting it
as a dependent bean on the Server instance. This can be done by calling
Server.addBean(Object) via embedded code or in jetty.xml IoC XML like:
An `ErrorHandler` instance may be set on the entire server by setting it as a dependent bean on the Server instance.
This can be done by calling `Server.addBean(Object)` via embedded code or in `jetty.xml` IoC XML like:
[source,xml]
----
<Configure id="Server" class="org.eclipse.jetty.server.Server">
...
<Call name="addBean">
<Arg>
<New class="com.acme.handler.MyErrorHandler"/>
</Arg>
</Call>
...
</Configure>
----
==== Server level 404 error
You might get a 'page not found' when a request is made to the server
for a resource that is outside of any registered contexts. As an
example, you have a domain name pointing to your public server IP, yet
no context is registered with jetty to serve pages for that domain. As a
consequence, the server, by default, gives a listing of all contexts
running on the server.
It is possible to get a 'page not found' when a request is made to the server for a resource that is outside of any registered contexts.
As an example, you have a domain name pointing to your public server IP, yet no context is registered with Jetty to serve pages for that domain.
As a consequence, the server, by default, gives a listing of all contexts running on the server.
One of the quickest ways to avoid this behavior is to create a catch all
context. Create a "root" web app mapped to the "/" URI. Have the
index.html redirect to whatever place with a header directive.
One of the quickest ways to avoid this behavior is to create a catch all context.
Create a "root" web app mapped to the "/" URI, and use the `index.html` redirect to whatever place with a header directive.

View File

@ -17,65 +17,44 @@
[[serving-webapp-from-particular-port]]
=== Serving a WebApp from a Particular Port/Connector
Sometimes it is required to serve different web applications from
different ports/connectors. The simplest way to do this is to create
multiple `Server` instances, however if contexts need to share resources
(eg data sources, authentication), or if the mapping of ports to web
applications is not cleanly divided, then the named connector mechanism
can be used.
Sometimes it is required to serve different web applications from different ports/connectors.
The simplest way to do this is to create multiple `Server` instances.
However, if contexts need to share resources (eg data sources, authentication), or if the mapping of ports to web applications is not cleanly divided, then the named connector mechanism can be used.
[[creating-server-instances]]
==== Creating Multiple Server Instances
How to create multiple server instances is simply done when writing
embedded jetty code by creating multiples instances of the Server class
and configuring them as needed. This is also easy to achieve if you are
configuring your servers in XML. The id field in the Configure element
of jetty.xml files is used to identify the instance that the
configuration applies to, so to run two instances of the Server, you can
copy the jetty.xml, jetty-http.xml and other jetty configuration files
used and change the "Server" id to a new name. This can be done in the
same style and layout as the existing jetty.xml files or the multiple
XML files may be combined to a single file.
Creating multiple server instances is a straight forward process that includes embedding Jetty code by creating multiples instances of the Server class and configuring them as needed.
This is also easy to achieve if you are configuring your servers in XML.
The `id` field in the Configure element of `jetty.xml` files is used to identify the instance that the configuration applies to, so to run two instances of the Server, you can copy the `jetty.xml`, jetty-http.xml and other jetty configuration files used and change the "Server" id to a new name.
This can be done in the same style and layout as the existing `jetty.xml` files or the multiple XML files may be combined to a single file.
When creating new configurations for alternative server:
* Change all id="Server" to the new server
name:`<Configure id="OtherServer"
class="org.eclipse.jetty.server.Server"> `
* For all connectors for the new server change the refid in the server
argument: `<Arg name="server"><Ref
refid="OtherServer" /></Arg>`
* Make sure that any references to properties like jetty.http.port are
either renamed or replaced with absolute values
* Make sure that any deployers AppProviders refer to a different
"webapps" directory so that a different set of applications are
deployed.
* Change all `id="Server"` to the new server name: `<Configure id="OtherServer" class="org.eclipse.jetty.server.Server">`
* For all connectors for the new server change the `refid` in the server argument: `<Arg name="server"><Ref refid="OtherServer" /></Arg>`
* Make sure that any references to properties like `jetty.http.port` are either renamed or replaced with absolute values
* Make sure that any deployers `AppProviders` refer to a different "webapps" directory so that a different set of applications are deployed.
[[jetty-otherserver.xml]]
===== Example Other Server XML
The following example creates another server instance and configures it
with a connector and deployer:
The following example creates another server instance and configures it with a connector and deployer:
[source,xml]
----
include::{SRCDIR}/examples/embedded/src/main/resources/jetty-otherserver.xml[]
----
To run the other server, simply add the extra configuration file(s) to
the command line:
To run the other server, add the extra configuration file(s) to the command line:
[source, screen]
....
----
java -jar start.jar jetty-otherserver.xml
....
----
[[alternative]]
==== Named Connectors
It is also possible to use an extension to the virtual host mechanism
with named to connectors to make some web applications only accessible
by specific connectors. If a connector has a name "MyConnector" set
using the setName method, then this can be referenced with the special
virtual host name "@MyConnector".
It is also possible to use an extension to the virtual host mechanism with named to connectors to make some web applications only accessible by specific connectors.
If a connector has a name "MyConnector" set using the `setName` method, then this can be referenced with the special virtual host name "@MyConnector".

View File

@ -17,63 +17,42 @@
[[setting-context-path]]
=== Setting a Context Path
The context path is the prefix of a URL path that is used to select the
context(s) to which an incoming request is passed. Typically a URL in a
Java servlet server is of the format `
http://hostname.com/contextPath/servletPath/pathInfo`, where each of
the path elements can be zero or more / separated elements. If there is
no context path, the context is referred to as the _root_ context. The
root context must be configured as "/" but is reported as the empty
string by the servlet API getContextPath() method.
The context path is the prefix of a URL path that is used to select the context(s) to which an incoming request is passed. Typically a URL in a Java servlet server is of the format `http://hostname.com/contextPath/servletPath/pathInfo`, where each of the path elements can be zero or more / separated elements.
If there is no context path, the context is referred to as the _root_ context.
The root context must be configured as `/` but is reported as the empty string by the servlet API `getContextPath()` method.
How you set the context path depends on how you deploy the web
application (or ContextHandler):
How you set the context path depends on how you deploy the web application (or `ContextHandler`).
[[using-embedded-deployment]]
==== Using Embedded Deployment
If you run Jetty from code as an embedded server (see
link:#advanced-embedding[Embedding]), setting the context path is a
matter of calling the `setContextPath` method on the `ContextHandler`
instance (or `WebAppContext` instance).
If you run Jetty from code as an embedded server (see link:#advanced-embedding[Embedding]), setting the context path is a matter of calling the `setContextPath` method on the `ContextHandler` instance (or `WebAppContext` instance).
[[usng-the-context-provider]]
==== By naming convention
If a web application is deployed using the WebAppProvider of the
DeploymentManager without an XML IoC file, then the name of the WAR file
is used to set the context path:
If a web application is deployed using the WebAppProvider of the DeploymentManager without an XML IoC file, then the name of the WAR file is used to set the context path:
* If the WAR file is named myapp.war, then the context will be deployed
with a context path of /myapp
* If the WAR file is named ROOT.WAR (or any case insensitive variation),
then the context will be deployed with a context path of /
* If the WAR file is named ROOT-foobar.war ( or any case insensitive
variation), then the context will be deployed with a context path of /
and a virtual host of "foobar"
* If the WAR file is named myapp.war, then the context will be deployed with a context path of `/myapp`
* If the WAR file is named ROOT.WAR (or any case insensitive variation), then the context will be deployed with a context path of `/`
* If the WAR file is named ROOT-foobar.war ( or any case insensitive variation), then the context will be deployed with a context path of `/` and a virtual host of "foobar"
[[using-the-webapp-provider]]
==== By Deployer configuration
If a web application is deployed using the WebAppProvider of the
DeploymentManager with an XML IoC file to configure the context, then
the setContextPath method can be called within that file. For example:
If a web application is deployed using the `WebAppProvider` of the `DeploymentManager` with an XML IoC file to configure the context, then the `setContextPath` method can be called within that file.
For example:
[source,xml]
----
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
...
</Configure>
----
[[embedding-web-inf-jetty-web.xml-file]]
==== Embedding a WEB-INF/jetty-web.xml File
You can also set the context path for webapps by embedding a
`WEB-INF/jetty-web.xml` file in the WAR, which uses the same XML IoC
format as the deployer example above. However this is not the preferred
method as it requires the web application to be modified.
You can also set the context path for webapps by embedding a `WEB-INF/jetty-web.xml` file in the WAR, which uses the same XML IoC format as the deployer example above.
However this is not the preferred method as it requires the web application to be modified.

View File

@ -17,58 +17,44 @@
[[setting-form-size]]
=== Setting Max Form Size
Jetty limits the amount of data that can post back from a browser or
other client to the server. This helps protect the server against denial
of service attacks by malicious clients sending huge amounts of data.
The default maximum size Jetty permits is 200000 bytes. You can change
this default for a particular webapp, for all webapps on a particular
Server instance, or all webapps within the same JVM.
Jetty limits the amount of data that can post back from a browser or other client to the server.
This helps protect the server against denial of service attacks by malicious clients sending huge amounts of data.
The default maximum size Jetty permits is 200000 bytes.
You can change this default for a particular webapp, for all webapps on a particular Server instance, or all webapps within the same JVM.
==== For a Single Webapp
The method to invoke is:
`ContextHandler.setMaxFormContentSize(int maxSize);`
The method to invoke is: `ContextHandler.setMaxFormContentSize(int maxSize);`
You can do this either in a context XML deployment descriptor external
to the webapp, or in a `jetty-web.xml` file in the webapp's WEB-INF
directory.
This can be done either in a context XML deployment descriptor external to the webapp, or in a `jetty-web.xml` file in the webapp's `WEB-INF` directory.
In either case the syntax of the XML file is the same:
[source,xml]
----
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Max Form Size -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<Set name="maxFormContentSize">200000</Set>
</Configure>
----
==== For All Apps on a Server
Set an attribute on the Server instance for which you want to modify the
maximum form content size:
Set an attribute on the Server instance for which you want to modify the maximum form content size:
[source,xml]
----
<Configure class="org.eclipse.jetty.server.Server">
<Call name="setAttribute">
<Arg>org.eclipse.jetty.server.Request.maxFormContentSize</Arg>
<Arg>200000</Arg>
</Call>
</Configure>
----
==== For All Apps in the JVM
Use the system property
`org.eclipse.jetty.server.Request.maxFormContentSize`. This can be set
on the commandline or in the start.ini file.
Use the system property `org.eclipse.jetty.server.Request.maxFormContentSize`.
This can be set on the command line or in the `start.ini` file.

View File

@ -17,18 +17,13 @@
[[ref-temporary-directories]]
=== Temporary Directories
Jetty itself has no temporary directories, but you can assign a
directory for each web application, into which the WAR is unpacked, JSPs
compiled on-the-fly, etc. If you do not assign a specific temporary
directory, Jetty will create one as needed when your web application
starts. Whether you set the location of the temporary directory - or you
let Jetty create one for you - you also have a choice to either keep or
delete the temporary directory when the web application stops.
Jetty itself has no temporary directories, but you can assign a directory for each web application, into which the WAR is unpacked, JSPs compiled on-the-fly, etc.
If you do not assign a specific temporary directory, Jetty will create one as needed when your web application starts.
Whether you set the location of the temporary directory - or you let Jetty create one for you - you also have a choice to either keep or delete the temporary directory when the web application stops.
==== The default temp directory
By default, Jetty will create a temporary directory for each web
application. The name of the directory will be of the form:
By default, Jetty will create a temporary directory for each web application. The name of the directory will be of the form:
....
"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"
@ -40,26 +35,19 @@ For example:
jetty-0.0.0.0-8080-test.war-_test-any-8900275691885214790.dir
....
Where `0.0.0.0` is the host address, `8080` is the port, `test.war` is
the resourceBase, `test` is the context path (with / converted to _),
`any` is the virtual host, and `randomdigits` are a string of digits
guaranteed to be unique.
Where `0.0.0.0` is the host address, `8080` is the port, `test.war` is the resourceBase, `test` is the context path (with / converted to _), `any` is the virtual host, and `randomdigits` are a string of digits guaranteed to be unique.
Once the temp directory is created, it is retrievable as the value (as a
File) of the context attribute `javax.servlet.context.tempdir.`
Once the temp directory is created, it is retrievable as the value (as a File) of the context attribute `javax.servlet.context.tempdir.`
===== The location of the temp directory
By default, jetty will create this directory inside the directory named
by the `java.io.tmpdir` System property. You can instruct Jetty to use a
different parent directory by setting the context attribute
`org.eclipse.jetty.webapp.basetempdir` to the name of the desired parent
directory. The directory named by this attribute _must_ exist and be
__writeable__.
By default, Jetty will create this directory inside the directory named by the `java.io.tmpdir` System property.
You can instruct Jetty to use a different parent directory by setting the context attribute `org.eclipse.jetty.webapp.basetempdir` to the name of the desired parent directory.
The directory named by this attribute _must_ exist and be __writeable__.
As usual with Jetty, you can either set this attribute in a context xml
file, or you can do it in code. Here's an example of setting it in an
xml file:
As usual with Jetty, you can either set this attribute in a context xml file, or you can do it in code.
Here's an example of setting it in an xml file:
[source,xml]
----
@ -87,12 +75,10 @@ context.setAttribute("org.eclipse.jetty.webapp.basetempdir", "/tmp/foo");
==== Setting a specific temp directory
To use a particular directory as the temporary directory you can do
either:
There are several ways to use a particular directory as the temporary directory:
call WebAppContext.setTempDirectory(String dir)::
As usual with Jetty, you can do this with an xml file or directly in
code. Here's an example of setting the temp directory in xml:
Like before this can be accomplished with an xml file or directly in code. Here's an example of setting the temp directory in xml:
+
[source,xml]
----
@ -116,8 +102,7 @@ context.setTempDirectory(new File("/some/dir/foo"));
----
set the `javax.servlet.context.tempdir` context attribute::
You should set this context attribute with the name of directory you
want to use as the temp directory. Again, you can do this in xml:
You should set this context attribute with the name of directory you want to use as the temp directory. Again, you can do this in xml:
[source,xml]
----
@ -144,9 +129,7 @@ context.setWar("foo.war");
context.setAttribute("javax.servlet.context.tempdir", "/some/dir/foo");
----
Once a temporary directory has been created by either of these methods,
a File instance for it is set as the value of the
`javax.servlet.context.tempdir` attribute of the web application.
Once a temporary directory has been created by either of these methods, a File instance for it is set as the value of the `javax.servlet.context.tempdir` attribute of the web application.
____
[NOTE]
@ -156,27 +139,20 @@ ____
==== The "work" directory
Mostly for backward compatibility, from jetty-9.1.1 onwards, it will be
possible to create a directory named "work" in the $\{jetty.base}
directory. If such a directory is found, it is assumed you want to use
it as the parent directory for all of the temporary directories of the
webapps in that $\{jetty.base}. Moreover, as has historically been the
case, these temp directories inside the work directory are not cleaned
up when jetty exists (or more correctly speaking, the temp dir
corresponding to a context is not cleaned up when that context stops).
Mostly for backward compatibility, from jetty-9.1.1 onwards, it is be possible to create a directory named "work" in the `$\{jetty.base}` directory.
If such a directory is found, it is assumed you want to use it as the parent directory for all of the temporary directories of the webapps in that `$\{jetty.base}`.
Moreover, as has historically been the case, these temp directories inside the work directory are not cleaned up when jetty exists (or more correctly speaking, the `temp` directory corresponding to a context is not cleaned up when that context stops).
When a work directory is used, the algorithm for generating the name of
the context-specific temp dirs omits the random digit string. This
ensures the name of the dir remains consistent across context restarts.
When a work directory is used, the algorithm for generating the name of the context-specific temp directories omits the random digit string.
This ensures the name of the directory remains consistent across context restarts.
==== Persisting the temp directory
Sometimes you may find it useful to keep the contents of the temporary
directory between restarts of the web application. By default, Jetty
will _not_ persist the temp directory. To cause Jetty to keep it, use
link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html[WebAppContext.setPersistTempDirectory(true)].
Sometimes you may find it useful to keep the contents of the temporary directory between restarts of the web application.
By default, Jetty will _not_ persist the temp directory.
To configure Jetty to keep it, use link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html[WebAppContext.setPersistTempDirectory(true)].
Be aware that if you call setPersistTempDirectory(true), but let Jetty
create a new temp directory each time (ie you do NOT set an explicit
temp directory), then you will accumulate temp directories in your
chosen temp directory location.
____
[NOTE]
Be aware that if you call `setPersistTempDirectory(true)`, but let Jetty create a new temp directory each time (i.e. you do NOT set an explicit temp directory), then you will accumulate temp directories in your chosen temp directory location.
____

View File

@ -94,14 +94,10 @@ public class ALPNNegotiationTest extends AbstractALPNTest
// Now if we read more, we should read a TLS Alert.
encrypted.clear();
read = channel.read(encrypted);
if (read > 0)
{
encrypted.flip();
// TLS Alert message type == 21.
Assert.assertEquals(21, encrypted.get() & 0xFF);
encrypted.clear();
Assert.assertEquals(-1, channel.read(encrypted));
}
Assert.assertTrue(read > 0);
Assert.assertEquals(21, encrypted.get(0));
encrypted.clear();
Assert.assertEquals(-1, channel.read(encrypted));
}
}
@ -151,11 +147,12 @@ public class ALPNNegotiationTest extends AbstractALPNTest
ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
sslEngine.unwrap(encrypted, decrypted);
// Now if we read more, we should either read the TLS Close Alert, or directly -1
// Now if we read more, we should read the TLS Close Alert.
encrypted.clear();
read = channel.read(encrypted);
// Since we have close the connection abruptly, the server also does so
Assert.assertTrue(read < 0);
encrypted.flip();
Assert.assertTrue(read > 0);
Assert.assertEquals(21, encrypted.get(0));
}
}

View File

@ -81,7 +81,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
// If somebody else switched to CLOSED while we were ishutting,
// then we do the close for them
if (_state.get()==State.CLOSED)
doOnClose();
doOnClose(null);
else
throw new IllegalStateException();
}
@ -102,7 +102,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
if (!_state.compareAndSet(s,State.CLOSED))
continue;
// Already OSHUT so we close
doOnClose();
doOnClose(null);
return;
case CLOSED: // already closed
@ -133,7 +133,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
// If somebody else switched to CLOSED while we were oshutting,
// then we do the close for them
if (_state.get()==State.CLOSED)
doOnClose();
doOnClose(null);
else
throw new IllegalStateException();
}
@ -150,7 +150,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
if (!_state.compareAndSet(s,State.CLOSED))
continue;
// Already ISHUT so we close
doOnClose();
doOnClose(null);
return;
case OSHUTTING: // Somebody else oshutting
@ -165,6 +165,11 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
@Override
public final void close()
{
close(null);
}
protected final void close(Throwable failure)
{
while(true)
{
@ -176,7 +181,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
case OSHUT: // Already oshut
if (!_state.compareAndSet(s,State.CLOSED))
continue;
doOnClose();
doOnClose(failure);
return;
case ISHUTTING: // Somebody else ishutting
@ -193,15 +198,14 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
}
protected void doShutdownInput()
{}
{
}
protected void doShutdownOutput()
{}
{
}
protected void doClose()
{}
private void doOnClose()
private void doOnClose(Throwable failure)
{
try
{
@ -209,10 +213,24 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
}
finally
{
onClose();
if (failure == null)
onClose();
else
onClose(failure);
}
}
protected void doClose()
{
}
protected void onClose(Throwable failure)
{
super.onClose();
_writeFlusher.onFail(failure);
_fillInterest.onFail(failure);
}
@Override
public boolean isOutputShutdown()
{
@ -324,8 +342,6 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
public void onClose()
{
super.onClose();
if (LOG.isDebugEnabled())
LOG.debug("onClose {}",this);
_writeFlusher.onClose();
_fillInterest.onClose();
}

View File

@ -268,7 +268,7 @@ abstract public class WriteFlusher
if (_callback!=null)
_callback.succeeded();
}
boolean isCallbackNonBlocking()
{
return _callback!=null && _callback.isNonBlocking();
@ -280,7 +280,7 @@ abstract public class WriteFlusher
State s = _state.get();
return (s instanceof PendingState) && ((PendingState)s).isCallbackNonBlocking();
}
/**
* Abstract call to be implemented by specific WriteFlushers. It should schedule a call to {@link #completeWrite()}
* or {@link #onFail(Throwable)} when appropriate.
@ -355,7 +355,7 @@ abstract public class WriteFlusher
* {@link #onFail(Throwable)} or {@link #onClose()}
*/
public void completeWrite()
{
{
if (DEBUG)
LOG.debug("completeWrite: {}", this);
@ -404,8 +404,9 @@ abstract public class WriteFlusher
}
}
/* ------------------------------------------------------------ */
/** Flush the buffers iteratively until no progress is made
/**
* Flushes the buffers iteratively until no progress is made.
*
* @param buffers The buffers to flush
* @return The unflushed buffers, or null if all flushed
* @throws IOException if unable to flush
@ -418,15 +419,15 @@ abstract public class WriteFlusher
int before=buffers.length==0?0:buffers[0].remaining();
boolean flushed=_endPoint.flush(buffers);
int r=buffers.length==0?0:buffers[0].remaining();
if (LOG.isDebugEnabled())
LOG.debug("Flushed={} {}/{}+{} {}",flushed,before-r,before,buffers.length-1,this);
if (flushed)
return null;
progress=before!=r;
int not_empty=0;
while(r==0)
{
@ -442,17 +443,17 @@ abstract public class WriteFlusher
if (not_empty>0)
buffers=Arrays.copyOfRange(buffers,not_empty,buffers.length);
}
}
if (LOG.isDebugEnabled())
LOG.debug("!fully flushed {}",this);
// If buffers is null, then flush has returned false but has consumed all the data!
// This is probably SSL being unable to flush the encrypted buffer, so return EMPTY_BUFFERS
// and that will keep this WriteFlusher pending.
return buffers==null?EMPTY_BUFFERS:buffers;
}
/* ------------------------------------------------------------ */
/** Notify the flusher of a failure
* @param cause The cause of the failure
@ -494,8 +495,6 @@ abstract public class WriteFlusher
public void onClose()
{
if (_state.get()==__IDLE)
return;
onFail(new ClosedChannelException());
}
@ -522,7 +521,7 @@ abstract public class WriteFlusher
{
return String.format("WriteFlusher@%x{%s}", hashCode(), _state.get());
}
public String toStateString()
{
switch(_state.get().getType())

View File

@ -29,6 +29,7 @@ import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.AbstractEndPoint;
@ -589,7 +590,7 @@ public class SslConnection extends AbstractConnection
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshook {}/{}", SslConnection.this,
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "client" : "resumed server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
}
@ -668,17 +669,22 @@ public class SslConnection extends AbstractConnection
}
}
}
catch (IllegalStateException e)
catch (SSLHandshakeException x)
{
// Some internal error in SSLEngine
LOG.debug(e);
close();
throw new EofException(e);
close(x);
throw x;
}
catch (Exception e)
catch (SSLException x)
{
close();
throw e;
if (!_handshaken)
x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x);
close(x);
throw x;
}
catch (Throwable x)
{
close(x);
throw x;
}
finally
{
@ -771,6 +777,7 @@ public class SslConnection extends AbstractConnection
switch (wrapResultStatus)
{
case CLOSED:
{
// The SSL engine has close, but there may be close handshake that needs to be written
if (BufferUtil.hasContent(_encryptedOutput))
{
@ -790,11 +797,13 @@ public class SslConnection extends AbstractConnection
getEndPoint().shutdownOutput();
}
return allConsumed;
}
case BUFFER_UNDERFLOW:
{
throw new IllegalStateException();
}
default:
{
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput));
@ -802,7 +811,7 @@ public class SslConnection extends AbstractConnection
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} server handshook complete {}/{}", SslConnection.this, _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
LOG.debug("{} server handshake succeeded {}/{}", SslConnection.this, _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
}
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
@ -862,6 +871,17 @@ public class SslConnection extends AbstractConnection
}
}
}
}
}
catch (SSLHandshakeException x)
{
close(x);
throw x;
}
catch (Throwable x)
{
close(x);
throw x;
}
finally
{
@ -884,32 +904,27 @@ public class SslConnection extends AbstractConnection
public void doShutdownOutput()
{
boolean ishut = isInputShutdown();
boolean oshut = isOutputShutdown();
if (LOG.isDebugEnabled())
LOG.debug("{} shutdownOutput: ishut={}", SslConnection.this, ishut);
if (ishut)
LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, oshut, ishut);
try
{
// Aggressively close, since inbound close alert has already been processed
// and the TLS specification allows to close the connection directly, which
// is what most other implementations expect: a FIN rather than a TLS close
// reply. If a TLS close reply is sent, most implementations send a RST.
getEndPoint().close();
}
else
{
try
synchronized (this)
{
synchronized (this) // TODO review synchronized boundary
if (!oshut)
{
_sslEngine.closeOutbound();
flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
ensureFillInterested();
// Send the TLS close message.
flush(BufferUtil.EMPTY_BUFFER);
if (!ishut)
ensureFillInterested();
}
}
catch (Exception e)
{
LOG.ignore(e);
getEndPoint().close();
}
}
catch (Throwable x)
{
LOG.ignore(x);
getEndPoint().close();
}
}
@ -928,23 +943,8 @@ public class SslConnection extends AbstractConnection
@Override
public void doClose()
{
// First send the TLS Close Alert, then the FIN
if (!_sslEngine.isOutboundDone())
{
try
{
synchronized (this) // TODO review synchronized boundary
{
_sslEngine.closeOutbound();
flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
ensureFillInterested();
}
}
catch (Exception e)
{
LOG.ignore(e);
}
}
// First send the TLS Close Alert, then the FIN.
doShutdownOutput();
getEndPoint().close();
super.doClose();
}

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.server.ssl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
@ -60,11 +59,11 @@ import org.junit.Before;
import org.junit.Test;
public class SslConnectionFactoryTest
{
{
Server _server;
ServerConnector _connector;
int _port;
@Before
public void before() throws Exception
{
@ -84,7 +83,7 @@ public class SslConnectionFactoryTest
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
@ -97,7 +96,7 @@ public class SslConnectionFactoryTest
https.setIdleTimeout(30000);
_server.addConnector(https);
_server.setHandler(new AbstractHandler()
{
@Override
@ -108,30 +107,30 @@ public class SslConnectionFactoryTest
response.flushBuffer();
}
});
_server.start();
_port=https.getLocalPort();
_port=https.getLocalPort();
}
@After
public void after() throws Exception
{
_server.stop();
_server=null;
}
@Test
public void testConnect() throws Exception
{
String response= getResponse("127.0.0.1",null);
String response= getResponse("127.0.0.1",null);
Assert.assertThat(response,Matchers.containsString("host=127.0.0.1"));
}
@Test
public void testSNIConnect() throws Exception
{
String response;
response= getResponse("localhost","localhost","jetty.eclipse.org");
Assert.assertThat(response,Matchers.containsString("host=localhost"));
}
@ -154,30 +153,21 @@ public class SslConnectionFactoryTest
out.flush();
socket.setSoTimeout(1000);
InputStream input = socket.getInputStream();
int read = input.read();
// TLS Alert message type == 21.
Assert.assertThat(read, Matchers.equalTo(21));
int reads = 0;
while (read >= 0)
{
read = input.read();
++reads;
}
Assert.assertThat(reads, Matchers.lessThan(32));
// Expect TLS message type == 21: Alert
Assert.assertThat(socket.getInputStream().read(),Matchers.equalTo(21));
}
}
private String getResponse(String sniHost,String reqHost, String cn) throws Exception
{
SslContextFactory clientContextFactory = new SslContextFactory(true);
clientContextFactory.start();
SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port);
if (cn!=null)
{
{
SNIHostName serverName = new SNIHostName(sniHost);
List<SNIServerName> serverNames = new ArrayList<>();
serverNames.add(serverName);
@ -188,35 +178,35 @@ public class SslConnectionFactoryTest
}
sslSocket.startHandshake();
if (cn!=null)
{
{
X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
Assert.assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn="+cn));
}
sslSocket.getOutputStream().write(("GET /ctx/path HTTP/1.0\r\nHost: "+reqHost+":"+_port+"\r\n\r\n").getBytes(StandardCharsets.ISO_8859_1));
String response = IO.toString(sslSocket.getInputStream());
sslSocket.close();
clientContextFactory.stop();
return response;
}
@Test
public void testSocketCustomization() throws Exception
{
final Queue<String> history = new ConcurrentArrayQueue<>();
_connector.addBean(new SocketCustomizationListener()
{
@Override
protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
{
history.add("customize connector "+connection+","+ssl);
}
}
});
_connector.getBean(SslConnectionFactory.class).addBean(new SocketCustomizationListener()
@ -225,26 +215,26 @@ public class SslConnectionFactoryTest
protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
{
history.add("customize ssl "+connection+","+ssl);
}
}
});
_connector.getBean(HttpConnectionFactory.class).addBean(new SocketCustomizationListener()
{
@Override
protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
{
history.add("customize http "+connection+","+ssl);
}
}
});
String response= getResponse("127.0.0.1",null);
String response= getResponse("127.0.0.1",null);
Assert.assertThat(response,Matchers.containsString("host=127.0.0.1"));
Assert.assertEquals("customize connector class org.eclipse.jetty.io.ssl.SslConnection,false",history.poll());
Assert.assertEquals("customize ssl class org.eclipse.jetty.io.ssl.SslConnection,false",history.poll());
Assert.assertEquals("customize connector class org.eclipse.jetty.server.HttpConnection,true",history.poll());
Assert.assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true",history.poll());
Assert.assertEquals(0,history.size());
}
}