diff --git a/docs/security.md b/docs/security.md index 0649c076b8d..613645f719c 100644 --- a/docs/security.md +++ b/docs/security.md @@ -44,3 +44,44 @@ The signature algorithm which Gravitino supports is as below: | PS256 | RSASSA-PSS using SHA-256 and MGF1 with SHA-256 | | PS384 | RSASSA-PSS using SHA-384 and MGF1 with SHA-384 | | PS512 | RSASSA-PSS using SHA-512 and MGF1 with SHA-512 | + +## HTTPS configuration +Users would better use HTTPS instead of HTTP if users choose OAuth 2.0 as the authenticator. +Because HTTPS will protect the header of request from smuggling and HTTPS will be safer. +If users choose to enable HTTPS, Gravitino won't provide the ability of HTTP service. +Both Gravitino server and Iceberg REST service can configure HTTPS. + +### Gravitino server's configuration +| Configuration item | Description | Default value | Since version | +|-----------------------------------------------------|------------------------------------------------------------|---------------|---------------| +| `gravitino.server.webserver.enableHttps` | Enables https | `false` | 0.3.0 | +| `gravitino.server.webserver.httpsPort` | The https port number of the Jetty web server | `8433` | 0.3.0 | +| `gravitino.server.webserver.keyStorePath` | Path to the key store file | `` | 0.3.0 | +| `gravitino.server.webserver.keyStorePassword` | Password to the key store | `` | 0.3.0 | +| `gravitino.server.webserver.keyStoreType` | The type to the key store | `JKS` | 0.3.0 | +| `gravitino.server.webserver.managerPassword` | Manager password to the key store | `` | 0.3.0 | +| `gravitino.server.webserver.tlsProtocol` | TLS protocol to use. The protocol must be supported by JVM | none | 0.3.0 | +| `gravitino.server.webserver.enableCipherAlgorithms` | The collection of the cipher algorithms which are enabled. | `` | 0.3.0 | +| `gravitino.server.webserver.enableClientAuth` | Enables the authentication of the client | `false` | 0.3.0 | +| `gravitino.server.webserver.trustStorePath` | Path to the trust store file | `` | 0.3.0 | +| `gravitino.server.webserver.trustStorePassword` | Password to the trust store | `` | 0.3.0 | +| `gravitino.server.webserver.trustStoreType` | The type to the trust store | `JKS` | 0.3.0 | + +### Iceberg REST service's configuration +| Configuration item | Description | Default value | Since version | +|------------------------------------------------------------|------------------------------------------------------------|---------------|---------------| +| `gravitino.auxService.iceberg-rest.enableHttps` | Enables https | `false` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.httpsPort` | The https port number of the Jetty web server | `8433` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.keyStorePath` | Path to the key store file | `` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.keyStorePassword` | Password to the key store | `` | 0.3.0 | +| `gravitino.uxService.iceberg-rest.keyStoreType` | The type to the key store | `JKS` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.managerPassword` | Manager password to the key store | `` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.tlsProtocol` | TLS protocol to use. The protocol must be supported by JVM | none | 0.3.0 | +| `gravitino.auxService.iceberg-rest.enableCipherAlgorithms` | The collection of the cipher algorithms which are enabled | `` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.enableClientAuth` | Enables the authentication of the client | `false` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.trustStorePath` | Path to the trust store file | `` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.trustStorePassword` | Password to the trust store | `` | 0.3.0 | +| `gravitino.auxService.iceberg-rest.trustStoreType` | The type to the trust store | `JKS` | 0.3.0 | + +About `tlsProtocol`, the reference list of protocols can be found in the "Additional JSSE Standard Names" section of the Java security guide. The list for Java 8 can be found at [this](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#jssenames). +About `enableCipherAlgorithms`, the reference list of protocols can be found in the "JSSE Cipher Suite Names" section of the Java security guide. The list for Java 8 can be found at [this](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#ciphersuites) \ No newline at end of file diff --git a/integration-test/src/test/java/com/datastrato/gravitino/integration/test/web/rest/AuthenticationOperationsIT.java b/integration-test/src/test/java/com/datastrato/gravitino/integration/test/web/rest/AuthenticationOperationsIT.java index 5486144b989..a089802bf07 100644 --- a/integration-test/src/test/java/com/datastrato/gravitino/integration/test/web/rest/AuthenticationOperationsIT.java +++ b/integration-test/src/test/java/com/datastrato/gravitino/integration/test/web/rest/AuthenticationOperationsIT.java @@ -54,6 +54,7 @@ public static void startIntegrationTest() throws Exception { configs.put(OAuthConfig.DEFAULT_SIGN_KEY.getKey(), publicKey); configs.put(OAuthConfig.ALLOW_SKEW_SECONDS.getKey(), "6"); configs.put(AuthConstants.HTTP_HEADER_AUTHORIZATION, token); + registerCustomConfigs(configs); AbstractIT.startIntegrationTest(); } diff --git a/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServer.java b/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServer.java index 2a35194ec40..d162bb4484c 100644 --- a/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServer.java +++ b/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServer.java @@ -8,6 +8,7 @@ import com.codahale.metrics.servlets.MetricsServlet; import com.datastrato.gravitino.GravitinoEnv; import com.datastrato.gravitino.metrics.MetricsSystem; +import com.google.common.base.Preconditions; import java.io.File; import java.io.IOException; import java.net.BindException; @@ -16,15 +17,20 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.EnumSet; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.Servlet; +import org.apache.commons.lang3.StringUtils; import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.servlet.DefaultServlet; @@ -32,6 +38,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; @@ -44,6 +51,9 @@ public final class JettyServer { private static final Logger LOG = LoggerFactory.getLogger(JettyServer.class); + private static final String HTTPS = "https"; + private static final String HTTP_PROTOCOL = "http/1.1"; + private Server server; private ServletContextHandler servletContextHandler; @@ -76,18 +86,56 @@ public synchronized void initialize( errorHandler.setServer(server); server.addBean(errorHandler); - // Create and set Http ServerConnector - ServerConnector httpConnector = - createHttpServerConnector( - server, - serverConfig.getRequestHeaderSize(), - serverConfig.getResponseHeaderSize(), - serverConfig.getHost(), - serverConfig.getHttpPort(), - serverConfig.getIdleTimeout()); - server.addConnector(httpConnector); - - // TODO. Create and set https connector @jerry + if (serverConfig.isEnableHttps()) { + // Create and set Https ServerConnector + Preconditions.checkArgument( + StringUtils.isNotBlank(serverConfig.getKeyStorePath()), + "If enables https, must set keyStorePath"); + Preconditions.checkArgument( + StringUtils.isNotBlank(serverConfig.getKeyStorePassword()), + "If enables https, must set keyStorePassword"); + Preconditions.checkArgument( + StringUtils.isNotBlank(serverConfig.getManagerPassword()), + "If enables https, must set managerPassword"); + if (serverConfig.isEnableClientAuth()) { + Preconditions.checkArgument( + StringUtils.isNotBlank(serverConfig.getTrustStorePath()), + "If enables the authentication of the client, must set trustStorePath"); + Preconditions.checkArgument( + StringUtils.isNotBlank(serverConfig.getTrustStorePasword()), + "If enables the authentication of the client, must set trustStorePassword"); + } + ServerConnector httpsConnector = + createHttpsServerConnector( + server, + serverConfig.getRequestHeaderSize(), + serverConfig.getResponseHeaderSize(), + serverConfig.getHost(), + serverConfig.getHttpsPort(), + serverConfig.getIdleTimeout(), + serverConfig.getKeyStorePath(), + serverConfig.getKeyStorePassword(), + serverConfig.getManagerPassword(), + serverConfig.getKeyStoreType(), + serverConfig.getTlsProtocol(), + serverConfig.getSupportedAlgorithms(), + serverConfig.isEnableClientAuth(), + serverConfig.getTrustStorePath(), + serverConfig.getTrustStorePasword(), + serverConfig.getTrustStoreType()); + server.addConnector(httpsConnector); + } else { + // Create and set Http ServerConnector + ServerConnector httpConnector = + createHttpServerConnector( + server, + serverConfig.getRequestHeaderSize(), + serverConfig.getResponseHeaderSize(), + serverConfig.getHost(), + serverConfig.getHttpPort(), + serverConfig.getIdleTimeout()); + server.addConnector(httpConnector); + } // Initialize ServletContextHandler or WebAppContext if (shouldEnableUI) { @@ -127,11 +175,12 @@ public synchronized void start() throws RuntimeException { throw new RuntimeException("Failed to start " + serverName + " web server.", e); } + if (!serverConfig.isEnableHttps()) { + LOG.warn("Users would better use HTTPS to void token data leak."); + } + LOG.info( - "{} web server started on host {} port {}.", - serverName, - serverConfig.getHost(), - serverConfig.getHttpPort()); + "{} web server started on host {} port {}.", serverName, serverConfig.getHost(), getPort()); } public synchronized void join() { @@ -162,7 +211,7 @@ public synchronized void stop() { "{} web server stopped on host {} port {}.", serverName, serverConfig.getHost(), - serverConfig.getHttpPort()); + getPort()); } catch (Exception e) { // Swallow the exception. LOG.warn("Failed to stop {} web server.", serverName, e); @@ -260,7 +309,7 @@ private ServerConnector createHttpServerConnector( HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(httpConfig); ServerConnector connector = - creatorServerConnector(server, new ConnectionFactory[] {httpConnectionFactory}); + createServerConnector(server, new ConnectionFactory[] {httpConnectionFactory}); connector.setHost(host); connector.setPort(port); connector.setReuseAddress(true); @@ -268,7 +317,69 @@ private ServerConnector createHttpServerConnector( return connector; } - private ServerConnector creatorServerConnector( + private int getPort() { + if (serverConfig.isEnableHttps()) { + return serverConfig.getHttpsPort(); + } else { + return serverConfig.getHttpPort(); + } + } + + private ServerConnector createHttpsServerConnector( + Server server, + int reqHeaderSize, + int respHeaderSize, + String host, + int port, + int idleTimeout, + String keyStorePath, + String keyStorePassword, + String keyManagerPassword, + String keyStoreType, + Optional tlsProtocol, + Set supportedAlgorithms, + boolean isEnableClientAuth, + String trustStorePath, + String trustStorePassword, + String trustStoreType) { + HttpConfiguration httpConfig = new HttpConfiguration(); + httpConfig.setSecureScheme(HTTPS); + httpConfig.setRequestHeaderSize(reqHeaderSize); + httpConfig.setResponseHeaderSize(respHeaderSize); + httpConfig.setSendServerVersion(true); + httpConfig.setIdleTimeout(idleTimeout); + httpConfig.setSecurePort(port); + + SslContextFactory sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setKeyStorePath(keyStorePath); + sslContextFactory.setKeyStorePassword(keyStorePassword); + sslContextFactory.setKeyManagerPassword(keyManagerPassword); + sslContextFactory.setKeyStoreType(keyStoreType); + tlsProtocol.ifPresent(sslContextFactory::setProtocol); + if (!supportedAlgorithms.isEmpty()) { + sslContextFactory.setIncludeCipherSuites(supportedAlgorithms.toArray(new String[0])); + } + if (isEnableClientAuth) { + sslContextFactory.setNeedClientAuth(true); + sslContextFactory.setTrustStorePath(trustStorePath); + sslContextFactory.setTrustStorePassword(trustStorePassword); + sslContextFactory.setTrustStoreType(trustStoreType); + } + SecureRequestCustomizer src = new SecureRequestCustomizer(); + httpConfig.addCustomizer(src); + HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(httpConfig); + SslConnectionFactory sslConnectionFactory = + new SslConnectionFactory(sslContextFactory, HTTP_PROTOCOL); + ServerConnector connector = + createServerConnector( + server, new ConnectionFactory[] {sslConnectionFactory, httpConnectionFactory}); + connector.setHost(host); + connector.setPort(port); + connector.setReuseAddress(true); + return connector; + } + + private ServerConnector createServerConnector( Server server, ConnectionFactory[] connectionFactories) { Scheduler serverExecutor = new ScheduledExecutorScheduler(serverName + "-webserver-JettyScheduler", true); diff --git a/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServerConfig.java b/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServerConfig.java index 7f695150d9e..8d39ba39a23 100644 --- a/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServerConfig.java +++ b/server-common/src/main/java/com/datastrato/gravitino/server/web/JettyServerConfig.java @@ -8,12 +8,20 @@ import com.datastrato.gravitino.config.ConfigBuilder; import com.datastrato.gravitino.config.ConfigEntry; import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; import java.util.Map; +import java.util.Optional; +import java.util.Set; +import javax.net.ssl.SSLContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class JettyServerConfig { private static final Logger LOG = LoggerFactory.getLogger(JettyServerConfig.class); + private static final String SPLITTER = ","; public static final ConfigEntry WEBSERVER_HOST = new ConfigBuilder("host") @@ -79,6 +87,89 @@ public final class JettyServerConfig { .intConf() .createWithDefault(100); + public static final ConfigEntry ENABLE_HTTPS = + new ConfigBuilder("enableHttps") + .doc("Enables https") + .version("0.3.0") + .booleanConf() + .createWithDefault(false); + + public static final ConfigEntry WEBSERVER_HTTPS_PORT = + new ConfigBuilder("httpsPort") + .doc("The https port number of the Jetty web server") + .version("0.3.0") + .intConf() + .createWithDefault(8433); + + public static final ConfigEntry SSL_KEYSTORE_PATH = + new ConfigBuilder("keyStorePath") + .doc("Path to the key store file") + .version("0.3.0") + .stringConf() + .createWithDefault(""); + + public static final ConfigEntry SSL_KEYSTORE_PASSWORD = + new ConfigBuilder("keyStorePassword") + .doc("Password to the key store") + .version("0.3.0") + .stringConf() + .createWithDefault(""); + + public static final ConfigEntry SSL_MANAGER_PASSWORD = + new ConfigBuilder("managerPassword") + .doc("Manager password to the key store") + .version("0.3.0") + .stringConf() + .createWithDefault(""); + + public static final ConfigEntry SSL_KEYSTORE_TYPE = + new ConfigBuilder("keyStoreType") + .doc("The type to the key store") + .version("0.3.0") + .stringConf() + .createWithDefault("JKS"); + + public static final ConfigEntry> SSL_PROTOCOL = + new ConfigBuilder("tlsProtocol") + .doc("TLS protocol to use. The protocol must be supported by JVM") + .version("0.3.0") + .stringConf() + .createWithOptional(); + public static final ConfigEntry ENABLE_CIPHER_ALGORITHMS = + new ConfigBuilder("enableCipherAlgorithms") + .doc("The collection of the cipher algorithms are enabled ") + .version("0.3.0") + .stringConf() + .createWithDefault(""); + + public static final ConfigEntry ENABLE_CLIENT_AUTH = + new ConfigBuilder("enableClientAuth") + .doc("Enables the authentication of the client") + .version("0.3.0") + .booleanConf() + .createWithDefault(false); + + public static final ConfigEntry SSL_TRUST_STORE_PATH = + new ConfigBuilder("trustStorePath") + .doc("Path to the trust store file") + .version("0.3.0") + .stringConf() + .createWithDefault(""); + + public static final ConfigEntry SSL_TRUST_STORE_PASSWORD = + new ConfigBuilder("trustStorePassword") + .doc("Password to the trust store") + .version("0.3.0") + .stringConf() + .createWithDefault(""); + + public static final ConfigEntry SSL_TRUST_STORE_TYPE = + new ConfigBuilder("trustStoreType") + .doc("The type to the trust store") + .version("0.3.0") + .stringConf() + .createWithDefault("JKS"); + private final String host; private final int httpPort; @@ -97,6 +188,18 @@ public final class JettyServerConfig { private final int threadPoolWorkQueueSize; + private final int httpsPort; + private final String keyStorePath; + private final String keyStorePassword; + private final String managerPassword; + private final boolean enableHttps; + private final String keyStoreType; + private final Optional tlsProtocol; + private final Set enableCipherAlgorithms; + private final boolean enableClientAuth; + private final String trustStorePath; + private final String trustStorePasword; + private final String trustStoreType; private final Config internalConfig; private JettyServerConfig(Map configs) { @@ -128,6 +231,21 @@ private JettyServerConfig(Map configs) { this.requestHeaderSize = internalConfig.get(WEBSERVER_REQUEST_HEADER_SIZE); this.responseHeaderSize = internalConfig.get(WEBSERVER_RESPONSE_HEADER_SIZE); this.threadPoolWorkQueueSize = internalConfig.get(WEBSERVER_THREAD_POOL_WORK_QUEUE_SIZE); + + this.enableHttps = internalConfig.get(ENABLE_HTTPS); + this.httpsPort = internalConfig.get(WEBSERVER_HTTPS_PORT); + this.keyStorePath = internalConfig.get(SSL_KEYSTORE_PATH); + this.keyStorePassword = internalConfig.get(SSL_KEYSTORE_PASSWORD); + this.managerPassword = internalConfig.get(SSL_MANAGER_PASSWORD); + this.keyStoreType = internalConfig.get(SSL_KEYSTORE_TYPE); + this.tlsProtocol = internalConfig.get(SSL_PROTOCOL); + this.enableCipherAlgorithms = + Collections.unmodifiableSet( + Sets.newHashSet(internalConfig.get(ENABLE_CIPHER_ALGORITHMS).split(SPLITTER))); + this.enableClientAuth = internalConfig.get(ENABLE_CLIENT_AUTH); + this.trustStorePath = internalConfig.get(SSL_TRUST_STORE_PATH); + this.trustStorePasword = internalConfig.get(SSL_TRUST_STORE_PASSWORD); + this.trustStoreType = internalConfig.get(SSL_TRUST_STORE_TYPE); } public static JettyServerConfig fromConfig(Config config, String prefix) { @@ -174,4 +292,81 @@ public int getThreadPoolWorkQueueSize() { public int getIdleTimeout() { return idleTimeout; } + + public int getHttpsPort() { + return httpsPort; + } + + public String getKeyStorePath() { + return keyStorePath; + } + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public String getManagerPassword() { + return managerPassword; + } + + public boolean isEnableHttps() { + return enableHttps; + } + + public String getKeyStoreType() { + return keyStoreType; + } + + public Optional getTlsProtocol() { + return tlsProtocol; + } + + public boolean isEnableClientAuth() { + return enableClientAuth; + } + + public String getTrustStorePath() { + return trustStorePath; + } + + public String getTrustStorePasword() { + return trustStorePasword; + } + + public String getTrustStoreType() { + return trustStoreType; + } + + private SSLContext getDefaultSSLContext() { + try { + return SSLContext.getDefault(); + } catch (NoSuchAlgorithmException nsa) { + return null; + } + } + + private SSLContext getSSLContextInstance(String protocol) { + try { + SSLContext context = SSLContext.getInstance(protocol); + context.init(null, null, null); + return context; + } catch (NoSuchAlgorithmException | KeyManagementException e) { + return null; + } + } + + public Set getSupportedAlgorithms() { + if (enableCipherAlgorithms.isEmpty()) { + return Collections.emptySet(); + } + SSLContext context = + tlsProtocol.map(this::getSSLContextInstance).orElseGet(this::getDefaultSSLContext); + if (context == null) { + return Collections.emptySet(); + } + Set supportedAlgorithms = Sets.newHashSet(enableCipherAlgorithms); + supportedAlgorithms.retainAll( + Sets.newHashSet(context.getServerSocketFactory().getSupportedCipherSuites())); + return supportedAlgorithms; + } } diff --git a/server-common/src/test/java/com/datastrato/gravitino/server/web/TestJettyServerConfig.java b/server-common/src/test/java/com/datastrato/gravitino/server/web/TestJettyServerConfig.java new file mode 100644 index 00000000000..434a7303f32 --- /dev/null +++ b/server-common/src/test/java/com/datastrato/gravitino/server/web/TestJettyServerConfig.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 Datastrato. + * This software is licensed under the Apache License version 2. + */ +package com.datastrato.gravitino.server.web; + +import com.datastrato.gravitino.Config; +import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TestJettyServerConfig { + + @Test + public void testCipherAlgorithms() { + Config noIntersectConfig = new Config() {}; + noIntersectConfig.set(JettyServerConfig.ENABLE_CIPHER_ALGORITHMS, "test1,test2"); + JettyServerConfig jettyServerConfig = JettyServerConfig.fromConfig(noIntersectConfig, ""); + + Assertions.assertIterableEquals( + Collections.emptySet(), jettyServerConfig.getSupportedAlgorithms()); + Config containConfig = new Config() {}; + containConfig.set(JettyServerConfig.ENABLE_CIPHER_ALGORITHMS, "TLS_AES_256_GCM_SHA384"); + jettyServerConfig = JettyServerConfig.fromConfig(containConfig, ""); + Assertions.assertIterableEquals( + Sets.newHashSet("TLS_AES_256_GCM_SHA384"), jettyServerConfig.getSupportedAlgorithms()); + Config partConfig = new Config() {}; + partConfig.set(JettyServerConfig.ENABLE_CIPHER_ALGORITHMS, "TLS_AES_256_GCM_SHA384,test1"); + jettyServerConfig = JettyServerConfig.fromConfig(partConfig, ""); + Assertions.assertIterableEquals( + Sets.newHashSet("TLS_AES_256_GCM_SHA384"), jettyServerConfig.getSupportedAlgorithms()); + + Config protocolConfig = new Config() {}; + protocolConfig.set(JettyServerConfig.SSL_PROTOCOL, Optional.of("TLS")); + protocolConfig.set(JettyServerConfig.ENABLE_CIPHER_ALGORITHMS, "TLS_AES_256_GCM_SHA384,test1"); + jettyServerConfig = JettyServerConfig.fromConfig(protocolConfig, ""); + Assertions.assertIterableEquals( + Sets.newHashSet("TLS_AES_256_GCM_SHA384"), jettyServerConfig.getSupportedAlgorithms()); + } +}