Skip to content

Commit d05d415

Browse files
authored
Merge pull request #9773 from geoand/#9342
Make REST Client work whether or not SSL is enabled or not in native
2 parents 26a5120 + b406f7a commit d05d415

File tree

8 files changed

+155
-120
lines changed

8 files changed

+155
-120
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package io.quarkus.runtime.graal;
2+
3+
import java.io.IOException;
4+
import java.net.InetAddress;
5+
import java.net.Socket;
6+
import java.net.UnknownHostException;
7+
import java.security.KeyManagementException;
8+
import java.security.Provider;
9+
import java.security.SecureRandom;
10+
11+
import javax.net.ssl.KeyManager;
12+
import javax.net.ssl.SSLContext;
13+
import javax.net.ssl.SSLContextSpi;
14+
import javax.net.ssl.SSLEngine;
15+
import javax.net.ssl.SSLServerSocketFactory;
16+
import javax.net.ssl.SSLSessionContext;
17+
import javax.net.ssl.SSLSocketFactory;
18+
import javax.net.ssl.TrustManager;
19+
20+
public class DisabledSSLContext extends SSLContext {
21+
22+
public DisabledSSLContext() {
23+
super(new DisabledSSLContextSpi(), new Provider("DISABLED", 1, "DISABLED") {
24+
}, "DISABLED");
25+
}
26+
27+
private static class DisabledSSLContextSpi extends SSLContextSpi {
28+
29+
@Override
30+
protected void engineInit(KeyManager[] keyManagers, TrustManager[] trustManagers, SecureRandom secureRandom)
31+
throws KeyManagementException {
32+
}
33+
34+
@Override
35+
protected SSLSocketFactory engineGetSocketFactory() {
36+
return new SSLSocketFactory() {
37+
@Override
38+
public String[] getDefaultCipherSuites() {
39+
return new String[0];
40+
}
41+
42+
@Override
43+
public String[] getSupportedCipherSuites() {
44+
return new String[0];
45+
}
46+
47+
@Override
48+
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
49+
throw sslSupportDisabledException();
50+
}
51+
52+
@Override
53+
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
54+
throw sslSupportDisabledException();
55+
}
56+
57+
@Override
58+
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1)
59+
throws IOException, UnknownHostException {
60+
throw sslSupportDisabledException();
61+
}
62+
63+
@Override
64+
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
65+
throw sslSupportDisabledException();
66+
}
67+
68+
@Override
69+
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1)
70+
throws IOException {
71+
throw sslSupportDisabledException();
72+
}
73+
};
74+
}
75+
76+
@Override
77+
protected SSLServerSocketFactory engineGetServerSocketFactory() {
78+
throw sslSupportDisabledException();
79+
}
80+
81+
@Override
82+
protected SSLEngine engineCreateSSLEngine() {
83+
throw sslSupportDisabledException();
84+
}
85+
86+
@Override
87+
protected SSLEngine engineCreateSSLEngine(String s, int i) {
88+
throw sslSupportDisabledException();
89+
}
90+
91+
@Override
92+
protected SSLSessionContext engineGetServerSessionContext() {
93+
throw sslSupportDisabledException();
94+
}
95+
96+
@Override
97+
protected SSLSessionContext engineGetClientSessionContext() {
98+
throw sslSupportDisabledException();
99+
}
100+
101+
private RuntimeException sslSupportDisabledException() {
102+
return new IllegalStateException(
103+
"Native SSL support is disabled: you have set quarkus.ssl.native to false in your configuration.");
104+
}
105+
}
106+
}
Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,10 @@
11
package io.quarkus.runtime.graal;
22

3-
import java.io.IOException;
4-
import java.net.InetAddress;
5-
import java.net.Socket;
6-
import java.net.UnknownHostException;
7-
import java.security.KeyManagementException;
83
import java.security.NoSuchAlgorithmException;
94
import java.security.Provider;
10-
import java.security.SecureRandom;
115

12-
import javax.net.ssl.KeyManager;
136
import javax.net.ssl.SSLContext;
147
import javax.net.ssl.SSLContextSpi;
15-
import javax.net.ssl.SSLEngine;
16-
import javax.net.ssl.SSLServerSocketFactory;
17-
import javax.net.ssl.SSLSessionContext;
18-
import javax.net.ssl.SSLSocketFactory;
19-
import javax.net.ssl.TrustManager;
208

219
import com.oracle.svm.core.annotate.Alias;
2210
import com.oracle.svm.core.annotate.Substitute;
@@ -91,92 +79,4 @@ public static synchronized SSLContext getDefault()
9179
// return new Target_javax_net_ssl_SSLContext((SSLContextSpi) instance.impl, instance.provider,
9280
// protocol);
9381
// }
94-
95-
private static class DisabledSSLContext extends SSLContext {
96-
97-
protected DisabledSSLContext() {
98-
super(new DisabledSSLContextSpi(), new Provider("DISABLED", 1, "DISABLED") {
99-
}, "DISABLED");
100-
}
101-
}
102-
103-
private static class DisabledSSLContextSpi extends SSLContextSpi {
104-
105-
@Override
106-
protected void engineInit(KeyManager[] keyManagers, TrustManager[] trustManagers, SecureRandom secureRandom)
107-
throws KeyManagementException {
108-
}
109-
110-
@Override
111-
protected SSLSocketFactory engineGetSocketFactory() {
112-
return new SSLSocketFactory() {
113-
@Override
114-
public String[] getDefaultCipherSuites() {
115-
return new String[0];
116-
}
117-
118-
@Override
119-
public String[] getSupportedCipherSuites() {
120-
return new String[0];
121-
}
122-
123-
@Override
124-
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
125-
throw sslSupportDisabledException();
126-
}
127-
128-
@Override
129-
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
130-
throw sslSupportDisabledException();
131-
}
132-
133-
@Override
134-
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1)
135-
throws IOException, UnknownHostException {
136-
throw sslSupportDisabledException();
137-
}
138-
139-
@Override
140-
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
141-
throw sslSupportDisabledException();
142-
}
143-
144-
@Override
145-
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1)
146-
throws IOException {
147-
throw sslSupportDisabledException();
148-
}
149-
};
150-
}
151-
152-
@Override
153-
protected SSLServerSocketFactory engineGetServerSocketFactory() {
154-
throw sslSupportDisabledException();
155-
}
156-
157-
@Override
158-
protected SSLEngine engineCreateSSLEngine() {
159-
throw sslSupportDisabledException();
160-
}
161-
162-
@Override
163-
protected SSLEngine engineCreateSSLEngine(String s, int i) {
164-
throw sslSupportDisabledException();
165-
}
166-
167-
@Override
168-
protected SSLSessionContext engineGetServerSessionContext() {
169-
throw sslSupportDisabledException();
170-
}
171-
172-
@Override
173-
protected SSLSessionContext engineGetClientSessionContext() {
174-
throw sslSupportDisabledException();
175-
}
176-
177-
private RuntimeException sslSupportDisabledException() {
178-
return new IllegalStateException(
179-
"Native SSL support is disabled: you have set quarkus.ssl.native to false in your configuration.");
180-
}
181-
}
18282
}

extensions/rest-client/deployment/src/main/java/io/quarkus/restclient/deployment/RestClientProcessor.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
6060
import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
6161
import io.quarkus.deployment.builditem.FeatureBuildItem;
62-
import io.quarkus.deployment.builditem.SslNativeConfigBuildItem;
6362
import io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBuildItem;
6463
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
6564
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
@@ -138,18 +137,15 @@ void setup(BuildProducer<FeatureBuildItem> feature,
138137
}
139138

140139
@BuildStep
141-
@Record(ExecutionTime.STATIC_INIT)
142140
void processInterfaces(CombinedIndexBuildItem combinedIndexBuildItem,
143-
SslNativeConfigBuildItem sslNativeConfig,
144141
Capabilities capabilities,
145142
BuildProducer<NativeImageProxyDefinitionBuildItem> proxyDefinition,
146143
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
147144
BuildProducer<ReflectiveHierarchyBuildItem> reflectiveHierarchy,
148145
BuildProducer<BeanRegistrarBuildItem> beanRegistrars,
149146
BuildProducer<ExtensionSslNativeSupportBuildItem> extensionSslNativeSupport,
150147
BuildProducer<ServiceProviderBuildItem> serviceProvider,
151-
BuildProducer<RestClientBuildItem> restClient,
152-
RestClientRecorder restClientRecorder) {
148+
BuildProducer<RestClientBuildItem> restClient) {
153149

154150
// According to the spec only rest client interfaces annotated with RegisterRestClient are registered as beans
155151
Map<DotName, ClassInfo> interfaces = new HashMap<>();
@@ -222,8 +218,6 @@ public void register(RegistrationContext registrationContext) {
222218

223219
// Indicates that this extension would like the SSL support to be enabled
224220
extensionSslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.REST_CLIENT));
225-
226-
restClientRecorder.setSslEnabled(sslNativeConfig.isEnabled());
227221
}
228222

229223
private void findInterfaces(IndexView index, Map<DotName, ClassInfo> interfaces, Set<Type> returnTypes,

extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
import org.eclipse.microprofile.config.ConfigProvider;
1717
import org.eclipse.microprofile.context.ManagedExecutor;
1818
import org.eclipse.microprofile.rest.client.RestClientBuilder;
19+
import org.graalvm.nativeimage.ImageInfo;
1920

2021
import io.quarkus.arc.Arc;
2122
import io.quarkus.arc.InstanceHandle;
23+
import io.quarkus.runtime.graal.DisabledSSLContext;
24+
import io.quarkus.runtime.ssl.SslContextConfiguration;
2225

2326
public class RestClientBase {
2427

@@ -77,6 +80,12 @@ private void configureSsl(RestClientBuilder builder) {
7780
if (maybeHostnameVerifier.isPresent()) {
7881
registerHostnameVerifier(maybeHostnameVerifier.get(), builder);
7982
}
83+
84+
// we need to push a disabled SSL context when SSL has been disabled
85+
// because otherwise Apache HTTP Client will try to initialize one and will fail
86+
if (ImageInfo.inImageRuntimeCode() && !SslContextConfiguration.isSslNativeEnabled()) {
87+
builder.sslContext(new DisabledSSLContext());
88+
}
8089
}
8190

8291
private void registerHostnameVerifier(String verifier, RestClientBuilder builder) {

extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientRecorder.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
public class RestClientRecorder {
2424

2525
public static ResteasyProviderFactory providerFactory;
26-
public static boolean SSL_ENABLED;
2726

2827
public BeanContainerListener hackAroundExtension() {
2928
return new BeanContainerListener() {
@@ -44,11 +43,6 @@ public void setRestClientBuilderResolver() {
4443
RestClientBuilderResolver.setInstance(new BuilderResolver());
4544
}
4645

47-
public void setSslEnabled(boolean sslEnabled) {
48-
SSL_ENABLED = sslEnabled;
49-
RestClientBuilderImpl.setSslEnabled(sslEnabled);
50-
}
51-
5246
public void initializeResteasyProviderFactory(RuntimeValue<InjectorFactory> ifc, boolean useBuiltIn,
5347
Set<String> providersToRegister,
5448
Set<String> contributedProviders) {

extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/graal/ClientBuilderReplacement.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import javax.ws.rs.client.ClientBuilder;
44

55
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
6-
import org.jboss.resteasy.client.jaxrs.engines.URLConnectionClientEngineBuilder;
76
import org.jboss.resteasy.client.jaxrs.internal.LocalResteasyProviderFactory;
87
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;
98

@@ -19,12 +18,6 @@ final class ClientBuilderReplacement {
1918
public static ClientBuilder newBuilder() {
2019
ResteasyClientBuilder client = new ResteasyClientBuilderImpl();
2120
client.providerFactory(new LocalResteasyProviderFactory(RestClientRecorder.providerFactory));
22-
if (!RestClientRecorder.SSL_ENABLED) {
23-
client.httpEngine(new URLConnectionClientEngineBuilder().resteasyClientBuilder(client).build());
24-
client.sslContext(null);
25-
client.trustStore(null);
26-
client.keyStore(null, "");
27-
}
2821
return client;
2922
}
3023
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.quarkus.restclient.runtime.graal;
2+
3+
import java.security.NoSuchAlgorithmException;
4+
5+
import javax.net.ssl.SSLContext;
6+
7+
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
8+
9+
import com.oracle.svm.core.annotate.Alias;
10+
import com.oracle.svm.core.annotate.Substitute;
11+
import com.oracle.svm.core.annotate.TargetClass;
12+
13+
/**
14+
* This class is used to make sure that only the default SSLContext is requested when no SSLContext has been provided.
15+
* The reason this is necessary is because by default, the code requests
16+
* {@code SSLContext.getInstance(SSLConnectionSocketFactory.TLS)} which will fail in native when the SSL has been disabled
17+
*/
18+
@TargetClass(className = "org.jboss.resteasy.client.jaxrs.engines.ClientHttpEngineBuilder43")
19+
public final class ClientHttpEngineBuilder43Replacement {
20+
21+
@Alias
22+
private ResteasyClientBuilder that;
23+
24+
@Substitute
25+
public ClientHttpEngineBuilder43Replacement resteasyClientBuilder(ResteasyClientBuilder resteasyClientBuilder) {
26+
that = resteasyClientBuilder;
27+
if (that.getSSLContext() == null) {
28+
try {
29+
that.sslContext(SSLContext.getDefault());
30+
} catch (NoSuchAlgorithmException e) {
31+
throw new RuntimeException(e);
32+
}
33+
}
34+
return this;
35+
}
36+
}

tcks/microprofile-rest-client/pom.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
<!-- We have our own version of these tests which set up a config environment -->
4646
<exclude>org.eclipse.microprofile.rest.client.tck.InvokeWithJsonBProviderTest</exclude>
4747
<exclude>org.eclipse.microprofile.rest.client.tck.InvokeWithJsonPProviderTest</exclude>
48+
49+
<!-- The connection timeout is too small -->
50+
<exclude>org/eclipse/microprofile/rest/client/tck/timeout/*.java</exclude>
4851
</excludes>
4952
</configuration>
5053
</plugin>

0 commit comments

Comments
 (0)