Skip to content

Commit c3b3359

Browse files
Merge pull request #1213 from stuartwdouglas/ssl
Initial Undertow SSL config
2 parents 8571377 + 0943a0b commit c3b3359

File tree

7 files changed

+104
-39
lines changed

7 files changed

+104
-39
lines changed

core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigurationSetup.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.net.InetAddress;
99
import java.net.InetSocketAddress;
1010
import java.nio.charset.StandardCharsets;
11+
import java.nio.file.Path;
1112
import java.util.ArrayList;
1213
import java.util.Comparator;
1314
import java.util.HashMap;
@@ -67,6 +68,7 @@
6768
import io.quarkus.runtime.configuration.InetAddressConverter;
6869
import io.quarkus.runtime.configuration.InetSocketAddressConverter;
6970
import io.quarkus.runtime.configuration.NameIterator;
71+
import io.quarkus.runtime.configuration.PathConverter;
7072
import io.quarkus.runtime.configuration.RegexConverter;
7173
import io.quarkus.runtime.configuration.SimpleConfigurationProviderResolver;
7274
import io.quarkus.runtime.configuration.ssl.CipherSuiteSelectorConverter;
@@ -150,6 +152,10 @@ public void setUpConverters(BuildProducer<ConfigurationCustomConverterBuildItem>
150152
200,
151153
Protocol.class,
152154
ProtocolConverter.class));
155+
configurationTypes.produce(new ConfigurationCustomConverterBuildItem(
156+
200,
157+
Path.class,
158+
PathConverter.class));
153159
}
154160

155161
/**
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.quarkus.runtime.configuration;
2+
3+
import java.nio.file.Path;
4+
import java.nio.file.Paths;
5+
6+
import org.eclipse.microprofile.config.spi.Converter;
7+
8+
public class PathConverter implements Converter<Path> {
9+
@Override
10+
public Path convert(String value) {
11+
return Paths.get(value);
12+
}
13+
}

core/runtime/src/main/java/io/quarkus/runtime/configuration/ssl/ServerSslConfig.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@
4040
*/
4141
@ConfigGroup
4242
public class ServerSslConfig {
43-
44-
static final Logger log = Logger.getLogger("io.quarkus.configuration.ssl");
45-
46-
private static final Protocol[] NO_PROTOCOLS = new Protocol[0];
47-
private static final X509Certificate[] NO_CERTS = new X509Certificate[0];
48-
4943
/**
5044
* The server certificate configuration.
5145
*/
@@ -88,12 +82,15 @@ public class ServerSslConfig {
8882
* @throws GeneralSecurityException if something failed in the context setup
8983
*/
9084
public SSLContext toSSLContext() throws GeneralSecurityException, IOException {
85+
//TODO: static fields break config
86+
Logger log = Logger.getLogger("io.quarkus.configuration.ssl");
9187
final Optional<Path> certFile = certificate.file;
9288
final Optional<Path> keyFile = certificate.keyFile;
9389
final Optional<Path> keyStoreFile = certificate.keyStoreFile;
9490
final KeyStore keyStore;
9591
if (certFile.isPresent() && keyFile.isPresent()) {
9692
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
93+
keyStore.load(null, "password".toCharArray());
9794
final Path certPath = certFile.get();
9895
final Iterator<PemEntry<?>> certItr = Pem.parsePemContent(load(certPath));
9996
final ArrayList<X509Certificate> certList = new ArrayList<>();
@@ -129,7 +126,8 @@ public SSLContext toSSLContext() throws GeneralSecurityException, IOException {
129126
if (keyItr.hasNext()) {
130127
log.warnf("Ignoring extra content in key file \"%s\"", keyPath);
131128
}
132-
keyStore.setEntry("default", new KeyStore.PrivateKeyEntry(privateKey, certList.toArray(NO_CERTS)), null);
129+
keyStore.setEntry("default", new KeyStore.PrivateKeyEntry(privateKey, certList.toArray(new X509Certificate[0])),
130+
new KeyStore.PasswordProtection("password".toCharArray()));
133131
} else if (keyStoreFile.isPresent()) {
134132
final Path keyStorePath = keyStoreFile.get();
135133
final Optional<String> keyStoreFileType = certificate.keyStoreFileType;
@@ -157,14 +155,14 @@ public SSLContext toSSLContext() throws GeneralSecurityException, IOException {
157155
return null;
158156
}
159157
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
160-
keyManagerFactory.init(keyStore, null);
158+
keyManagerFactory.init(keyStore, "password".toCharArray());
161159
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
162160
sslContextBuilder.setCipherSuiteSelector(cipherSuites.orElse(CipherSuiteSelector.openSslDefault()));
163161
ProtocolSelector protocolSelector;
164162
if (protocols.isEmpty()) {
165163
protocolSelector = ProtocolSelector.defaultProtocols();
166164
} else {
167-
protocolSelector = ProtocolSelector.empty().add(protocols.toArray(NO_PROTOCOLS));
165+
protocolSelector = ProtocolSelector.empty().add(protocols.toArray(new Protocol[0]));
168166
}
169167
sslContextBuilder.setProtocolSelector(protocolSelector);
170168
sslContextBuilder.setKeyManager((X509ExtendedKeyManager) keyManagerFactory.getKeyManagers()[0]);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.quarkus.runtime.graal;
2+
3+
import java.lang.invoke.MethodHandle;
4+
import java.security.Principal;
5+
6+
import javax.security.auth.x500.X500Principal;
7+
8+
import org.wildfly.security.x500.util.X500PrincipalUtil;
9+
10+
import com.oracle.svm.core.annotate.Alias;
11+
import com.oracle.svm.core.annotate.Delete;
12+
import com.oracle.svm.core.annotate.RecomputeFieldValue;
13+
import com.oracle.svm.core.annotate.Substitute;
14+
import com.oracle.svm.core.annotate.TargetClass;
15+
16+
/**
17+
*
18+
*/
19+
@TargetClass(X500PrincipalUtil.class)
20+
final class Target_org_wildfly_security_x500_util_X500PrincipalUtil {
21+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)
22+
@Alias
23+
static Class<?> X500_NAME_CLASS;
24+
@Delete
25+
static MethodHandle AS_X500_PRINCIPAL_HANDLE;
26+
27+
@Substitute
28+
public static X500Principal asX500Principal(Principal principal, boolean convert) {
29+
return null;
30+
}
31+
}

extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/devmode/UndertowHotReplacementSetup.java

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
package io.quarkus.undertow.deployment.devmode;
22

3-
import java.util.OptionalInt;
4-
5-
import javax.servlet.ServletException;
6-
7-
import io.quarkus.deployment.QuarkusConfig;
83
import io.quarkus.deployment.devmode.HotReplacementContext;
94
import io.quarkus.deployment.devmode.HotReplacementSetup;
10-
import io.quarkus.runtime.LaunchMode;
11-
import io.quarkus.undertow.runtime.HttpConfig;
125
import io.quarkus.undertow.runtime.UndertowDeploymentTemplate;
136
import io.undertow.server.HandlerWrapper;
147
import io.undertow.server.HttpHandler;
@@ -25,18 +18,7 @@ public class UndertowHotReplacementSetup implements HotReplacementSetup {
2518
public void setupHotDeployment(HotReplacementContext context) {
2619
this.context = context;
2720
HandlerWrapper wrapper = createHandlerWrapper();
28-
//TODO: we need to get these values from the config in runtime mode
29-
HttpConfig config = new HttpConfig();
30-
config.port = QuarkusConfig.getInt("quarkus.http.port", "8080");
31-
config.host = QuarkusConfig.getString("quarkus.http.host", "localhost", true);
32-
config.ioThreads = OptionalInt.empty();
33-
config.workerThreads = OptionalInt.empty();
34-
35-
try {
36-
UndertowDeploymentTemplate.startUndertowEagerly(config, wrapper, LaunchMode.DEVELOPMENT);
37-
} catch (ServletException e) {
38-
throw new RuntimeException(e);
39-
}
21+
UndertowDeploymentTemplate.setHotDeployment(wrapper);
4022
}
4123

4224
private HandlerWrapper createHandlerWrapper() {

extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/HttpConfig.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.quarkus.runtime.annotations.ConfigItem;
2323
import io.quarkus.runtime.annotations.ConfigPhase;
2424
import io.quarkus.runtime.annotations.ConfigRoot;
25+
import io.quarkus.runtime.configuration.ssl.ServerSslConfig;
2526

2627
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
2728
public class HttpConfig {
@@ -32,12 +33,23 @@ public class HttpConfig {
3233
@ConfigItem(defaultValue = "8080")
3334
public int port;
3435

36+
/**
37+
* The HTTPS port
38+
*/
39+
@ConfigItem(defaultValue = "8443")
40+
public int sslPort;
41+
3542
/**
3643
* The HTTP port used to run tests
3744
*/
3845
@ConfigItem(defaultValue = "8081")
3946
public int testPort;
4047

48+
/**
49+
* The HTTPS port used to run tests
50+
*/
51+
@ConfigItem(defaultValue = "8444")
52+
public int testSslPort;
4153
/**
4254
* The HTTP host
4355
*/
@@ -58,8 +70,17 @@ public class HttpConfig {
5870
@ConfigItem
5971
public OptionalInt ioThreads;
6072

73+
/**
74+
* The SSL config
75+
*/
76+
public ServerSslConfig ssl;
77+
6178
public int determinePort(LaunchMode launchMode) {
6279
return launchMode == LaunchMode.TEST ? testPort : port;
6380
}
6481

82+
public int determineSslPort(LaunchMode launchMode) {
83+
return launchMode == LaunchMode.TEST ? testSslPort : sslPort;
84+
}
85+
6586
}

extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentTemplate.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Set;
2828
import java.util.stream.Collectors;
2929

30+
import javax.net.ssl.SSLContext;
3031
import javax.servlet.DispatcherType;
3132
import javax.servlet.Filter;
3233
import javax.servlet.MultipartConfigElement;
@@ -90,6 +91,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception {
9091
private static final String RESOURCES_PROP = "quarkus.undertow.resources";
9192

9293
private static volatile Undertow undertow;
94+
private static volatile HandlerWrapper hotDeploymentWrapper;
9395
private static volatile HttpHandler currentRoot = ResponseCodeHandler.HANDLE_404;
9496

9597
public RuntimeValue<DeploymentInfo> createDeployment(String name, Set<String> knownFile, Set<String> knownDirectories,
@@ -252,19 +254,22 @@ public void addServltInitParameter(RuntimeValue<DeploymentInfo> info, String nam
252254
}
253255

254256
public RuntimeValue<Undertow> startUndertow(ShutdownContext shutdown, DeploymentManager manager, HttpConfig config,
255-
List<HandlerWrapper> wrappers, LaunchMode launchMode) throws ServletException {
257+
List<HandlerWrapper> wrappers, LaunchMode launchMode) throws Exception {
256258

257259
if (undertow == null) {
258-
startUndertowEagerly(config, null, launchMode);
260+
SSLContext context = config.ssl.toSSLContext();
261+
doServerStart(config, launchMode, context);
259262

260-
//in development mode undertow is started eagerly
261-
shutdown.addShutdownTask(new Runnable() {
262-
@Override
263-
public void run() {
264-
undertow.stop();
265-
undertow = null;
266-
}
267-
});
263+
if (launchMode != LaunchMode.DEVELOPMENT) {
264+
//in development mode undertow should not be shut down
265+
shutdown.addShutdownTask(new Runnable() {
266+
@Override
267+
public void run() {
268+
undertow.stop();
269+
undertow = null;
270+
}
271+
});
272+
}
268273
}
269274
shutdown.addShutdownTask(new Runnable() {
270275
@Override
@@ -298,17 +303,22 @@ public void run() {
298303
return new RuntimeValue<>(undertow);
299304
}
300305

306+
public static void setHotDeployment(HandlerWrapper handlerWrapper) {
307+
hotDeploymentWrapper = handlerWrapper;
308+
}
309+
301310
/**
302311
* Used for quarkus:run, where we want undertow to start very early in the process.
303312
* <p>
304313
* This enables recovery from errors on boot. In a normal boot undertow is one of the last things start, so there would
305314
* be no chance to use hot deployment to fix the error. In development mode we start Undertow early, so any error
306315
* on boot can be corrected via the hot deployment handler
307316
*/
308-
public static void startUndertowEagerly(HttpConfig config, HandlerWrapper hotDeploymentWrapper, LaunchMode launchMode)
317+
private static void doServerStart(HttpConfig config, LaunchMode launchMode, SSLContext sslContext)
309318
throws ServletException {
310319
if (undertow == null) {
311320
int port = config.determinePort(launchMode);
321+
int sslPort = config.determineSslPort(launchMode);
312322
log.debugf("Starting Undertow on port %d", port);
313323
HttpHandler rootHandler = new CanonicalPathHandler(ROOT_HANDLER);
314324
if (hotDeploymentWrapper != null) {
@@ -329,6 +339,10 @@ public static void startUndertowEagerly(HttpConfig config, HandlerWrapper hotDep
329339
} else if (launchMode.isDevOrTest()) {
330340
builder.setWorkerThreads(6);
331341
}
342+
if (sslContext != null) {
343+
log.debugf("Starting Undertow HTTPS listener on port %d", sslPort);
344+
builder.addHttpsListener(sslPort, config.host, sslContext);
345+
}
332346
undertow = builder
333347
.build();
334348
undertow.start();

0 commit comments

Comments
 (0)