|
16 | 16 |
|
17 | 17 | package org.springframework.cloud.dataflow.container.registry;
|
18 | 18 |
|
19 |
| -import java.security.KeyManagementException; |
20 |
| -import java.security.NoSuchAlgorithmException; |
21 |
| -import java.security.cert.X509Certificate; |
22 | 19 | import java.util.ArrayList;
|
23 | 20 | import java.util.Collections;
|
24 | 21 | import java.util.Map;
|
25 | 22 | import java.util.Objects;
|
26 | 23 | import java.util.concurrent.ConcurrentHashMap;
|
27 | 24 |
|
28 |
| -import javax.net.ssl.SSLContext; |
29 |
| -import javax.net.ssl.TrustManager; |
30 |
| -import javax.net.ssl.X509TrustManager; |
31 |
| - |
32 |
| -import org.apache.hc.client5.http.config.RequestConfig; |
33 |
| -import org.apache.hc.client5.http.cookie.StandardCookieSpec; |
34 |
| -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; |
35 |
| -import org.apache.hc.client5.http.impl.classic.HttpClients; |
36 |
| -import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; |
37 |
| -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; |
38 |
| -import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; |
39 |
| -import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; |
40 |
| -import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; |
41 |
| -import org.apache.hc.core5.http.HttpHost; |
42 |
| -import org.apache.hc.core5.http.config.Lookup; |
43 |
| -import org.apache.hc.core5.http.config.RegistryBuilder; |
| 25 | +import javax.net.ssl.SSLException; |
| 26 | + |
| 27 | +import io.netty.handler.codec.http.HttpHeaders; |
| 28 | +import io.netty.handler.ssl.SslContext; |
| 29 | +import io.netty.handler.ssl.SslContextBuilder; |
| 30 | +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; |
| 31 | +import reactor.netty.http.Http11SslContextSpec; |
| 32 | +import reactor.netty.http.client.HttpClient; |
| 33 | +import reactor.netty.transport.ProxyProvider; |
44 | 34 |
|
45 | 35 | import org.springframework.boot.web.client.RestTemplateBuilder;
|
46 |
| -import org.springframework.cloud.dataflow.container.registry.authorization.DropAuthorizationHeaderRequestRedirectStrategy; |
47 | 36 | import org.springframework.http.MediaType;
|
48 |
| -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; |
| 37 | +import org.springframework.http.client.ClientHttpRequestFactory; |
| 38 | +import org.springframework.http.client.ReactorNettyClientRequestFactory; |
49 | 39 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
50 | 40 | import org.springframework.web.client.RestTemplate;
|
51 | 41 |
|
@@ -153,67 +143,50 @@ public RestTemplate getContainerRestTemplate(boolean skipSslVerification, boolea
|
153 | 143 | }
|
154 | 144 | }
|
155 | 145 |
|
156 |
| - private RestTemplate createContainerRestTemplate(boolean skipSslVerification, boolean withHttpProxy, Map<String, String> extra) |
157 |
| - throws NoSuchAlgorithmException, KeyManagementException { |
| 146 | + private RestTemplate createContainerRestTemplate(boolean skipSslVerification, boolean withHttpProxy, Map<String, String> extra) { |
| 147 | + HttpClient client = httpClientBuilder(skipSslVerification); |
| 148 | + return initRestTemplate(client, withHttpProxy, extra); |
| 149 | + } |
158 | 150 |
|
159 |
| - if (!skipSslVerification) { |
160 |
| - // Create a RestTemplate that uses custom request factory |
161 |
| - return this.initRestTemplate(HttpClients.custom(), withHttpProxy, extra); |
| 151 | + private static void removeAuthorization(HttpHeaders headers) { |
| 152 | + for(Map.Entry<String,String> entry: headers.entries()) { |
| 153 | + if(entry.getKey().equalsIgnoreCase(org.springframework.http.HttpHeaders.AUTHORIZATION)) { |
| 154 | + headers.remove(entry.getKey()); |
| 155 | + break; |
| 156 | + } |
162 | 157 | }
|
163 |
| - |
164 |
| - // Trust manager that blindly trusts all SSL certificates. |
165 |
| - TrustManager[] trustAllCerts = new TrustManager[] { |
166 |
| - new X509TrustManager() { |
167 |
| - public java.security.cert.X509Certificate[] getAcceptedIssuers() { |
168 |
| - return new X509Certificate[0]; |
169 |
| - } |
170 |
| - |
171 |
| - public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { |
172 |
| - } |
173 |
| - |
174 |
| - public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { |
175 |
| - } |
176 |
| - } |
177 |
| - }; |
178 |
| - SSLContext sslContext = SSLContext.getInstance("SSL"); |
179 |
| - // Install trust manager to SSL Context. |
180 |
| - sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); |
181 |
| - |
182 |
| - // Create a RestTemplate that uses custom request factory |
183 |
| - return initRestTemplate( |
184 |
| - httpClientBuilder(sslContext), |
185 |
| - withHttpProxy, |
186 |
| - extra); |
187 |
| - } |
188 |
| - private HttpClientBuilder httpClientBuilder(SSLContext sslContext) { |
189 |
| - // Register http/s connection factories |
190 |
| - Lookup<ConnectionSocketFactory> connSocketFactoryLookup = RegistryBuilder.<ConnectionSocketFactory> create() |
191 |
| - .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)) |
192 |
| - .register("http", new PlainConnectionSocketFactory()) |
193 |
| - .build(); |
194 |
| - return HttpClients.custom() |
195 |
| - .setConnectionManager(new BasicHttpClientConnectionManager(connSocketFactoryLookup)); |
196 | 158 | }
|
197 |
| - private RestTemplate initRestTemplate(HttpClientBuilder clientBuilder, boolean withHttpProxy, Map<String, String> extra) { |
198 | 159 |
|
199 |
| - clientBuilder.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(StandardCookieSpec.RELAXED).build()); |
| 160 | + private HttpClient httpClientBuilder(boolean skipSslVerification) { |
| 161 | + |
| 162 | + try { |
| 163 | + SslContextBuilder builder = skipSslVerification ? SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE) : SslContextBuilder.forClient(); |
| 164 | + SslContext sslContext = builder.build(); |
| 165 | + HttpClient client = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext)); |
| 166 | + |
| 167 | + return client.followRedirect(true, (entries, httpClientRequest) -> { |
| 168 | + HttpHeaders httpHeaders = httpClientRequest.requestHeaders(); |
| 169 | + removeAuthorization(httpHeaders); |
| 170 | + removeAuthorization(entries); |
| 171 | + httpClientRequest.headers(httpHeaders); |
| 172 | + }); |
| 173 | + } catch (SSLException e) { |
| 174 | + throw new RuntimeException(e); |
| 175 | + } |
| 176 | + |
| 177 | + } |
| 178 | + private RestTemplate initRestTemplate(HttpClient client, boolean withHttpProxy, Map<String, String> extra) { |
200 | 179 |
|
201 | 180 | // Set the HTTP proxy if configured.
|
202 | 181 | if (withHttpProxy) {
|
203 | 182 | if (!properties.getHttpProxy().isEnabled()) {
|
204 | 183 | throw new ContainerRegistryException("Registry Configuration uses a HttpProxy but non is configured!");
|
205 | 184 | }
|
206 |
| - HttpHost proxy = new HttpHost(properties.getHttpProxy().getHost(), properties.getHttpProxy().getPort()); |
207 |
| - clientBuilder.setProxy(proxy); |
| 185 | + ProxyProvider.Builder builder = ProxyProvider.builder().type(ProxyProvider.Proxy.HTTP).host(properties.getHttpProxy().getHost()).port(properties.getHttpProxy().getPort()); |
| 186 | + client.proxy(typeSpec -> builder.build()); |
208 | 187 | }
|
209 |
| - |
210 |
| - HttpComponentsClientHttpRequestFactory customRequestFactory = |
211 |
| - new HttpComponentsClientHttpRequestFactory( |
212 |
| - clientBuilder |
213 |
| - .setRedirectStrategy(new DropAuthorizationHeaderRequestRedirectStrategy(extra)) |
214 |
| - // Azure redirects may contain double slashes and on default those are normilised |
215 |
| - .setDefaultRequestConfig(RequestConfig.custom().build()) |
216 |
| - .build()); |
| 188 | + // TODO what do we do with extra? |
| 189 | + ClientHttpRequestFactory customRequestFactory = new ReactorNettyClientRequestFactory(client); |
217 | 190 |
|
218 | 191 | // DockerHub response's media-type is application/octet-stream although the content is in JSON.
|
219 | 192 | // Similarly the Github CR response's media-type is always text/plain although the content is in JSON.
|
|
0 commit comments