Как разрешить самоподписанные SSL-сертификаты в более старой версии rest-assured

Мне приходится работать со старой версией (1.8.1) фреймворка спокойной безопасности. И все мои post() или get() запросы, вызываемые из режима rest-assured, терпят неудачу, потому что сервер, который я использую для тестов, имеет самоподписанный сертификат SSL.

Я знаю, что, начиная с версии 2.2.0, довольно легко настроить ssl-соединение для использования relaxedHTTPSValidation, например.

given().relaxedHTTPSValidation().when().get("https://some_server.com")

Я также нашел на вики-сайте, посвященном спокойствию, как бороться с конфигурацией SSL .

Но мой вопрос: возможно ли это в более старой версии 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$2$sendRequest(RequestSpecificationImpl.groovy)
       at com.jayway.restassured.internal.RequestSpecificationImpl$this$2$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$2$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy)
       at com.jayway.restassured.internal.RequestSpecificationImpl$this$2$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)

Примечание. Это не дубликат этого или этот вопрос, потому что ответы на него относятся к более новой версии" не беспокойся ".


person running.t    schedule 27.01.2017    source источник
comment
Какую ошибку SSL вы получаете? Я предполагаю исключение рукопожатия, но можете ли вы опубликовать трассировку стека? Кроме того, пробовали ли вы импортировать сертификат в хранилище доверенных сертификатов вашей установки Java?   -  person Adam    schedule 27.01.2017
comment
@ Адам: об импорте сертификата в хранилище доверенных сертификатов. Кажется, это не вариант, поскольку наши тестовые среды создаются / порождаются автоматически, поэтому я могу предположить, что сертификат создается один раз за сеанс тестирования. Можно ли загрузить такой сертификат перед тестом, создать временное хранилище доверенных сертификатов, которое я мог бы использовать во время тестового сеанса, и добавить этот сертификат в это хранилище доверенных сертификатов?   -  person running.t    schedule 30.01.2017
comment
Судя по ошибке, похоже, что вам нужно загрузить сертификат в хранилище доверенных сертификатов при запуске JVM. См. stackoverflow.com/questions/373295/. Это должно быть частью настройки вашей среды, и если по какой-то ужасной бюрократической причине это не может произойти, я не думаю, что вы можете многое сделать, кроме как получить настоящий подписанный сертификат или заставить его храниться в вашем тесте (не рекомендуемые).   -  person Adam    schedule 30.01.2017
comment
@Adam: да, но в целом каждый тестовый сеанс у меня создается новый тестовый сервер с новым самозаверяющим сертификатом. Поэтому мне пришлось бы добавить каждый такой сертификат перед сеансом тестирования и, вероятно, удалить его после сеанса тестирования. Так что на самом деле это выглядит как часть методов @BeforeSuite и @AfterSuite (установка и разборка). Теперь я пытаюсь сделать это автоматически на Java без использования внешних инструментов. Вероятно, когда это будет сделано, вставит фрагмент кода с решением в качестве ответа.   -  person running.t    schedule 31.01.2017


Ответы (2)


Это сработало для меня с исправлением ниже

@Test
public void testUserFetchesSuccess(){
   given().config(RestAssured.config().sslConfig(new SSLConfig().allowAllHostnames())).
    get(restUrl).
    then().body("id", equalTo("abc0"));
}
person Hemant Daga    schedule 19.05.2017
comment
Вы тестировали его с помощью надежной версии 1.8.1 или более ранней? - person running.t; 19.05.2017

Как я писал в одном из своих комментариев, я пробовал решение, которое:

  1. Скачать сертификаты сервера
  2. Создает временное хранилище ключей для использования
  3. хранит сертификаты сервера во временном хранилище ключей
  4. Использует временное хранилище ключей в режиме ожидания при подключении к серверу во время тестов

Вот важная часть кода:

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 метод основан на фрагменте кода, который я нашел в разделе этот вопрос. DummyTrustManager в точности совпадает с DefaultTrustManager там.
  • storeCertificates основан на этом вопросе и ответе на него.
  • Я все еще не уверен, SSLContext.setDefault(context) изменяется SSLContext только временно (во время загрузки сертификатов) или навсегда
person running.t    schedule 31.01.2017