Skip to content

Commit

Permalink
CXF-9039: Support SeBootstrap HTTPS configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
reta committed Dec 26, 2024
1 parent 9164d67 commit 624a5fb
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.cxf.configuration.jsse;

import java.util.Arrays;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

/**
* Allows to supply to the HTTP Server the complete SSLContext already preconfigured.
*/
public class SSLContextServerParameters extends TLSServerParameters {
private final SSLContext sslContext;

public SSLContextServerParameters(SSLContext sslContext) {
this.sslContext = sslContext;
setSecureSocketProtocol(sslContext.getProtocol());
setJsseProvider(sslContext.getProvider().getName());
setCipherSuites(Arrays.asList(sslContext.getServerSocketFactory().getSupportedCipherSuites()));
}

public SSLContext getSslContext() {
return sslContext;
}

@Override
public TrustManager[] getTrustManagers() {
throw new UnsupportedOperationException("The operation is not supported by SSLContextServerParameters");
}

@Override
public KeyManager[] getKeyManagers() {
throw new UnsupportedOperationException("The operation is not supported by SSLContextServerParameters");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

Expand All @@ -49,17 +50,22 @@
import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.Variant.VariantListBuilder;
import jakarta.ws.rs.ext.RuntimeDelegate;
import org.apache.cxf.Bus;
import org.apache.cxf.configuration.jsse.SSLContextServerParameters;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.configuration.security.ClientAuthentication;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.bootstrap.ConfigurationBuilderImpl;
import org.apache.cxf.jaxrs.bootstrap.InstanceImpl;
import org.apache.cxf.jaxrs.utils.ResourceUtils;
import org.apache.cxf.transport.http.HTTPServerEngineFactoryParametersProvider;

public class RuntimeDelegateImpl extends RuntimeDelegate {
// The default value is implementation specific, using non-priviledged default port
// The default value is implementation specific, using non-priviledged default ports
private static final int DEFAULT_HTTP_PORT = 8080;
private static final int DEFAULT_HTTPS_PORT = 8443;

protected Map<Class<?>, HeaderDelegate<?>> headerProviders = new HashMap<>();

public RuntimeDelegateImpl() {
Expand Down Expand Up @@ -155,16 +161,19 @@ public CompletionStage<Instance> bootstrap(Application application, Configuratio
instanceConfigurationBuilder = instanceConfigurationBuilder.host("localhost");
}

String protocol = "HTTP";
if (!configuration.hasProperty(Configuration.PROTOCOL)) { // The default value is "HTTP"
instanceConfigurationBuilder = instanceConfigurationBuilder.protocol("HTTP");
instanceConfigurationBuilder = instanceConfigurationBuilder.protocol(protocol);
} else if (configuration.property(Configuration.PROTOCOL) instanceof String p) {
protocol = p;
}

if (!configuration.hasProperty(Configuration.PORT)) {
instanceConfigurationBuilder = instanceConfigurationBuilder.port(DEFAULT_HTTP_PORT);
instanceConfigurationBuilder = instanceConfigurationBuilder.port(getDefaultPort(protocol));
} else if (configuration.port() == Configuration.FREE_PORT) {
instanceConfigurationBuilder = instanceConfigurationBuilder.port(findFreePort()); /* free port */
} else if (configuration.port() == Configuration.DEFAULT_PORT) {
instanceConfigurationBuilder = instanceConfigurationBuilder.port(DEFAULT_HTTP_PORT);
instanceConfigurationBuilder = instanceConfigurationBuilder.port(getDefaultPort(protocol));
}

if (!configuration.hasProperty(Configuration.ROOT_PATH)) { // The default value is "/"
Expand All @@ -177,8 +186,11 @@ public CompletionStage<Instance> bootstrap(Application application, Configuratio
factory.setStart(true);

if ("https".equalsIgnoreCase(configuration.protocol())) {
final TLSServerParameters parameters = new TLSServerParameters();
final SSLContext sslContext = configuration.sslContext();

final TLSServerParameters parameters = (sslContext != null)
? new SSLContextServerParameters(sslContext) : new TLSServerParameters();

final SSLClientAuthentication sslClientAuthentication = configuration.sslClientAuthentication();
if (sslClientAuthentication != null) {
final ClientAuthentication clientAuthentication = new ClientAuthentication();
Expand All @@ -192,12 +204,17 @@ public CompletionStage<Instance> bootstrap(Application application, Configuratio
parameters.setClientAuthentication(clientAuthentication);
}

final SSLContext sslContext = configuration.sslContext();
if (sslContext != null) {
parameters.setSecureSocketProtocol(sslContext.getProtocol());
}

// TODO: Support SSL context propagation down to HTTP engine
factory.getBus().setExtension(new HTTPServerEngineFactoryParametersProvider() {
@Override
public Optional<TLSServerParameters> getDefaultTlsServerParameters(Bus bus, String host,
int port, String protocol, String id) {
if ("https".equalsIgnoreCase(protocol) && port == instanceConfiguration.port()) {
return Optional.of(parameters);
} else {
return Optional.empty();
}
}
}, HTTPServerEngineFactoryParametersProvider.class);
}

return CompletableFuture
Expand Down Expand Up @@ -227,6 +244,10 @@ public Application run() throws Exception {
public EntityPart.Builder createEntityPartBuilder(String partName) throws IllegalArgumentException {
return new EntityPartBuilderImpl(partName);
}

private static int getDefaultPort(String protocol) {
return (protocol.equalsIgnoreCase("http")) ? DEFAULT_HTTP_PORT : DEFAULT_HTTPS_PORT;
}

@SuppressWarnings({ "removal", "deprecation" })
private static int findFreePort() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void setServletContext(ServletContext sc) {
}

/**
* Post-configure retreival of server engine.
* Post-configure retrieval of server engine.
*/
protected void retrieveEngine()
throws GeneralSecurityException,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.apache.cxf.common.util.ReflectionUtil;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.common.util.SystemPropertyAction;
import org.apache.cxf.configuration.jsse.SSLContextServerParameters;
import org.apache.cxf.configuration.jsse.SSLUtils;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.configuration.security.ClientAuthentication;
Expand Down Expand Up @@ -854,6 +855,11 @@ public Connection upgradeConnection(Connector c, EndPoint endPoint,
return result;
}
protected SSLContext createSSLContext(SslContextFactory scf) throws Exception {
// The full SSL context is provided by SSLContextServerParameters
if (tlsServerParameters instanceof SSLContextServerParameters sslContextServerParameters) {
return sslContextServerParameters.getSslContext();
}

String proto = tlsServerParameters.getSecureSocketProtocol() == null
? "TLS" : tlsServerParameters.getSecureSocketProtocol();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.management.InstrumentationManager;
import org.apache.cxf.transport.http.HTTPServerEngineFactoryParametersProvider;
import org.eclipse.jetty.util.component.Container;


Expand Down Expand Up @@ -265,6 +266,15 @@ public synchronized JettyHTTPServerEngine createJettyHTTPServerEngine(String hos
if (id != null && tlsParametersMap != null && tlsParametersMap.containsKey(id)) {
tlsParameters = tlsParametersMap.get(id);
}

if (tlsParameters == null) {
final HTTPServerEngineFactoryParametersProvider provider =
bus.getExtension(HTTPServerEngineFactoryParametersProvider.class);
if (provider != null) {
tlsParameters = provider.getDefaultTlsServerParameters(bus, host, port, protocol, id).orElse(null);
}
}

JettyHTTPServerEngine ref = getOrCreate(this, host, port, tlsParameters);
// checking the protocol
if (!protocol.equals(ref.getProtocol())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.cxf.common.injection.NoJSR250Annotations;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.transport.http.HTTPServerEngineFactoryParametersProvider;


@NoJSR250Annotations(unlessNull = "bus")
Expand Down Expand Up @@ -176,6 +177,17 @@ public synchronized NettyHttpServerEngine createNettyHttpServerEngine(String hos
if ("https".equals(protocol) && tlsServerParametersMap != null) {
tlsServerParameters = tlsServerParametersMap.get(Integer.toString(port));
}

if (tlsServerParameters == null) {
final HTTPServerEngineFactoryParametersProvider provider =
bus.getExtension(HTTPServerEngineFactoryParametersProvider.class);
if (provider != null) {
tlsServerParameters = provider
.getDefaultTlsServerParameters(bus, host, port, protocol, null)
.orElse(null);
}
}

NettyHttpServerEngine ref = getOrCreate(this, host, port, tlsServerParameters);
// checking the protocol
if (!protocol.equals(ref.getProtocol())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.PropertyUtils;
import org.apache.cxf.common.util.SystemPropertyAction;
import org.apache.cxf.configuration.jsse.SSLContextServerParameters;
import org.apache.cxf.configuration.jsse.SSLUtils;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.interceptor.Fault;
Expand Down Expand Up @@ -512,6 +513,11 @@ private boolean shouldDestroyPort() {


protected SSLContext createSSLContext() throws Exception {
// The full SSL context is provided by SSLContextServerParameters
if (tlsServerParameters instanceof SSLContextServerParameters sslContextServerParameters) {
return sslContextServerParameters.getSslContext();
}

String proto = tlsServerParameters.getSecureSocketProtocol() == null
? "TLS" : tlsServerParameters.getSecureSocketProtocol();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.management.InstrumentationManager;
import org.apache.cxf.transport.http.HTTPServerEngineFactoryParametersProvider;



Expand Down Expand Up @@ -263,6 +264,15 @@ public synchronized UndertowHTTPServerEngine createUndertowHTTPServerEngine(Stri
if (id != null && tlsParametersMap != null && tlsParametersMap.containsKey(id)) {
tlsParameters = tlsParametersMap.get(id);
}

if (tlsParameters == null) {
final HTTPServerEngineFactoryParametersProvider provider =
bus.getExtension(HTTPServerEngineFactoryParametersProvider.class);
if (provider != null) {
tlsParameters = provider.getDefaultTlsServerParameters(bus, host, port, protocol, id).orElse(null);
}
}

UndertowHTTPServerEngine ref = getOrCreate(this, host, port, tlsParameters);
// checking the protocol
if (!protocol.equals(ref.getProtocol())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.cxf.transport.http;

import java.util.Optional;

import jakarta.annotation.Nullable;
import org.apache.cxf.Bus;
import org.apache.cxf.configuration.jsse.TLSServerParameters;

/**
* Provides programmatic defaults to the different HTTP server engine
* factories implementations (that do not share any common interfaces or other
* abstractions).
*/
public interface HTTPServerEngineFactoryParametersProvider {
/**
* Returns the default {@link TLSServerParameters} instance that the HTTP server
* engine could use if there are no {@link TLSServerParameters} provided to by the
* configuration.
* @param bus {@link Bus} instance
* @param host host name
* @param port port
* @param protocol protocol
* @param id server transport identifier (if available)
* @return the default {@link TLSServerParameters} instance, if available
*/
Optional<TLSServerParameters> getDefaultTlsServerParameters(Bus bus, String host,
int port, String protocol, @Nullable String id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import javax.net.ssl.X509TrustManager;

import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.jsse.SSLContextServerParameters;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.jsse.TLSParameterBase;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
Expand Down Expand Up @@ -123,7 +124,7 @@ public static SSLContext getSSLContext(TLSParameterBase parameters, boolean addH
HostnameVerifier hnv = getHostnameVerifier((TLSClientParameters)parameters);
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
tms[i] = new X509TrustManagerWrapper((X509TrustManager)tms[i], hnv);
tms[i] = new X509TrustManagerWrapper((X509TrustManager)tms[i], hnv);
}
}
}
Expand Down Expand Up @@ -160,7 +161,14 @@ public static KeyManager[] configureKeyManagersWithCertAlias(TLSParameterBase tl
}

public static SSLEngine createServerSSLEngine(TLSServerParameters parameters) throws Exception {
SSLContext sslContext = getSSLContext(parameters);
SSLContext sslContext = null;
// The full SSL context is provided by SSLContextServerParameters
if (parameters instanceof SSLContextServerParameters sslContextServerParameters) {
sslContext = sslContextServerParameters.getSslContext();
} else {
sslContext = getSSLContext(parameters);
}

SSLEngine serverEngine = sslContext.createSSLEngine();
serverEngine.setUseClientMode(false);
serverEngine.setNeedClientAuth(parameters.getClientAuthentication().isRequired());
Expand Down
Loading

0 comments on commit 624a5fb

Please sign in to comment.