|
6 | 6 | package io.jooby; |
7 | 7 |
|
8 | 8 | import com.typesafe.config.Config; |
| 9 | +import io.jooby.internal.SSLDefaultProvider; |
9 | 10 |
|
10 | 11 | import javax.annotation.Nonnull; |
| 12 | +import javax.annotation.Nullable; |
| 13 | +import javax.net.ssl.SSLContext; |
11 | 14 | import java.io.IOException; |
12 | 15 | import java.net.ServerSocket; |
| 16 | +import java.util.Objects; |
13 | 17 | import java.util.Optional; |
| 18 | +import java.util.ServiceLoader; |
| 19 | +import java.util.stream.Stream; |
| 20 | +import java.util.stream.StreamSupport; |
| 21 | + |
| 22 | +import static java.util.stream.Stream.concat; |
| 23 | +import static java.util.stream.StreamSupport.stream; |
14 | 24 |
|
15 | 25 | /** |
16 | 26 | * Available server options. |
@@ -75,14 +85,18 @@ public class ServerOptions { |
75 | 85 |
|
76 | 86 | private String host = "0.0.0.0"; |
77 | 87 |
|
| 88 | + private SSLOptions ssl; |
| 89 | + |
| 90 | + private Integer securePort; |
| 91 | + |
78 | 92 | /** |
79 | 93 | * Creates server options from config object. The configuration options must provided entries |
80 | 94 | * like: <code>server.port</code>, <code>server.ioThreads</code>, etc... |
81 | 95 | * |
82 | 96 | * @param conf Configuration object. |
83 | 97 | * @return Server options. |
84 | 98 | */ |
85 | | - public static @Nonnull Optional<ServerOptions> from(@Nonnull Config conf) { |
| 99 | + public static @Nonnull Optional<ServerOptions> parse(@Nonnull Config conf) { |
86 | 100 | if (conf.hasPath("server")) { |
87 | 101 | ServerOptions options = new ServerOptions(); |
88 | 102 | if (conf.hasPath("server.port")) { |
@@ -175,6 +189,23 @@ public int getPort() { |
175 | 189 | return this; |
176 | 190 | } |
177 | 191 |
|
| 192 | + public Integer getSecurePort() { |
| 193 | + return securePort; |
| 194 | + } |
| 195 | + |
| 196 | + public boolean isSSLEnabled() { |
| 197 | + return securePort != null || ssl != null; |
| 198 | + } |
| 199 | + |
| 200 | + public ServerOptions setSecurePort(Integer securePort) { |
| 201 | + if (securePort != null && securePort.intValue() == 0) { |
| 202 | + this.securePort = randomPort(); |
| 203 | + } else { |
| 204 | + this.securePort = securePort; |
| 205 | + } |
| 206 | + return this; |
| 207 | + } |
| 208 | + |
178 | 209 | /** |
179 | 210 | * Number of IO threads used by the server. Required by Netty and Undertow. |
180 | 211 | * |
@@ -347,6 +378,33 @@ public void setHost(String host) { |
347 | 378 | } |
348 | 379 | } |
349 | 380 |
|
| 381 | + public @Nullable SSLOptions getSsl() { |
| 382 | + return ssl; |
| 383 | + } |
| 384 | + |
| 385 | + public ServerOptions setSsl(@Nullable SSLOptions ssl) { |
| 386 | + this.ssl = ssl; |
| 387 | + return this; |
| 388 | + } |
| 389 | + |
| 390 | + public @Nullable SSLContext getSSLContext() { |
| 391 | + if (isSSLEnabled()) { |
| 392 | + setSecurePort(Optional.ofNullable(securePort).orElse(8443)); |
| 393 | + setSsl(Optional.ofNullable(ssl).orElseGet(SSLOptions::pkcs12)); |
| 394 | + SSLOptions options = getSsl(); |
| 395 | + SSLContextProvider provider = concat( |
| 396 | + stream(ServiceLoader.load(SSLContextProvider.class).spliterator(), false), |
| 397 | + Stream.of(new SSLDefaultProvider()) |
| 398 | + ) |
| 399 | + .filter(it -> it.supports(options.getType())) |
| 400 | + .findFirst() |
| 401 | + .orElseThrow( |
| 402 | + () -> new UnsupportedOperationException("KeyStore: " + options.getType())); |
| 403 | + return provider.create(ServerOptions.class.getClassLoader(), options); |
| 404 | + } |
| 405 | + return null; |
| 406 | + } |
| 407 | + |
350 | 408 | private int randomPort() { |
351 | 409 | try (ServerSocket socket = new ServerSocket(0)) { |
352 | 410 | return socket.getLocalPort(); |
|
0 commit comments