Skip to content

Commit

Permalink
Allow configuring endpointIdentificationAlgorithm for jetty SSL
Browse files Browse the repository at this point in the history
  • Loading branch information
huangminchn committed Dec 2, 2019
1 parent 403eb02 commit 0ff529e
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 19 deletions.
47 changes: 39 additions & 8 deletions src/main/java/spark/Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ public synchronized Service secure(String keystoreFile,
* @param certAlias the default certificate Alias
* @param truststoreFile the truststore file location as string, leave null to reuse
* keystore
* @param truststorePassword the trust store password
* @param needsClientCert Whether to require client certificate to be supplied in
* request
* @param truststorePassword the trust store password
* @return the object with connection set to be secure
*/
public synchronized Service secure(String keystoreFile,
Expand All @@ -260,16 +260,47 @@ public synchronized Service secure(String keystoreFile,
String truststoreFile,
String truststorePassword,
boolean needsClientCert) {
return secure(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert, "HTTPS");
}

/**
* Set the connection to be secure, using the specified keystore and
* truststore. This has to be called before any route mapping is done. You
* have to supply a keystore file, truststore file is optional (keystore
* will be reused).
* This method is only relevant when using embedded Jetty servers. It should
* not be used if you are using Servlets, where you will need to secure the
* connection in the servlet container
*
* @param keystoreFile The keystore file location as string
* @param keystorePassword the password for the keystore
* @param certAlias the default certificate Alias
* @param truststoreFile the truststore file location as string, leave null to reuse
* keystore
* @param truststorePassword the trust store password
* @param needsClientCert Whether to require client certificate to be supplied in
* request
* @param endpointIdentificationAlgorithm Endpoint identification algorithm:
* "HTTPS", "LDAPS" or null
* @return
*/
public synchronized Service secure(String keystoreFile,
String keystorePassword,
String certAlias,
String truststoreFile,
String truststorePassword,
boolean needsClientCert,
String endpointIdentificationAlgorithm) {
if (initialized) {
throwBeforeRouteMappingException();
}

if (keystoreFile == null) {
throw new IllegalArgumentException(
"Must provide a keystore file to run secured");
"Must provide a keystore file to run secured");
}

sslStores = SslStores.create(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert);
sslStores = SslStores.create(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert, endpointIdentificationAlgorithm);
return this;
}

Expand Down Expand Up @@ -314,7 +345,7 @@ public synchronized Service staticFileLocation(String folder) {
if (initialized && !isRunningFromServlet()) {
throwBeforeRouteMappingException();
}

if (!staticFilesConfiguration.isStaticResourcesSet()) {
staticFilesConfiguration.configure(folder);
} else {
Expand All @@ -334,7 +365,7 @@ public synchronized Service externalStaticFileLocation(String externalFolder) {
if (initialized && !isRunningFromServlet()) {
throwBeforeRouteMappingException();
}

if (!staticFilesConfiguration.isExternalStaticResourcesSet()) {
staticFilesConfiguration.configureExternal(externalFolder);
} else {
Expand Down Expand Up @@ -467,7 +498,7 @@ public synchronized void stop() {
}
initiateStop();
}

/**
* Waits for the Spark server to stop.
* <b>Warning:</b> this method should not be called from a request handler.
Expand All @@ -480,15 +511,15 @@ public void awaitStop() {
Thread.currentThread().interrupt();
}
}

private void initiateStop() {
stopLatch = new CountDownLatch(1);
Thread stopThread = new Thread(() -> {
if (server != null) {
server.extinguish();
initLatch = new CountDownLatch(1);
}

routes.clear();
exceptionMapper.clear();
staticFilesConfiguration.clear();
Expand Down
31 changes: 30 additions & 1 deletion src/main/java/spark/Spark.java
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,35 @@ public static void secure(String keystoreFile,
getInstance().secure(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert);
}

/**
* Set the connection to be secure, using the specified keystore and
* truststore. This has to be called before any route mapping is done. You
* have to supply a keystore file, truststore file is optional (keystore
* will be reused).
* This method is only relevant when using embedded Jetty servers. It should
* not be used if you are using Servlets, where you will need to secure the
* connection in the servlet container
*
* @param keystoreFile The keystore file location as string
* @param keystorePassword the password for the keystore
* @param certAlias the default certificate Alias
* @param truststoreFile the truststore file location as string, leave null to reuse
* keystore
* @param truststorePassword the trust store password
* @param needsClientCert Whether to require client certificate to be supplied in
* request
* @param endpointIdentificationAlgorithm endpoint identification algorithm
*/
public static void secure(String keystoreFile,
String keystorePassword,
String certAlias,
String truststoreFile,
String truststorePassword,
boolean needsClientCert,
String endpointIdentificationAlgorithm) {
getInstance().secure(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert, endpointIdentificationAlgorithm);
}

/**
* Configures the embedded web server's thread pool.
*
Expand Down Expand Up @@ -1182,7 +1211,7 @@ public static void awaitInitialization() {
public static void stop() {
getInstance().stop();
}

/**
* Waits for the Spark server to be stopped.
* If it's already stopped, will return immediately.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public static ServerConnector createSecureSocketConnector(Server server,
sslContextFactory.setWantClientAuth(true);
}

// null is also an option of the endpoint identification algorithm
sslContextFactory.setEndpointIdentificationAlgorithm(sslStores.endpointIdentificationAlgorithm());

HttpConnectionFactory httpConnectionFactory = createHttpConnectionFactory();

ServerConnector connector = new ServerConnector(server, sslContextFactory, httpConnectionFactory);
Expand Down
29 changes: 24 additions & 5 deletions src/main/java/spark/ssl/SslStores.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class SslStores {
protected String truststoreFile;
protected String truststorePassword;
protected boolean needsClientCert;
protected String endpointIdentificationAlgorithm = null;

/**
* Creates a Stores instance.
Expand All @@ -42,7 +43,7 @@ public static SslStores create(String keystoreFile,
String truststoreFile,
String truststorePassword) {

return new SslStores(keystoreFile, keystorePassword, null, truststoreFile, truststorePassword, false);
return new SslStores(keystoreFile, keystorePassword, null, truststoreFile, truststorePassword, false, "HTTPS");
}

public static SslStores create(String keystoreFile,
Expand All @@ -51,7 +52,7 @@ public static SslStores create(String keystoreFile,
String truststoreFile,
String truststorePassword) {

return new SslStores(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, false);
return new SslStores(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, false, "HTTPS");
}

public static SslStores create(String keystoreFile,
Expand All @@ -60,7 +61,7 @@ public static SslStores create(String keystoreFile,
String truststorePassword,
boolean needsClientCert) {

return new SslStores(keystoreFile, keystorePassword, null, truststoreFile, truststorePassword, needsClientCert);
return new SslStores(keystoreFile, keystorePassword, null, truststoreFile, truststorePassword, needsClientCert, "HTTPS");
}

public static SslStores create(String keystoreFile,
Expand All @@ -70,21 +71,32 @@ public static SslStores create(String keystoreFile,
String truststorePassword,
boolean needsClientCert) {

return new SslStores(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert);
return new SslStores(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert, "HTTPS");
}

public static SslStores create(String keystoreFile,
String keystorePassword,
String certAlias,
String truststoreFile,
String truststorePassword,
boolean needsClientCert,
String endpointIdentificationAlgorithm) {
return new SslStores(keystoreFile, keystorePassword, certAlias, truststoreFile, truststorePassword, needsClientCert, endpointIdentificationAlgorithm);
}
private SslStores(String keystoreFile,
String keystorePassword,
String certAlias,
String truststoreFile,
String truststorePassword,
boolean needsClientCert) {
boolean needsClientCert,
String endpointIdentificationAlgorithm) {
this.keystoreFile = keystoreFile;
this.keystorePassword = keystorePassword;
this.certAlias = certAlias;
this.truststoreFile = truststoreFile;
this.truststorePassword = truststorePassword;
this.needsClientCert = needsClientCert;
this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
}

/**
Expand Down Expand Up @@ -128,4 +140,11 @@ public String trustStorePassword() {
public boolean needsClientCert() {
return needsClientCert;
}

/**
* @return endpointIdentificationAlgorithm
*/
public String endpointIdentificationAlgorithm() {
return endpointIdentificationAlgorithm;
}
}
11 changes: 6 additions & 5 deletions src/test/java/spark/ServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ public void testSecure_thenReturnNewSslStores() {
assertEquals("Should return keystorePassword from SslStores", "keypassword", sslStores.keystorePassword());
assertEquals("Should return trustStoreFile from SslStores", "truststorefile", sslStores.trustStoreFile());
assertEquals("Should return trustStorePassword from SslStores", "truststorepassword", sslStores.trustStorePassword());
assertNotNull("Should be set to HTTPS as default", sslStores.endpointIdentificationAlgorithm());
}

@Test
Expand Down Expand Up @@ -228,21 +229,21 @@ public void testWebSocket_whenInitializedTrue_thenThrowIllegalStateException() {
Whitebox.setInternalState(service, "initialized", true);
service.webSocket("/", DummyWebSocketListener.class);
}

@Test
public void testWebSocket_whenPathNull_thenThrowNullPointerException() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("WebSocket path cannot be null");
service.webSocket(null, new DummyWebSocketListener());
}

@Test
public void testWebSocket_whenHandlerNull_thenThrowNullPointerException() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("WebSocket handler class cannot be null");
service.webSocket("/", null);
}

@Test(timeout = 300)
public void stopExtinguishesServer() {
Service service = Service.ignite();
Expand All @@ -262,7 +263,7 @@ public void stopExtinguishesServer() {
}
Mockito.verify(server).extinguish();
}

@Test
public void awaitStopBlocksUntilExtinguished() {
Service service = Service.ignite();
Expand All @@ -276,7 +277,7 @@ public void awaitStopBlocksUntilExtinguished() {
Mockito.verify(server).extinguish();
assertFalse(service.initialized);
}

@WebSocket
protected static class DummyWebSocketListener {
}
Expand Down

0 comments on commit 0ff529e

Please sign in to comment.