Подписание клиентского запроса в JAVA

149
22 октября 2018, 00:10

Всем привет!

Пытаюсь отправить https запрос и получить ответ от сервера с использованием .p12 сертификата:

System.setProperty("javax.net.debug", "ssl");
HttpRequest<String> httpRequest = HttpRequestBuilder.create(GET,"https://site.ru/",String.class).proxy("myproxy",pyport).build();
        String responseHandler = httpRequest.execute().get();
        System.out.println(responseHandler);

Добавляю сертификат через protecle: Собственно сам сертификат состоит из 2-х страниц - если я правильно понимаю - это открытый и закрытый ключи.

Проблема в том, что java добавляет его как trusted (adding as trusted cert: в логе - при чем, я нахожу только 1 сертификат из двух по Serial number) но к самому запросу не добавляет.

Пытался отправлять запрос (через SSLSocket) и добавлять сертификат (через System.properties) различными способами - постоянно выдает ошибку Connection refused.

Единственное, чего я добился - это экспортировать одну из страниц через protecle (любую) из сертификата как PEM-файл и добавить его также в cacaers моей jdk в таком случае ошибки следующие:

Warning: no suitable certificate found - continuing without client authentication

400 No required SSL certificate was sent

Кто-нибудь сталкивался с похожей проблемой?

@Темка тоже

В продолжение на Ваш ответ:

код на Powershell:

$certPath = "path"
$certPass = "password"
$Url = "https://ftp.mysite.domen.ru/" 
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
$Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath,$certPass)
$req = [system.Net.HttpWebRequest]::Create($Url)            
$req.ClientCertificates.AddRange($Cert)
$response = $req.GetResponse() #ОК

Ваш приведенный код дал также connection refused

Сам код + stacktrace (уже на Java):

System.setProperty("http.proxyHost", "myproxyhost.ru");
System.setProperty("http.proxyPort", "myproxyport");
System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
System.setProperty("javax.net.ssl.keyStore", "d:\\path\\to\\key\\$131001.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "keypassword");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", "c:\\Program Files\\Java\\jdk-10.0.2\\lib\\security\\cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
System.setProperty("javax.net.debug", "ssl");
String url = "https://ftp.mysite.domen.ru/" ;
HttpClient httpclient = new HttpClient();
GetMethod method = new GetMethod();
method.setPath(url);
int statusCode = httpclient.executeMethod(method);
System.out.println("Status: " + statusCode);
method.releaseConnection();
method.getResponseBodyAsString();

Stacktrace:

авг. 09, 2018 9:21:19 ДП org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: I/O exception (java.net.ConnectException) caught when processing request: Connection refused: connect
авг. 09, 2018 9:21:19 ДП org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: Retrying request
авг. 09, 2018 9:21:20 ДП org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: I/O exception (java.net.ConnectException) caught when processing request: Connection refused: connect
авг. 09, 2018 9:21:20 ДП org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: Retrying request
авг. 09, 2018 9:21:21 ДП org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: I/O exception (java.net.ConnectException) caught when processing request: Connection refused: connect
авг. 09, 2018 9:21:21 ДП org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: Retrying request
Exception in thread "main" java.net.ConnectException: Connection refused: connect
    at java.base/java.net.DualStackPlainSocketImpl.connect0(Native Method)
    at java.base/java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
    at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:400)
    at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:243)
    at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:225)
    at java.base/java.net.PlainSocketImpl.connect(PlainSocketImpl.java:148)
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:402)
    at java.base/java.net.Socket.connect(Socket.java:591)
    at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:657)
    at java.base/sun.security.ssl.SSLSocketImpl.<init>(SSLSocketImpl.java:467)
    at java.base/sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:153)
    at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:82)
    at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:127)
    at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
    at rti.EntryPoint_.main(EntryPoint_.java:53)
Process finished with exit code 1

У меня есть только предположение, что проблемы связаны с тем, что после протокола https:// стоит ftp, что, как я могу предположить, предполагает собой ftp over https, но я не уверен в этом

Answer 1

Информации в твоём вопросе недостаточно, желательно привести лог ошибки со стэктрейсом. Однако судя по текущему описанию, ты пытаешься подписать именно клиентский запрос. Если это так, то тебе кидает ошибку, что не может найти подходящий сертификат в твоём хранилище. Привожу пример отправки подписанного клиентского запроса (оригинал тут).

String getHttpResponseWithSSL(String url) throws Exception {
    {
    //В блоке переопределяется хранилище доверенных сертификатов. По умолчанию это $JRE_HOME/lib/security/cacerts
        System.setProperty("javax.net.ssl.trustStore", "/usr/lib/jvm/java-6-openjdk/jre/lib/securitycacerts");
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        System.setProperty("javax.net.ssl.trustStoreType", "JKS");
    }
    //my certificate and password
    {
    //В блоке определяется хранилище с сертификатами (и ключами) для подписание клиентской (твоей) стороны. Значения по умолчанию не имеет
        System.setProperty("javax.net.ssl.keyStore", "mycert.pfx");
        System.setProperty("javax.net.ssl.keyStorePassword", "mypass");
        System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
     }
    //Дальше отправка запроса 
    HttpClient httpclient = new HttpClient();
    GetMethod method = new GetMethod();
    method.setPath(url);
    int statusCode = httpclient.executeMethod(method);
    System.out.println("Status: " + statusCode);
    method.releaseConnection();
    return method.getResponseBodyAsString();
}

P.S. Если я угадал, то переименуй вопрос в "Подписание клиентского запроса в JAVA"

Answer 2

Решение было найдено.

Проблемы, которые я проглядел:

  1. Если у вас стоит прокси и необходимо добавлять System.Property, то для https-запроса вместо

    System.setProperty("http.proxyHost", "myproxyhost.ru");

    System.setProperty("http.proxyPort", "myproxynumber");

нужно использовать

System.setProperty("https.proxyHost", "myproxyhost.ru");
System.setProperty("https.proxyPort", "myproxynumber");

Также, необходимо использовать следующие property:

System.setProperty("javax.net.debug", "ssl");
System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
System.setProperty("javax.net.ssl.keyStore", "d:\\path\\to\\keystore\\cert.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "keypassword");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", "c:\\Program Files\\Java\\jdk-10.0.2\\lib\\security\\cacerts"); //можно не устанавливать, если стоит по умолчанию, необходимо обратить внимание на stacktrace: trustStore is: c:\Program Files\Java\jdk-10.0.2\lib\security\cacerts trustStore type is: JKS
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

Плюс ко всему этому, очень важное замечание (возможно это только для моего случая): как я ни пытался добавлять p12 сертификат в cacerts, это не работало. В итоге что я сделал: зашел через браузер на целевой сайт (предварительно установив сертификат в браузер) нажал слева от пути на "сертификат" - и копировал его в файл в кодировке BASE-64 в формате .cer. Далее, через утилиту portecle открыл свой cacerts и сделал "Import trusted certificates" моего .cer сертификата. Только после этого я получил ответ от сервера. Решение по этой проблеме нашел здесь: https://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore

Код целиком:

public static void main(String[] args) throws IOException {
    System.setProperty("https.proxyHost", "myproxyhost.ru");
    System.setProperty("https.proxyPort", "myproxynumber");
    System.setProperty("javax.net.debug", "ssl");
    System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
    System.setProperty("javax.net.ssl.keyStore", "d:\\path\\to\\keystore\\cert.p12");
    System.setProperty("javax.net.ssl.keyStorePassword", "keypassword");
    System.setProperty("javax.net.ssl.trustStoreType", "JKS");
    System.setProperty("javax.net.ssl.trustStore", "c:\\Program Files\\Java\\jdk-10.0.2\\lib\\security\\cacerts");
    System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
    URL url1 = new URL("https://ftp.my.site.ru/");
    HttpsURLConnection connection = (HttpsURLConnection)url1.openConnection();
    connection.getResponseCode();
    BufferedReader in = new BufferedReader(
            new InputStreamReader(connection.getInputStream()));
    String urlString = "";
    String current;
    while ((current = in.readLine()) != null) {
        urlString += current;
    }
    System.out.println(urlString);
}
READ ALSO
Выравнивание HTML CSS

Выравнивание HTML CSS

Как сделать так, чтобы поля ввода с текстом выравнивались как на фото? Заранее спасибо

168
сделать скролинг блока по вертикали

сделать скролинг блока по вертикали

На странице есть блок с видео и текстовым контентом справа от негоКак сделать так, чтобы у текстового контента был только вертикальный скролл...

141
Ошибка с выводом элементов canvas

Ошибка с выводом элементов canvas

Нужно разместить несколько элементов на холстеДелаю через цикл, всё должно работать по-моему, но ничего на холсте не отображается

142
SpiderMonkey Garbage collection, блокирующий режим

SpiderMonkey Garbage collection, блокирующий режим

При использовании js из консоли, насколько понимаю, с помощью опций

127