@ -25,6 +25,8 @@ import java.time.Duration;
@@ -25,6 +25,8 @@ import java.time.Duration;
import java.util.Map ;
import java.util.Set ;
import java.util.concurrent.TimeUnit ;
import java.util.function.Consumer ;
import java.util.function.Function ;
import java.util.function.UnaryOperator ;
import javax.net.ssl.SSLContext ;
@ -45,8 +47,11 @@ import org.apache.hc.core5.http.ssl.TLS;
@@ -45,8 +47,11 @@ import org.apache.hc.core5.http.ssl.TLS;
import org.apache.hc.core5.ssl.SSLContextBuilder ;
import org.apache.hc.core5.ssl.TrustStrategy ;
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder ;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings ;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects ;
import org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder ;
import org.springframework.boot.ssl.SslBundle ;
import org.springframework.boot.web.client.RestTemplateBuilder ;
import org.springframework.boot.web.client.RootUriTemplateHandler ;
import org.springframework.core.ParameterizedTypeReference ;
@ -56,7 +61,6 @@ import org.springframework.http.HttpMethod;
@@ -56,7 +61,6 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity ;
import org.springframework.http.RequestEntity.UriTemplateRequestEntity ;
import org.springframework.http.ResponseEntity ;
import org.springframework.http.client.ClientHttpRequestFactory ;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory ;
import org.springframework.util.Assert ;
import org.springframework.util.ObjectUtils ;
@ -155,14 +159,12 @@ public class TestRestTemplate {
@@ -155,14 +159,12 @@ public class TestRestTemplate {
private static RestTemplateBuilder createInitialBuilder ( RestTemplateBuilder builder , String username ,
String password , HttpClientOption . . . httpClientOptions ) {
Assert . notNull ( builder , "'builder' must not be null" ) ;
if ( httpClientOptions ! = null ) {
ClientHttpRequestFactory requestFactory = builder . buildRequestFactory ( ) ;
if ( requestFactory instanceof HttpComponentsClientHttpRequestFactory ) {
builder = builder . redirects ( HttpClientOption . ENABLE_REDIRECTS . isPresent ( httpClientOptions )
? Redirects . FOLLOW : Redirects . DONT_FOLLOW ) ;
builder = builder . requestFactoryBuilder (
( settings ) - > new CustomHttpComponentsClientHttpRequestFactory ( httpClientOptions , settings ) ) ;
}
ClientHttpRequestFactoryBuilder < ? > requestFactoryBuilder = builder . requestFactoryBuilder ( ) ;
if ( requestFactoryBuilder instanceof HttpComponentsClientHttpRequestFactoryBuilder ) {
builder = builder . requestFactoryBuilder ( applyHttpClientOptions (
( HttpComponentsClientHttpRequestFactoryBuilder ) requestFactoryBuilder , httpClientOptions ) ) ;
builder = builder . redirects ( HttpClientOption . ENABLE_REDIRECTS . isPresent ( httpClientOptions )
? Redirects . FOLLOW : Redirects . DONT_FOLLOW ) ;
}
if ( username ! = null | | password ! = null ) {
builder = builder . basicAuthentication ( username , password ) ;
@ -170,6 +172,16 @@ public class TestRestTemplate {
@@ -170,6 +172,16 @@ public class TestRestTemplate {
return builder ;
}
private static HttpComponentsClientHttpRequestFactoryBuilder applyHttpClientOptions (
HttpComponentsClientHttpRequestFactoryBuilder builder , HttpClientOption [ ] httpClientOptions ) {
builder = builder . withDefaultRequestConfigCustomizer (
new CookieSpecCustomizer ( HttpClientOption . ENABLE_COOKIES . isPresent ( httpClientOptions ) ) ) ;
if ( HttpClientOption . SSL . isPresent ( httpClientOptions ) ) {
builder = builder . withTlsSocketStrategyFactory ( new SelfSignedTlsSocketStrategyFactory ( ) ) ;
}
return builder ;
}
/ * *
* Configure the { @link UriTemplateHandler } to use to expand URI templates . By default
* the { @link DefaultUriBuilderFactory } is used which relies on Spring ' s URI template
@ -1049,7 +1061,10 @@ public class TestRestTemplate {
@@ -1049,7 +1061,10 @@ public class TestRestTemplate {
/ * *
* { @link HttpComponentsClientHttpRequestFactory } to apply customizations .
*
* @deprecated since 3 . 5 . 0 for removal in 4 . 0 . 0
* /
@Deprecated
protected static class CustomHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {
private final String cookieSpec ;
@ -1142,6 +1157,31 @@ public class TestRestTemplate {
@@ -1142,6 +1157,31 @@ public class TestRestTemplate {
}
/ * *
* Factory used to create a { @link TlsSocketStrategy } supporting self - signed
* certificates .
* /
private static class SelfSignedTlsSocketStrategyFactory implements Function < SslBundle , TlsSocketStrategy > {
private static final String [ ] SUPPORTED_PROTOCOLS = { TLS . V_1_3 . getId ( ) , TLS . V_1_2 . getId ( ) } ;
@Override
public TlsSocketStrategy apply ( SslBundle sslBundle ) {
try {
TrustSelfSignedStrategy trustStrategy = new TrustSelfSignedStrategy ( ) ;
SSLContext sslContext = new SSLContextBuilder ( ) . loadTrustMaterial ( null , trustStrategy ) . build ( ) ;
return new DefaultClientTlsStrategy ( sslContext , SUPPORTED_PROTOCOLS , null , null , null ) ;
}
catch ( KeyManagementException | NoSuchAlgorithmException | KeyStoreException ex ) {
throw new IllegalStateException ( ex ) ;
}
}
}
/ * *
* { @link TrustStrategy } supporting self - signed certificates .
* /
private static final class TrustSelfSignedStrategy implements TrustStrategy {
@Override
@ -1151,4 +1191,19 @@ public class TestRestTemplate {
@@ -1151,4 +1191,19 @@ public class TestRestTemplate {
}
private static class CookieSpecCustomizer implements Consumer < RequestConfig . Builder > {
private final boolean enableCookies ;
CookieSpecCustomizer ( boolean enableCookies ) {
this . enableCookies = enableCookies ;
}
@Override
public void accept ( RequestConfig . Builder builder ) {
builder . setCookieSpec ( this . enableCookies ? StandardCookieSpec . STRICT : StandardCookieSpec . IGNORE ) ;
}
}
}