diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigurationSetup.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigurationSetup.java index bfbdb706e56eb..8af0bf78f7dfe 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigurationSetup.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/ConfigurationSetup.java @@ -8,6 +8,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -67,6 +68,7 @@ import io.quarkus.runtime.configuration.InetAddressConverter; import io.quarkus.runtime.configuration.InetSocketAddressConverter; import io.quarkus.runtime.configuration.NameIterator; +import io.quarkus.runtime.configuration.PathConverter; import io.quarkus.runtime.configuration.RegexConverter; import io.quarkus.runtime.configuration.SimpleConfigurationProviderResolver; import io.quarkus.runtime.configuration.ssl.CipherSuiteSelectorConverter; @@ -150,6 +152,10 @@ public void setUpConverters(BuildProducer 200, Protocol.class, ProtocolConverter.class)); + configurationTypes.produce(new ConfigurationCustomConverterBuildItem( + 200, + Path.class, + PathConverter.class)); } /** diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/PathConverter.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/PathConverter.java new file mode 100644 index 0000000000000..1bbc20a3cf610 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/PathConverter.java @@ -0,0 +1,13 @@ +package io.quarkus.runtime.configuration; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.microprofile.config.spi.Converter; + +public class PathConverter implements Converter { + @Override + public Path convert(String value) { + return Paths.get(value); + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ssl/ServerSslConfig.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ssl/ServerSslConfig.java index 66083657bc04f..e81a8910c2e50 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/ssl/ServerSslConfig.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/ssl/ServerSslConfig.java @@ -40,12 +40,6 @@ */ @ConfigGroup public class ServerSslConfig { - - static final Logger log = Logger.getLogger("io.quarkus.configuration.ssl"); - - private static final Protocol[] NO_PROTOCOLS = new Protocol[0]; - private static final X509Certificate[] NO_CERTS = new X509Certificate[0]; - /** * The server certificate configuration. */ @@ -88,12 +82,15 @@ public class ServerSslConfig { * @throws GeneralSecurityException if something failed in the context setup */ public SSLContext toSSLContext() throws GeneralSecurityException, IOException { + //TODO: static fields break config + Logger log = Logger.getLogger("io.quarkus.configuration.ssl"); final Optional certFile = certificate.file; final Optional keyFile = certificate.keyFile; final Optional keyStoreFile = certificate.keyStoreFile; final KeyStore keyStore; if (certFile.isPresent() && keyFile.isPresent()) { keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, "password".toCharArray()); final Path certPath = certFile.get(); final Iterator> certItr = Pem.parsePemContent(load(certPath)); final ArrayList certList = new ArrayList<>(); @@ -129,7 +126,8 @@ public SSLContext toSSLContext() throws GeneralSecurityException, IOException { if (keyItr.hasNext()) { log.warnf("Ignoring extra content in key file \"%s\"", keyPath); } - keyStore.setEntry("default", new KeyStore.PrivateKeyEntry(privateKey, certList.toArray(NO_CERTS)), null); + keyStore.setEntry("default", new KeyStore.PrivateKeyEntry(privateKey, certList.toArray(new X509Certificate[0])), + new KeyStore.PasswordProtection("password".toCharArray())); } else if (keyStoreFile.isPresent()) { final Path keyStorePath = keyStoreFile.get(); final Optional keyStoreFileType = certificate.keyStoreFileType; @@ -157,14 +155,14 @@ public SSLContext toSSLContext() throws GeneralSecurityException, IOException { return null; } final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, null); + keyManagerFactory.init(keyStore, "password".toCharArray()); final SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); sslContextBuilder.setCipherSuiteSelector(cipherSuites.orElse(CipherSuiteSelector.openSslDefault())); ProtocolSelector protocolSelector; if (protocols.isEmpty()) { protocolSelector = ProtocolSelector.defaultProtocols(); } else { - protocolSelector = ProtocolSelector.empty().add(protocols.toArray(NO_PROTOCOLS)); + protocolSelector = ProtocolSelector.empty().add(protocols.toArray(new Protocol[0])); } sslContextBuilder.setProtocolSelector(protocolSelector); sslContextBuilder.setKeyManager((X509ExtendedKeyManager) keyManagerFactory.getKeyManagers()[0]); diff --git a/core/runtime/src/main/java/io/quarkus/runtime/graal/Target_org_wildfly_security_x500_util_X500PrincipalUtil.java b/core/runtime/src/main/java/io/quarkus/runtime/graal/Target_org_wildfly_security_x500_util_X500PrincipalUtil.java new file mode 100644 index 0000000000000..81043eff3e8c0 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/graal/Target_org_wildfly_security_x500_util_X500PrincipalUtil.java @@ -0,0 +1,31 @@ +package io.quarkus.runtime.graal; + +import java.lang.invoke.MethodHandle; +import java.security.Principal; + +import javax.security.auth.x500.X500Principal; + +import org.wildfly.security.x500.util.X500PrincipalUtil; + +import com.oracle.svm.core.annotate.Alias; +import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.RecomputeFieldValue; +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; + +/** + * + */ +@TargetClass(X500PrincipalUtil.class) +final class Target_org_wildfly_security_x500_util_X500PrincipalUtil { + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) + @Alias + static Class X500_NAME_CLASS; + @Delete + static MethodHandle AS_X500_PRINCIPAL_HANDLE; + + @Substitute + public static X500Principal asX500Principal(Principal principal, boolean convert) { + return null; + } +} diff --git a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/devmode/UndertowHotReplacementSetup.java b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/devmode/UndertowHotReplacementSetup.java index 9b26487a77a6f..94add88cf0b3e 100644 --- a/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/devmode/UndertowHotReplacementSetup.java +++ b/extensions/undertow/deployment/src/main/java/io/quarkus/undertow/deployment/devmode/UndertowHotReplacementSetup.java @@ -1,14 +1,7 @@ package io.quarkus.undertow.deployment.devmode; -import java.util.OptionalInt; - -import javax.servlet.ServletException; - -import io.quarkus.deployment.QuarkusConfig; import io.quarkus.deployment.devmode.HotReplacementContext; import io.quarkus.deployment.devmode.HotReplacementSetup; -import io.quarkus.runtime.LaunchMode; -import io.quarkus.undertow.runtime.HttpConfig; import io.quarkus.undertow.runtime.UndertowDeploymentTemplate; import io.undertow.server.HandlerWrapper; import io.undertow.server.HttpHandler; @@ -25,18 +18,7 @@ public class UndertowHotReplacementSetup implements HotReplacementSetup { public void setupHotDeployment(HotReplacementContext context) { this.context = context; HandlerWrapper wrapper = createHandlerWrapper(); - //TODO: we need to get these values from the config in runtime mode - HttpConfig config = new HttpConfig(); - config.port = QuarkusConfig.getInt("quarkus.http.port", "8080"); - config.host = QuarkusConfig.getString("quarkus.http.host", "localhost", true); - config.ioThreads = OptionalInt.empty(); - config.workerThreads = OptionalInt.empty(); - - try { - UndertowDeploymentTemplate.startUndertowEagerly(config, wrapper, LaunchMode.DEVELOPMENT); - } catch (ServletException e) { - throw new RuntimeException(e); - } + UndertowDeploymentTemplate.setHotDeployment(wrapper); } private HandlerWrapper createHandlerWrapper() { diff --git a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/HttpConfig.java b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/HttpConfig.java index 964b7464e65e0..88580406f1f35 100644 --- a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/HttpConfig.java +++ b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/HttpConfig.java @@ -22,6 +22,7 @@ import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; import io.quarkus.runtime.annotations.ConfigRoot; +import io.quarkus.runtime.configuration.ssl.ServerSslConfig; @ConfigRoot(phase = ConfigPhase.RUN_TIME) public class HttpConfig { @@ -32,12 +33,23 @@ public class HttpConfig { @ConfigItem(defaultValue = "8080") public int port; + /** + * The HTTPS port + */ + @ConfigItem(defaultValue = "8443") + public int sslPort; + /** * The HTTP port used to run tests */ @ConfigItem(defaultValue = "8081") public int testPort; + /** + * The HTTPS port used to run tests + */ + @ConfigItem(defaultValue = "8444") + public int testSslPort; /** * The HTTP host */ @@ -58,8 +70,17 @@ public class HttpConfig { @ConfigItem public OptionalInt ioThreads; + /** + * The SSL config + */ + public ServerSslConfig ssl; + public int determinePort(LaunchMode launchMode) { return launchMode == LaunchMode.TEST ? testPort : port; } + public int determineSslPort(LaunchMode launchMode) { + return launchMode == LaunchMode.TEST ? testSslPort : sslPort; + } + } diff --git a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentTemplate.java b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentTemplate.java index 6e87fd9820ab8..d19952e0d81b0 100644 --- a/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentTemplate.java +++ b/extensions/undertow/runtime/src/main/java/io/quarkus/undertow/runtime/UndertowDeploymentTemplate.java @@ -27,6 +27,7 @@ import java.util.Set; import java.util.stream.Collectors; +import javax.net.ssl.SSLContext; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.MultipartConfigElement; @@ -90,6 +91,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { private static final String RESOURCES_PROP = "quarkus.undertow.resources"; private static volatile Undertow undertow; + private static volatile HandlerWrapper hotDeploymentWrapper; private static volatile HttpHandler currentRoot = ResponseCodeHandler.HANDLE_404; public RuntimeValue createDeployment(String name, Set knownFile, Set knownDirectories, @@ -252,19 +254,22 @@ public void addServltInitParameter(RuntimeValue info, String nam } public RuntimeValue startUndertow(ShutdownContext shutdown, DeploymentManager manager, HttpConfig config, - List wrappers, LaunchMode launchMode) throws ServletException { + List wrappers, LaunchMode launchMode) throws Exception { if (undertow == null) { - startUndertowEagerly(config, null, launchMode); + SSLContext context = config.ssl.toSSLContext(); + doServerStart(config, launchMode, context); - //in development mode undertow is started eagerly - shutdown.addShutdownTask(new Runnable() { - @Override - public void run() { - undertow.stop(); - undertow = null; - } - }); + if (launchMode != LaunchMode.DEVELOPMENT) { + //in development mode undertow should not be shut down + shutdown.addShutdownTask(new Runnable() { + @Override + public void run() { + undertow.stop(); + undertow = null; + } + }); + } } shutdown.addShutdownTask(new Runnable() { @Override @@ -298,6 +303,10 @@ public void run() { return new RuntimeValue<>(undertow); } + public static void setHotDeployment(HandlerWrapper handlerWrapper) { + hotDeploymentWrapper = handlerWrapper; + } + /** * Used for quarkus:run, where we want undertow to start very early in the process. *

@@ -305,10 +314,11 @@ public void run() { * be no chance to use hot deployment to fix the error. In development mode we start Undertow early, so any error * on boot can be corrected via the hot deployment handler */ - public static void startUndertowEagerly(HttpConfig config, HandlerWrapper hotDeploymentWrapper, LaunchMode launchMode) + private static void doServerStart(HttpConfig config, LaunchMode launchMode, SSLContext sslContext) throws ServletException { if (undertow == null) { int port = config.determinePort(launchMode); + int sslPort = config.determineSslPort(launchMode); log.debugf("Starting Undertow on port %d", port); HttpHandler rootHandler = new CanonicalPathHandler(ROOT_HANDLER); if (hotDeploymentWrapper != null) { @@ -329,6 +339,10 @@ public static void startUndertowEagerly(HttpConfig config, HandlerWrapper hotDep } else if (launchMode.isDevOrTest()) { builder.setWorkerThreads(6); } + if (sslContext != null) { + log.debugf("Starting Undertow HTTPS listener on port %d", sslPort); + builder.addHttpsListener(sslPort, config.host, sslContext); + } undertow = builder .build(); undertow.start();