How to disable SSL certificate checking with Spring RestTemplate?(使用resttemplate访问https时禁用证书检查)

*********************************************************************************************

I am trying to write an integration test where our test launches an embedded HTTPS server using Simple. I created a self-signed certificate using keytool and am able to access the server using a browser (specifically Chrome, and I do get a warning about the self-signed certificate).

However, when I try to connect using Spring RestTemplate, I get a ResourceAccessException:

org.springframework.web.client.ResourceAccessException:
I/O error on GET request for "https://localhost:8088":sun.security.validator.ValidatorException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target;
nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:557)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:444)
at net.initech.DummySslServer.shouldConnect(DummySslServer.java:119)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1917)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:52)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:541)
... 33 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1351)
... 47 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 53 more

From other questions and blog posts I've seen the advice to replace the HostnameVerifier with something like

private static final HostnameVerifier PROMISCUOUS_VERIFIER = ( s, sslSession ) -> true;

And I've set it both globally and on the RestTemplate itself:

HttpsURLConnection.setDefaultHostnameVerifier( PROMISCUOUS_VERIFIER );

..and on the RestTemplate itself:

final RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory( new SimpleClientHttpRequestFactory() {
@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
if(connection instanceof HttpsURLConnection ){
((HttpsURLConnection) connection).setHostnameVerifier(PROMISCUOUS_VERIFIER);
}
super.prepareConnection(connection, httpMethod);
}
});

Yet, I am still getting the above error. How can I get around it?

  1. Installing the certificate locally outside of the unit test is not an option as then it would need to get installed manually on every dev machine and build server and would cause an avalanche of red tape.
  2. We need SSL since we are testing a library that sits on top of RestTemplate and that we are configuring it correctly.

I am using Java 8 (but could use 7) and Spring 4.0.3 .

answer1:

I wish I still had a link to the source that lead me in this direction, but this is the code that ended up working for me. By looking over the JavaDoc for X509TrustManager it looks like the way the TrustManagers work is by returning nothing on successful validation, otherwise throwing an exception. Thus, with a null implementation, it is treated as a successful validation. Then you remove all other implementations.

import javax.net.ssl.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; public final class SSLUtil{ private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers(){
return null;
}
public void checkClientTrusted( X509Certificate[] certs, String authType ){}
public void checkServerTrusted( X509Certificate[] certs, String authType ){}
}
}; public static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
// Install the all-trusting trust manager
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
// Return it to the initial state (discovered by reflection, now hardcoded)
SSLContext.getInstance("SSL").init( null, null, null );
} private SSLUtil(){
throw new UnsupportedOperationException( "Do not instantiate libraries.");
}
}

answer2:

You can also register your keystore :

private void registerKeyStore(String keyStoreName) {
try {
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream keyStoreInputStream = classLoader.getResourceAsStream(keyStoreName);
if (keyStoreInputStream == null) {
throw new FileNotFoundException("Could not find file named '" + keyStoreName + "' in the CLASSPATH");
} //load the keystore
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(keyStoreInputStream, null); //add to known keystore
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keystore); //default SSL connections are initialized with the keystore above
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustManagers, null);
SSLContext.setDefault(sc);
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
}
}

answer3:

Here's a solution where security checking is disabled (for example, conversing with the localhost) Also, some of the solutions I've seen now contain deprecated methods and such.

/**
* @param configFilePath
* @param ipAddress
* @param userId
* @param password
* @throws MalformedURLException
*/
public Upgrade(String aConfigFilePath, String ipAddress, String userId, String password) {
configFilePath = aConfigFilePath;
baseUri = "https://" + ipAddress + ":" + PORT + "/"; restTemplate = new RestTemplate(createSecureTransport(userId, password, ipAddress, PORT));
restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
} ClientHttpRequestFactory createSecureTransport(String username,
String password, String host, int port) {
HostnameVerifier nullHostnameVerifier = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM), credentials); HttpClient client = HttpClientBuilder.create()
.setSSLHostnameVerifier(nullHostnameVerifier)
.setSSLContext(createContext())
.setDefaultCredentialsProvider(credentialsProvider).build(); HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(client); return requestFactory;
} private SSLContext createContext() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
} public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
} public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
} }; try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
SSLContext.setDefault(sc);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return sc; } catch (Exception e) {
}
return null;
}

answer4(可以工作):

For the sake of other developers who finds this question and need another solution that fits not only for unit-tests:

I've found this on a blog (not my solution! Credit to the blog's owner).

TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build(); SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext); CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(csf)
.build(); HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory);

answer5:

Disabling certificate checking is the wrong solution, and radically insecure.

The correct solution is to import the self-signed certificate into your truststore. An even more correct solution is to get the certificate signed by a CA.

If this is 'only for testing' it is still necessary to test the production configuration. Testing something else isn't a test at all, it's just a waste of time.

How to disable SSL certificate checking with Spring RestTemplate?(使用resttemplate访问https时禁用证书检查)的更多相关文章

  1. PHP出现SSL certificate:unable to get local issuer certificate的解决办法

    当本地curl需要访问https时,如果没有配置证书,会出现SSL certificate: unable to get local issuer certificate错误信息. 解决办法: 1.下 ...

  2. C# 访问https 未能创建 SSL/TLS 安全通道

    C# 访问https请求被中止: 未能创建 SSL/TLS 安全通道(Could not create SSL/TLS secure channel) 一般GetResponse可以直接访问https ...

  3. 使用 OpenSSL为WindowsServer远程桌面(RDP)创建自签名证书 (Self-signed SSL certificate)

    前言 笔者查阅很多资料,才写成此文章,如有错误,请读者们及时提出. 一般大家使用远程桌面(Remote Desktop)连接Windows Server时,总会有一个警告提示,如图1 图1 出现此警告 ...

  4. SSL certificate problem unable to get local issuer certificate解决办法

    SSL certificate problem unable to get local issuer certificate 解决办法: 下载:ca-bundle.crt 将它放在自己的wamp或者x ...

  5. How To Set Up Apache with a Free Signed SSL Certificate on a VPS

    Prerequisites Before we get started, here are the web tools you need for this tutorial: Google Chrom ...

  6. How To Create a SSL Certificate on Apache for CentOS 6

    About Self-Signed Certificates 自签证书.一个SSL证书,是加密网站的信息,并创建更安全的链接的一种方式.附加地,证书可以给网站浏览者显示VPS的的身份证明信息.如果一个 ...

  7. Configure custom SSL certificate for RDP on Windows Server 2012 in Remote Administration mode

    Q: So the release of Windows Server 2012 has removed a lot of the old Remote Desktop related configu ...

  8. (转)How to renew your Apple Push Notification Push SSL Certificate

    转自:https://blog.serverdensity.com/how-to-renew-your-apple-push-notification-push-ssl-certificate/ It ...

  9. 执行Git命令时出现 SSL certificate problem 的解决办法

    比如我在windows下用git clone gitURL 就提示  SSL certificate problem: self signed certificate 这种问题,在windows下出现 ...

随机推荐

  1. 浏览器跨域问题(jsonp)——jsonp详解

    json相信大家都用的多,jsonp我就一直没有机会用到,但也经常看到,只知道是“用来跨域的”,一直不知道具体是个什么东西.今天总算搞明白了.下面一步步来搞清楚jsonp是个什么玩意. 同源策略 首先 ...

  2. 【RS】RankMBPR:Rank-Aware Mutual Bayesian Personalized Ranking for Item Recommendation - RankMBPR:基于排序感知的相互贝叶斯个性化排序的项目推荐

    [论文标题]RankMBPR:Rank-Aware Mutual Bayesian Personalized Ranking for Item Recommendation ( WAIM 2016:  ...

  3. 进阶之路(基础篇) - 021 arduino基础知识

    什么是arduino(翻译自arduino官方介绍)Arduino 是一款便捷灵活.方便上手的开源电子原型平台,包含硬件(各种型号的arduino板)和软件(arduino IDE).她适用于艺术家. ...

  4. 细说PHP中strlen和mb_strlen的区别(转)

    在PHP中,strlen与mb_strlen是求字符串长度的函数,但是对于一些初学者来说,如果不看手册,也许不太清楚其中的区别.下面通过例子,讲解这两者之间的区别. 先看例子: <?php // ...

  5. 记录:js删除数组中某一项或几项的几种方法(转)

    1:js中的splice方法 splice(index,len,[item])    注释:该方法会改变原始数组. splice有3个参数,它也可以用来替换/删除/添加数组内某一个或者几个值 inde ...

  6. 【Servlet】使用org.eclipse.jetty实现小型的Servlet服务器

    import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpSer ...

  7. 【Visual Studio】如何在VS 2012中打印变量值到输出窗口

    1.在调试程序时,想要输出某个变量的值到vs的输出窗口,而不是通过添加断点,每次调试时,一步一步的看变量的值,很麻烦,用console.writeline(str);是不行的,这个命令只能用在控制台应 ...

  8. JetBrains C++ IDE CLion配置与评测

    等了大半年的JetBrains C++ IDE千呼万唤始出来!上次我猜2014年肯定发布,今天经@wet2_cn同学的提醒,我去官博一看,嘿!有了!赶紧安装试了一把,感觉这是迄今为止用过最好的Cpp ...

  9. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  10. mysql FullText全文索引的问题

    今天有同学问题,搜索ip的时候怎样能把 select ip from tabelx where ip like '%192.168.0.1%' 这种句子的性能优化. 的确,使用 like %x 的方式 ...