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. Sql Server 在数据库中所有表所有栏位 找出匹配某个值的脚本(转)

    转自: http://blog.csdn.net/chenghaibing2008/article/details/11891419 (下面代码稍有修改,将要查找的内容直接作为参数传人,并且使用=而不 ...

  2. Swift 封装

    前言 封装主要有两大目的:一是为了我们使用数据更加方便,二是为了数据保护. 1.Swift 访问修饰符 在 Swift 语言中,访问修饰符也分为三类,分别是 private.internal.publ ...

  3. sqlserver不太常见的,可能常见但又疑问的tsql语句

    2013年10月29日16:01:58 当数据有 time类型列时候,比如 打电话的通话时长,我们查询时候不方便,我们可以添加一个冗余列,直接统计秒 ,但是 后期知道的,现在我把例如 00:12:23 ...

  4. /proc 目录详细说明

    /proc路径详细: Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以 ...

  5. JQuery EasyUI combobox 省市两级联动

    表名:province  结构如下 CallIn.tpl 模板页 <select id="consult_province" name="consult_provi ...

  6. JavaScript 如何从引用类型(Array 、 Object)创建一个新的对象

    数组的增删改 1.新增一项可以使用concat方法,它不会对原有数组进行改动,而是创建一个新数组 let a = [0, 1, 2] let b = a.concat([3]) console.log ...

  7. ext: gridpanel中的点击事件的参数是什么意思?

    listeners: {      // 当用户单击列表项时激发该函数      itemclick: function(view, record, item, index, evt)  //①    ...

  8. iphone 4s插件的安装,问题及美化

    此处iphone4s为美版,系统版本为5.0.1 首先添加我自己的weiphone源:http://apt.weiphone.com/u/2903862以及破解资源源:http://cydia.xse ...

  9. jsonp原理和jquey jsonp原理实践

    $.ajax({ type: "get", async: false, url: "ajax.htm", dataType: "jsonp" ...

  10. SQL SERVER 查看数据库信息

    a.使用sys.database_files查看有关数据库文件的信息 b.使用sys.filegroups查看有关数据库组的信息. c.使用sys.master_files 查看数据库文件的基本信息和 ...