如何在老版本的rest-assured中允许自签名SSL证书
How to allow self-signed SSL certificates in older version of rest-assured
我必须使用旧版本 (1.8.1) 的 rest-assured 框架。并且我从 rest-assured 调用的所有 post()
或 get()
请求都失败了,因为我用于测试的服务器具有自签名 SSL 证书。
我知道从 2.2.0 版本开始,使用 relaxedHTTPSValidation
设置 ssl 连接非常容易,例如
given().relaxedHTTPSValidation().when().get("https://some_server.com")
我也在放心wiki上找到了如何处理SSL config。
但我的问题是在老版本的rest-assured (1.8.1)中是否可行
抛出的异常是 SSLHandshakeException
.
这是我得到的痕迹:
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:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:543)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:409)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:304)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:611)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:446)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:882)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.apache.http.client.HttpClient$execute.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:1377)
at com.jayway.restassured.internal.http.HTTPBuilder.post(HTTPBuilder.java:341)
at com.jayway.restassured.internal.http.HTTPBuilder$post.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:801)
at com.jayway.restassured.internal.RequestSpecificationImpl.this$sendRequest(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl$this$sendRequest.call(Unknown Source)
at com.jayway.restassured.internal.filter.RootFilter.filter(RootFilter.groovy:30)
at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
at com.jayway.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:49)
at com.jayway.restassured.filter.FilterContext$next.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:758)
at com.jayway.restassured.internal.RequestSpecificationImpl$invokeFilterChain.callCurrent(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1142)
at com.jayway.restassured.internal.RequestSpecificationImpl.this$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl$this$applyPathParamsAndSendRequest.callCurrent(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.post(RequestSpecificationImpl.groovy:135)
at com.ibm.datatools.webauto.framework.common.BaseWebTest.login(BaseWebTest.java:53)
at com.ibm.datatools.webauto.dynamite.svt.ui.testcases.UDXTest.idaLogin(UDXTest.java:47)
at com.ibm.datatools.webauto.dynamite.svt.ui.testcases.UDXTest.beforeClass(UDXTest.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:510)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:211)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:170)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:104)
at org.testng.TestRunner.privateRun(TestRunner.java:774)
at org.testng.TestRunner.run(TestRunner.java:624)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:359)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312)
at org.testng.SuiteRunner.run(SuiteRunner.java:261)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1215)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.run(TestNG.java:1048)
at org.testng.TestNG.privateMain(TestNG.java:1355)
at org.testng.TestNG.main(TestNG.java:1324)
注意:这不是 or 问题的重复,因为那里提供的答案涉及更新版本的 rest-assured。
正如我在其中一条评论中所写,我尝试了以下解决方案:
- 下载服务器证书
- 创建供 rest-assured
使用的临时密钥库
- 在临时密钥库中存储服务器证书
- 在测试期间连接到服务器时使用 rest-assured 中的临时密钥库
这是代码的重要部分:
protected Certificate[] getCertificates(String url) throws IOException, GeneralSecurityException
{
URL urlConnection = new URL(url);
SSLContext context = SSLContext.getInstance("TLS");
context.init(new KeyManager[0], new TrustManager[] {new DummyTrustManager()}, new SecureRandom());
SSLContext.setDefault(context);
HttpsURLConnection con = (HttpsURLConnection)urlConnection.openConnection();
con.setHostnameVerifier(
new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
con.setSSLSocketFactory(context.getSocketFactory());
con.connect();
Certificate[] certificates = con.getServerCertificates();
con.disconnect();
return certificates;
}
protected void storeCertificates(Certificate[] certs, String keystorePath, String keystorePassword) throws GeneralSecurityException, IOException
{
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(null, keystorePassword.toCharArray());
for (Certificate c: certs)
{
keystore.setCertificateEntry(Integer.toHexString(c.hashCode()), c);
}
File f = new File(keystorePath);
FileOutputStream out_stream = new FileOutputStream(f);
keystore.store(out_stream, keystorePassword.toCharArray());
out_stream.close();
}
在那之后我唯一要做的就是:
RestAssured.keystore(keystorePath, keystorePassword);
备注:
getCertificates
方法基于 piece of code I found under this 问题。 DummyTrustManager
与那里的 DefaultTrustManager
完全相同。
storeCertificates
基于 this 问题及其答案。
- 我仍然不确定
SSLContext.setDefault(context)
更改 SSLContext
只是暂时的(在下载证书期间)还是永久的
下面的修正对我有用
@Test
public void testUserFetchesSuccess(){
given().config(RestAssured.config().sslConfig(new SSLConfig().allowAllHostnames())).
get(restUrl).
then().body("id", equalTo("abc0"));
}
我必须使用旧版本 (1.8.1) 的 rest-assured 框架。并且我从 rest-assured 调用的所有 post()
或 get()
请求都失败了,因为我用于测试的服务器具有自签名 SSL 证书。
我知道从 2.2.0 版本开始,使用 relaxedHTTPSValidation
设置 ssl 连接非常容易,例如
given().relaxedHTTPSValidation().when().get("https://some_server.com")
我也在放心wiki上找到了如何处理SSL config。
但我的问题是在老版本的rest-assured (1.8.1)中是否可行
抛出的异常是 SSLHandshakeException
.
这是我得到的痕迹:
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:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:543)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:409)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:304)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:611)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:446)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:882)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.apache.http.client.HttpClient$execute.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:1377)
at com.jayway.restassured.internal.http.HTTPBuilder.post(HTTPBuilder.java:341)
at com.jayway.restassured.internal.http.HTTPBuilder$post.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:801)
at com.jayway.restassured.internal.RequestSpecificationImpl.this$sendRequest(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl$this$sendRequest.call(Unknown Source)
at com.jayway.restassured.internal.filter.RootFilter.filter(RootFilter.groovy:30)
at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
at com.jayway.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:49)
at com.jayway.restassured.filter.FilterContext$next.call(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:758)
at com.jayway.restassured.internal.RequestSpecificationImpl$invokeFilterChain.callCurrent(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:1142)
at com.jayway.restassured.internal.RequestSpecificationImpl.this$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl$this$applyPathParamsAndSendRequest.callCurrent(Unknown Source)
at com.jayway.restassured.internal.RequestSpecificationImpl.post(RequestSpecificationImpl.groovy:135)
at com.ibm.datatools.webauto.framework.common.BaseWebTest.login(BaseWebTest.java:53)
at com.ibm.datatools.webauto.dynamite.svt.ui.testcases.UDXTest.idaLogin(UDXTest.java:47)
at com.ibm.datatools.webauto.dynamite.svt.ui.testcases.UDXTest.beforeClass(UDXTest.java:62)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:510)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:211)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:170)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:104)
at org.testng.TestRunner.privateRun(TestRunner.java:774)
at org.testng.TestRunner.run(TestRunner.java:624)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:359)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312)
at org.testng.SuiteRunner.run(SuiteRunner.java:261)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1215)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.run(TestNG.java:1048)
at org.testng.TestNG.privateMain(TestNG.java:1355)
at org.testng.TestNG.main(TestNG.java:1324)
注意:这不是
正如我在其中一条评论中所写,我尝试了以下解决方案:
- 下载服务器证书
- 创建供 rest-assured 使用的临时密钥库
- 在临时密钥库中存储服务器证书
- 在测试期间连接到服务器时使用 rest-assured 中的临时密钥库
这是代码的重要部分:
protected Certificate[] getCertificates(String url) throws IOException, GeneralSecurityException
{
URL urlConnection = new URL(url);
SSLContext context = SSLContext.getInstance("TLS");
context.init(new KeyManager[0], new TrustManager[] {new DummyTrustManager()}, new SecureRandom());
SSLContext.setDefault(context);
HttpsURLConnection con = (HttpsURLConnection)urlConnection.openConnection();
con.setHostnameVerifier(
new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
con.setSSLSocketFactory(context.getSocketFactory());
con.connect();
Certificate[] certificates = con.getServerCertificates();
con.disconnect();
return certificates;
}
protected void storeCertificates(Certificate[] certs, String keystorePath, String keystorePassword) throws GeneralSecurityException, IOException
{
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(null, keystorePassword.toCharArray());
for (Certificate c: certs)
{
keystore.setCertificateEntry(Integer.toHexString(c.hashCode()), c);
}
File f = new File(keystorePath);
FileOutputStream out_stream = new FileOutputStream(f);
keystore.store(out_stream, keystorePassword.toCharArray());
out_stream.close();
}
在那之后我唯一要做的就是:
RestAssured.keystore(keystorePath, keystorePassword);
备注:
getCertificates
方法基于 piece of code I found under this 问题。DummyTrustManager
与那里的DefaultTrustManager
完全相同。storeCertificates
基于 this 问题及其答案。- 我仍然不确定
SSLContext.setDefault(context)
更改SSLContext
只是暂时的(在下载证书期间)还是永久的
下面的修正对我有用
@Test
public void testUserFetchesSuccess(){
given().config(RestAssured.config().sslConfig(new SSLConfig().allowAllHostnames())).
get(restUrl).
then().body("id", equalTo("abc0"));
}