My task is to establish a connection to JIRA in java using RESTAPI. I'm facing an error with the SSL security certificate. I have tried many times and looked on google, but I didn't find any solution to my problem. Can anyone help me to fix this error?
APOD.java
package com.jiraconnection;
import com.fasterxml.jackson.annotation.JsonProperty;
public class APOD {
public final String expand;
public final String id;
public final String key;
public final String self;
public APOD(#JsonProperty("expand") String expand,
#JsonProperty("id") String id,
#JsonProperty("key") String key,
#JsonProperty("self") String self) {
this.expand = expand;
this.id = id;
this.key = key;
this.self = self;
}
}
JavaHttpURLConnectionDemo.java
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class JavaHttpURLConnectionDemo {
public static void main(String[] args) throws IOException {
// Create a neat value object to hold the URL
URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
// Open a connection(?) on the URL(?) and cast the response(??)
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
// Now it's "open", we can set the request method, headers etc.
connection.setRequestProperty("accept", "application/json");
// This line makes the request
InputStream responseStream = connection.getInputStream();
// Manually converting the response body InputStream to APOD using Jackson
ObjectMapper mapper = new ObjectMapper();
APOD apod = mapper.readValue(responseStream, APOD.class);
// Finally we have the response
System.out.println(apod.expand);
}
}
Error
Exception in thread "main" javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:324)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:267)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:262)
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1340)
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1215)
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1158)
HttpsURLConnection is using by default the JDK trusted certificates to validate the server certificate whether it is known and trusted. If it is present over there it won't throw a SSLHandshakeException
Jira has currently the following certificate chain:
You can easily verify whether your HttpsURLConnection has the trusted certificate by adding a breakpoint after initializing the HttpsURLConnection See below for an example:
So my assumption is that in your case the certificate is not present in the JDK truststore. What you can do is extract the Jira certificate, just like shown here: Using openssl to get the certificate from a server afterwords either import it into cacert file here: $JAVA_HOME/lib/security/cacerts. But I think it will be better to provide a custom ssl configuration to your HttpsUrlConnection as it would be more maintainable in my opinion. But either options will work.
So the following code snippet is for option 2 when using custom trustore:
Option 2
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.util.Objects;
import java.util.stream.Collectors;
public class App {
public static void main(String[] args) throws Exception {
Path trustStorePath = Paths.get("/path/to/your/truststore.jks");
char[] trustStorePassword = "my-password".toCharArray();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try(InputStream inputStream = Objects.requireNonNull(Files.newInputStream(trustStorePath))) {
trustStore.load(inputStream, trustStorePassword);
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(socketFactory);
connection.setRequestProperty("accept", "application/json");
try(InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String responseBody = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(responseBody);
}
}
}
Or you can do everything inline without the custom truststore from your filesystem as shown below. In this way you have the the root ca as pem, which is DigiCert High Assurance EV ROOT CA and load it programatically into your in memory truststore.
Option 3
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID;
import java.util.stream.Collectors;
public class App {
public static void main(String[] args) throws Exception {
String atlassian = ""
+ "MIIFdzCCBP6gAwIBAgIQAgzZlKL4HKlpT4RkDXUi8TAKBggqhkjOPQQDAzBWMQsw"
+ "CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTAwLgYDVQQDEydEaWdp"
+ "Q2VydCBUTFMgSHlicmlkIEVDQyBTSEEzODQgMjAyMCBDQTEwHhcNMjIwNTEwMDAw"
+ "MDAwWhcNMjMwNjEwMjM1OTU5WjBuMQswCQYDVQQGEwJBVTEYMBYGA1UECBMPTmV3"
+ "IFNvdXRoIFdhbGVzMQ8wDQYDVQQHEwZTeWRuZXkxGjAYBgNVBAoTEUF0bGFzc2lh"
+ "biBQdHkgTHRkMRgwFgYDVQQDDA8qLmF0bGFzc2lhbi5jb20wWTATBgcqhkjOPQIB"
+ "BggqhkjOPQMBBwNCAAR7p4KtlAjEKMIH66rdbCXtkR5nO20hqZco8B/L+EuJ9mqJ"
+ "PT4dmaDR8OZWzlLXfqiKKhtxuPckC5dtwns4kXyAo4IDlDCCA5AwHwYDVR0jBBgw"
+ "FoAUCrwIKReMpTlteg7OM8cus+37w3owHQYDVR0OBBYEFMw8XjgJmgk4VGCBWOyG"
+ "Lr/FMrRZMCkGA1UdEQQiMCCCDyouYXRsYXNzaWFuLmNvbYINYXRsYXNzaWFuLmNv"
+ "bTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC"
+ "MIGbBgNVHR8EgZMwgZAwRqBEoEKGQGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E"
+ "aWdpQ2VydFRMU0h5YnJpZEVDQ1NIQTM4NDIwMjBDQTEtMS5jcmwwRqBEoEKGQGh0"
+ "dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU0h5YnJpZEVDQ1NIQTM4"
+ "NDIwMjBDQTEtMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcC"
+ "ARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGFBggrBgEFBQcBAQR5MHcw"
+ "JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBPBggrBgEFBQcw"
+ "AoZDaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTSHlicmlk"
+ "RUNDU0hBMzg0MjAyMENBMS0xLmNydDAJBgNVHRMEAjAAMIIBgQYKKwYBBAHWeQIE"
+ "AgSCAXEEggFtAWsAdwCt9776fP8QyIudPZwePhhqtGcpXc+xDCTKhYY069yCigAA"
+ "AYCt4OEbAAAEAwBIMEYCIQC37AW4L7CCrKn0+kTydWf3zn6tdkFOg/ZI3mUU4/P3"
+ "CwIhAOnIlT0eX2nzpr6+d3GReTVlVf5+coiyYsSOJWOANM2ZAHcANc8ZG7+xbFe/"
+ "D61MbULLu7YnICZR6j/hKu+oA8M71kwAAAGAreDg7wAABAMASDBGAiEAj67xO2t2"
+ "OVtwSjLdsD8RknexjRqu+Ifwp5wO/2p8a84CIQDw9OKwzRnQ4cxYPKPrIYGm5hbH"
+ "KfVwcBMmo0u0XQ2YlQB3ALNzdwfhhFD4Y4bWBancEQlKeS2xZwwLh9zwAw55NqWa"
+ "AAABgK3g4SEAAAQDAEgwRgIhAP/l3SLBl5/9RHQvd5GjApgGAne4J/XnA68l/vQp"
+ "x7jHAiEAxWnEzde1lf4a1kMuFUyc6fBUE88GVb+zC9rjv4KCDcQwCgYIKoZIzj0E"
+ "AwMDZwAwZAIwFcy1X+o/HkXrM8rFdcjBGCieA0oBeRSSifale32U36xquKPBtSvm"
+ "2g/HAZh2N3DDAjBM4zmAiD0WTA0o3Fnh03mIwP/98RqXvjiDUL/bzovejseo8eRp"
+ "FDjNl90IcJuAoGc=";
String digicertCa = ""
+ "MIIEFzCCAv+gAwIBAgIQB/LzXIeod6967+lHmTUlvTANBgkqhkiG9w0BAQwFADBh"
+ "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3"
+ "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD"
+ "QTAeFw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFYxCzAJBgNVBAYTAlVT"
+ "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxMDAuBgNVBAMTJ0RpZ2lDZXJ0IFRMUyBI"
+ "eWJyaWQgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA"
+ "BMEbxppbmNmkKaDp1AS12+umsmxVwP/tmMZJLwYnUcu/cMEFesOxnYeJuq20ExfJ"
+ "qLSDyLiQ0cx0NTY8g3KwtdD3ImnI8YDEe0CPz2iHJlw5ifFNkU3aiYvkA8ND5b8v"
+ "c6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFAq8CCkXjKU5"
+ "bXoOzjPHLrPt+8N6MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA4G"
+ "A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI"
+ "KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j"
+ "b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp"
+ "Q2VydEdsb2JhbFJvb3RDQS5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny"
+ "bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDA9BgNVHSAE"
+ "NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG"
+ "BmeBDAECAzANBgkqhkiG9w0BAQwFAAOCAQEAR1mBf9QbH7Bx9phdGLqYR5iwfnYr"
+ "6v8ai6wms0KNMeZK6BnQ79oU59cUkqGS8qcuLa/7Hfb7U7CKP/zYFgrpsC62pQsY"
+ "kDUmotr2qLcy/JUjS8ZFucTP5Hzu5sn4kL1y45nDHQsFfGqXbbKrAjbYwrwsAZI/"
+ "BKOLdRHHuSm8EdCGupK8JvllyDfNJvaGEwwEqonleLHBTnm8dqMLUeTF0J5q/hos"
+ "Vq4GNiejcxwIfZMy0MJEGdqN9A57HSgDKwmKdsp33Id6rHtSJlWncg+d0ohP/rEh"
+ "xRqhqjn1VtvChMQ1H3Dau0bwhr9kAMQ+959GG50jBbl9s08PqUU643QwmA==";
String digicertRootCa = ""
+ "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh"
+ "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3"
+ "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD"
+ "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT"
+ "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j"
+ "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG"
+ "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB"
+ "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97"
+ "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt"
+ "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P"
+ "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4"
+ "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO"
+ "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR"
+ "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw"
+ "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr"
+ "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg"
+ "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF"
+ "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls"
+ "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk"
+ "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=";
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
for (String certificateContent : Arrays.asList(atlassian, digicertCa, digicertRootCa)) {
byte[] decodedCertificate = Base64.getDecoder().decode(certificateContent);
try(ByteArrayInputStream certificateAsInputStream = new ByteArrayInputStream(decodedCertificate);
BufferedInputStream bufferedCertificateStream = new BufferedInputStream(certificateAsInputStream)) {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Certificate certificate = certificateFactory.generateCertificate(bufferedCertificateStream);
trustStore.setCertificateEntry(UUID.randomUUID().toString(), certificate);
}
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(socketFactory);
connection.setRequestProperty("accept", "application/json");
try(InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String responseBody = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(responseBody);
}
}
}
Last resort would be disable the certificate validation, but I would not recommend that. Below is an example for that:
Option 4
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.stream.Collectors;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
public class App {
public static void main(String[] args) throws Exception {
X509ExtendedTrustManager unsafeTrustManager = new X509ExtendedTrustManager() {
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) {}
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) {}
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {}
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{ unsafeTrustManager }, null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
URL url = new URL("https://jira.atlassian.com/rest/api/latest/issue/JRA-9");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(socketFactory);
connection.setRequestProperty("accept", "application/json");
try(InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String responseBody = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(responseBody);
}
}
}
I have combined client-certificate-with-com-sun-net-httpserver-httpsserver
with simple-java-https-server but I always get the error message
SSL-Peer could not be verified.
I call setWantClientAuth(true) and verify Authentification by calling
Certificate[] peerCerts = pHttpsExchange.getSSLSession().getPeerCertificates();
The server is running with JDK 1.8 and the client is running on Android. The server Code is:
package de.org.vnetz;
import java.io.*;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.*;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.SSLContext;
import javax.security.auth.x500.X500Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class clsHTTPSServer {
final static String SERVER_PWD = "xxxxxx";
final static String KST_SERVER = "server.jks";
final static String TST_SERVER = "servertrust.jks";
private static final int PORT = 9999;
public static class MyHandler implements HttpHandler {
// whether to use client cert authentication
private final boolean useClientCertAuth = true;
private List<LdapName> allowedPrincipals = new ArrayList<LdapName>();
private final boolean extendedClientCheck = true;
private static final String CLIENTAUTH_OID = "1.3.6.1.5.5.7.3.2";
#Override
public void handle(HttpExchange t) throws IOException {
String response = "Hallo Natalie!";
HttpsExchange httpsExchange = (HttpsExchange) t;
boolean auth;
try
{
checkAuthentication(httpsExchange);
auth = true;
}
catch (Exception ex)
{
response = ex.getMessage();
auth = false;
}
boolean res = httpsExchange.getSSLSession().isValid();
if (res) {
String qry = httpsExchange.getRequestURI().getQuery();
if (qry!=null && qry.startsWith("qry=")) {
httpsExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpsExchange.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
else
{
httpsExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpsExchange.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write((response + " no query!").getBytes());
os.close();
}
}
}
// Verify https certs if its Https request and we have SSL auth enabled. Will be called before
// handling the request
protected void checkAuthentication(HttpExchange pHttpExchange) throws SecurityException {
// Cast will always work since this handler is only used for Http
HttpsExchange httpsExchange = (HttpsExchange) pHttpExchange;
if (useClientCertAuth) {
checkCertForClientUsage(httpsExchange);
checkCertForAllowedPrincipals(httpsExchange);
}
}
// Check the cert's principal against the list of given allowedPrincipals.
// If no allowedPrincipals are given than every principal is allowed.
// If an empty list as allowedPrincipals is given, no one is allowed to access
private void checkCertForClientUsage(HttpsExchange pHttpsExchange) {
try {
String host = pHttpsExchange.getSSLSession().getPeerHost();
//Principal p = pHttpsExchange.getSSLSession().getPeerPrincipal();
String pr = pHttpsExchange.getSSLSession().getProtocol();
Certificate[] peerCerts = pHttpsExchange.getSSLSession().getPeerCertificates();
if (peerCerts != null && peerCerts.length > 0) {
X509Certificate clientCert = (X509Certificate) peerCerts[0];
// We required that the extended key usage must be present if we are using
// client cert authentication
if (extendedClientCheck &&
(clientCert.getExtendedKeyUsage() == null || !clientCert.getExtendedKeyUsage().contains(CLIENTAUTH_OID))) {
throw new SecurityException("No extended key usage available");
}
}
} catch (ClassCastException e) {
throw new SecurityException("No X509 client certificate");
} catch (CertificateParsingException e) {
throw new SecurityException("Can't parse client cert");
} catch (SSLPeerUnverifiedException e) {
throw new SecurityException("SSL Peer couldn't be verified");
}
}
private void checkCertForAllowedPrincipals(HttpsExchange pHttpsExchange) {
if (allowedPrincipals != null) {
X500Principal certPrincipal;
try {
certPrincipal = (X500Principal) pHttpsExchange.getSSLSession().getPeerPrincipal();
Set<Rdn> certPrincipalRdns = getPrincipalRdns(certPrincipal);
for (LdapName principal : allowedPrincipals) {
for (Rdn rdn : principal.getRdns()) {
if (!certPrincipalRdns.contains(rdn)) {
throw new SecurityException("Principal " + certPrincipal + " not allowed");
}
}
}
} catch (SSLPeerUnverifiedException e) {
throw new SecurityException("SSLPeer unverified");
} catch (ClassCastException e) {
throw new SecurityException("Internal: Invalid Principal class provided " + e);
}
}
}
private Set<Rdn> getPrincipalRdns(X500Principal principal) {
try {
LdapName certAsLdapName =new LdapName(principal.getName());
return new HashSet<Rdn>(certAsLdapName.getRdns());
} catch (InvalidNameException e) {
throw new SecurityException("Cannot parse '" + principal + "' as LDAP name");
}
}
}
/**
* #param args
*/
public static void main(String[] args) throws Exception {
try {
// setup the socket address
InetSocketAddress address = new InetSocketAddress(PORT);
// initialise the HTTPS server
HttpsServer httpsServer = HttpsServer.create(address, 0);
SSLContext sslContext = SSLContext.getInstance("TLS");
// initialise the keystore
// char[] password = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(KST_SERVER);// ("testkey.jks");
ks.load(fis, SERVER_PWD.toCharArray());// password);
// setup the key manager factory
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, SERVER_PWD.toCharArray());
// setup the trust manager factory
// TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
// tmf.init(ks);
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(new FileInputStream(TST_SERVER), SERVER_PWD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
// setup the HTTPS context and parameters
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLParameters sslp = sslContext.getSupportedSSLParameters();
//sslp.setNeedClientAuth(true);
sslp.setWantClientAuth(true);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
// initialise the SSL context
SSLContext c = SSLContext.getDefault();
SSLEngine engine = c.createSSLEngine();
//params.setNeedClientAuth(true);
params.setWantClientAuth(true);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
// get the default parameters
SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
SSLParameters sslParams = sslContext.getDefaultSSLParameters();
//sslParams.setNeedClientAuth(true);
sslParams.setWantClientAuth(true);
params.setSSLParameters(defaultSSLParameters);
} catch (Exception ex) {
System.out.println("Failed to create HTTPS port");
}
}
});
httpsServer.createContext("/test", new MyHandler());
httpsServer.setExecutor(
new ThreadPoolExecutor(4, 80, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000))); // creates
// a
// default
// executor
httpsServer.start();
} catch (Exception exception) {
System.out.println("Failed to create HTTPS server on port " + 62112 + " of localhost");
exception.printStackTrace();
}
}
}
The client code is:
package vnetz.de.org.vnetz;
import android.content.Context;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.SocketException;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class clsHTTPS {
private static final String MYURL = "https://localhost:9999/test?qry=test";
static String NO_KEYSTORE = "";
static String UNAUTH_KEYSTORE = "unauthclient.bks"; // Doesn't exist in server trust store, should fail authentication.
static String AUTH_KEYSTORE = "authclient.bks"; // Exists in server trust store, should pass authentication.
static String TRUSTSTORE = "clienttrust.bks";
static String CLIENT_PWD = "xxxxxx";
private static Context context = null;
public clsHTTPS(Context context) {
this.context = context;
}
public static void main(String[] args) throws Exception {
}
public String connect(String jksFile) {
try {
String https_url = MYURL;
URL url;
url = new URL(https_url);
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier());
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(getSSLFactory(jksFile));
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setUseCaches(false);
// Print response
//SSLContext context = SSLContext.getInstance("TLS");
//context.init(null, new X509TrustManager[]{new NullX509TrustManager()}, new SecureRandom());
//HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
BufferedReader bir = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sbline = new StringBuilder();
String line;
while ((line = bir.readLine()) != null) {
System.out.println(line);
sbline.append(line);
}
bir.close();
conn.disconnect();
return sbline.toString();
} catch (SSLHandshakeException | SocketException e) {
System.out.println(e.getMessage());
System.out.println("");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static SSLSocketFactory getSSLFactory(String jksFile) throws Exception {
// Create key store
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
KeyManager[] kmfs = null;
if (jksFile.length() > 0) {
keyStore.load(context.getAssets().open(jksFile), CLIENT_PWD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, CLIENT_PWD.toCharArray());
kmfs = kmf.getKeyManagers();
}
// create trust store (validates the self-signed server!)
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(context.getAssets().open(TRUSTSTORE), CLIENT_PWD.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmfs, trustFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
private class NullHostNameVerifier implements HostnameVerifier
{
#Override
public boolean verify(String s, SSLSession sslSession)
{
return s.equalsIgnoreCase("localhost");
}
}
private class NullX509TrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
}
}
'Peer not verified' in a server means that the client didn't send a certificate, which probably means that its signer isn't in your server's truststore. When the server requests the client certificate, it supplies a list of acceptable signers, and the client must not send a certificate that isn't signed by one of those.
Or else the server didn't ask for a client certificate at all. Doesn't apply in this case.
In your case it would be a lot simpler to use needClientAuth, as that will just fail the handshake without you having to get as a far as getPeerCertificates().
NB:
The SSLSession is valid, otherwise you wouldn't have an SSL connection. The only way it becomes invalid is if you call invalidate(), which causes a full re-handshake on the next I/O. You're testing the wrong thing.
Checking for allowed principals is authorization, not authentication.
I am using a rest service which requires authentication, Below curl command is used to achieve this
curl -v --insecure --request POST "https://ip:port/login" -d IDToken1="username" -d "password" --cookie-jar cookie.txt
After authentication it creates a cookie file.
Can someone helps in creating the corresponding rest client using java.
I have used
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client
.target("http://hilweb05:8080/login");
Form form = new Form().param("IDToken1", "username").param("IDToken2", "password");
Response jsonAnswer = target.request()
.accept(MediaType.APPLICATION_JSON).post(Entity.form(form));
if (jsonAnswer.getStatus() != 200) {
throw new RuntimeException("Not reachable "
+ jsonAnswer.getStatus());
}
List<SomeDataClass> matList = jsonAnswer.readEntity(new GenericType<List<SomeDataClass>>() {});
for (SomeDataClass m : matList) {
System.out.println(m.getF1() + " " + m.getF2() + " "
+ m.getF3());
}
But its not working
I switched to Apache http client, with the below piece of code I am able to get the cookie.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
public class ApacheHttpClient {
public static void main(String[] args) throws ClientProtocolException, IOException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial((chain, authType) -> true).build();
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(sslContext, new String[]
{"SSLv2Hello", "SSLv3", "TLSv1","TLSv1.1", "TLSv1.2" }, null,
NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
try {
HttpPost httpPost = new HttpPost("url/login");
List <NameValuePair> nvps = new ArrayList <NameValuePair>();
nvps.add(new BasicNameValuePair("IDToken1", name));
nvps.add(new BasicNameValuePair("IDToken2", password));
httpPost.setEntity(new UrlEncodedFormEntity(nvps));
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println("Status -->>> "+ response2.getStatusLine().getStatusCode());
Header[] cookieInf = response2.getHeaders("Set-Cookie");
StringBuilder strBf = new StringBuilder();
for(Header header : cookieInf)
{
strBf.append(header.getValue());
}
System.out.println("Data is "+ strBf);
HttpEntity entity2 = response2.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume(entity2);
} finally {
response2.close();
}
} finally {
httpclient.close();
}
}
}
Now I need to write the cookie in a text file, so I need help in parsing the cookie information so that it matches the cookie file generated by curl command.
With the below piece of code it works
public class JerseyClientPost {
public static void main(String[] args) {
try {
Client client = Client.create(configureClient());
final com.sun.jersey.api.client.WebResource webResource = client
.resource("https://wtc2e3enm.eng.mobilephone.net:443/login");
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("IDToken1", name);
formData.add("IDToken2", password);
try {
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED)
.accept(MediaType.APPLICATION_JSON_TYPE).post(ClientResponse.class, formData);
String x = response.getEntity(String.class);
System.out.println("Response String is "+ x);
} catch (com.sun.jersey.api.client.ClientHandlerException che) {
che.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static ClientConfig configureClient() {
TrustManager[] certs = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
} };
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("SSL");
ctx.init(null, certs, new SecureRandom());
} catch (java.security.GeneralSecurityException ex) {
}
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
ClientConfig config = new DefaultClientConfig();
try {
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
new HTTPSProperties(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}, ctx));
} catch (Exception e) {
}
return config;
}
}
but I am not able to get the cookies from response, if I use curl I am able to get the cookie by using --cookie-jar argument. Can somebody help in getting the cookie
I am currently developing a SOAP-Server/Client using CXF rev 3.1.10.
Everything is set up and works quite fine as long as I don't try to use https.
I am not using any xml-files/beans, except the ones that might be used 'behind the scenes' by the framework.
I would actually like to leave it that way.
I am using a self signed certificate and its extracted keys, just in case this might be necessary.
Server Class
public class Server extends Thread {
private static final Logger LOG = Logger.getLogger(Server.class);
#WebService(name = "SoapService", serviceName = "SoapService", endpointInterface = "playground.mstahl.cxf_soap.SoapServiceDefinition")
private static final class ServerImpl implements SoapServiceDefinition {
#Override
public boolean handleStateDataRecipience(String user, String pass, String restri) throws Exception {
return true;
}
}
private final int usedPort;
private final String ksPath;
private final String ksPass;
private final boolean sslEnabled;
public Server(int port, boolean sslEnabled, String ksPath, String ksPass) {
super("CXF-SOAP-Playground");
setDaemon(true);
usedPort = port;
this.sslEnabled = sslEnabled;
this.ksPath = ksPath;
this.ksPass = ksPass;
start();
}
#Override
public void run() {
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setAddress(String.format("http" + (sslEnabled ? "s" : "") + "://localhost:%d/signtest/", Integer.valueOf(usedPort))); // <- Yah, pretty ugly, but its just for testing purposes ;)
sf.setServiceClass(ServerImpl.class);
ServerImpl serviceBean = new ServerImpl();
sf.setServiceBean(serviceBean);
if (sslEnabled) {
try {
JettyHTTPServerEngineFactory factory = sf.getBus().getExtension(JettyHTTPServerEngineFactory.class);
factory.setTLSServerParametersForPort(usedPort, getTLSServerParameters(ksPath, ksPass));
} catch (Exception e) {
e.printStackTrace();
}
}
org.apache.cxf.endpoint.Server server = sf.create();
if (!server.isStarted()) {
return;
}
LOG.debug("... done.");
while (!IsInterrupted()) {
try {
Thread.sleep(100);
} catch (Exception e) {
//meh, just a test
}
}
server.stop();
server.destroy();
}
private final TLSServerParameters getTLSServerParameters(final String ksPath, final String ksPass) {
TLSServerParameters tlsParams = null;
try {
tlsParams = new TLSServerParameters();
File truststore = new File(ksPath);
LOG.info("Try to load file " + truststore.getCanonicalPath());
final KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream stream = new FileInputStream(truststore);
final char[] keyStorePassphraseAsChar = ksPass.toCharArray();
keyStore.load(stream, keyStorePassphraseAsChar);
stream.close();
final KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("PKIX");
keyFactory.init(keyStore, keyStorePassphraseAsChar);
final KeyManager[] km = keyFactory.getKeyManagers();
tlsParams.setKeyManagers(km);
truststore = new File(ksPath);
stream = new FileInputStream(truststore);
keyStore.load(stream, keyStorePassphraseAsChar);
stream.close();
final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
trustFactory.init(keyStore);
final TrustManager[] tm = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(tm);
final SSLContext context = SSLContext.getDefault();
final SSLSocketFactory sf = context.getSocketFactory();
final List<String> cipherSuites = Arrays.asList(sf.getSupportedCipherSuites());
LOG.info(String.format("Suppored cipher suites : %s", cipherSuites.toString()));
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*_EXPORT_.*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
final ClientAuthentication ca = new ClientAuthentication();
ca.setRequired(false);
ca.setWant(false);
tlsParams.setClientAuthentication(ca);
} catch (final Exception e) {
LOG.error("Security configuration failed with the following: " + e.getMessage() + " " + e.getCause());
tlsParams = null;
}
return tlsParams;
}
}
My Server currently starts up quite fine. (At least no errors gets thrown...)
I can also access the given soap method as long as I am using http...
Client class
public class Client {
private static final Logger LOG = Logger.getLogger(Client.class);
private static SoapServiceDefinition client;
public Client(String address, boolean sslEnabled, String ksFile, String ksPass) {
// set keystore setting for plain httpclient
if (sslEnabled) {
LOG.debug(" ... collecting keystore file and passphrase due to enabled ssl.");
System.setProperty("javax.net.ssl.keyStore", ksFile);
System.setProperty("javax.net.ssl.trustStore", ksFile);
System.setProperty("javax.net.ssl.keyStorePassword", ksPass);
System.setProperty("javax.net.ssl.trustStorePassword", ksPass);
}
LOG.debug(" ... creating service factory.");
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(SoapServiceDefinition.class);
LOG.debug(" ... setting host address to '" + address + "'.");
factory.setAddress(address);
LOG.debug(" ... creating actual SOAP-client.");
client = (SoapServiceDefinition) factory.create();
final HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
if (sslEnabled) {
LOG.debug(" ... configuring SSL.");
configureClientSideSSL(httpConduit, ksFile, ksPass);
LOG.debug(" ... done.");
}
LOG.debug(" ... setting timeouts.");
final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
httpClientPolicy.setContentType("application/soap+xml");
httpConduit.setClient(httpClientPolicy);
retrieveAndStoreWSDL(address);
}
private void configureClientSideSSL(final HTTPConduit conduit, final String keyStorePath, final String trustpass) {
try {
final TLSClientParameters tlsParams = new TLSClientParameters();
tlsParams.setDisableCNCheck(true);
final KeyStore keyStore = KeyStore.getInstance("jceks");
final File truststore = new File(keyStorePath);
final FileInputStream stream = new FileInputStream(truststore);
keyStore.load(stream, trustpass.toCharArray());
final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
trustFactory.init(keyStore);
final TrustManager[] tm = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(tm);
final KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("PKIX");
keyFactory.init(keyStore, trustpass.toCharArray());
final KeyManager[] km = keyFactory.getKeyManagers();
tlsParams.setKeyManagers(km);
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*");
include.add(".*_EXPORT_.*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
conduit.setTlsClientParameters(tlsParams);
stream.close();
} catch (final Exception e) {
System.out.println("Security configuration failed with the following: " + e.getCause());
}
}
private void retrieveAndStoreWSDL(final String address) {
LOG.info(" ... retrieving the WSDL-file.");
final HttpClient httpclient = new HttpClient();
httpclient.getParams().setSoTimeout(0); // No timeout at all...in case of big wsdls
final GetMethod get = new GetMethod(address);
get.setQueryString("?wsdl");
try {
final int result = httpclient.executeMethod(get);
final String str = IOUtils.toString(get.getResponseBodyAsStream(), "UTF-8");
LOG.debug(" ... Response status code: " + result);
} catch (final Throwable e) {
LOG.debug("-", e);
LOG.error(e.getClass().getSimpleName() + " occurred during WSDL-retrieval. Won't store current WSDL.");
} finally {
get.releaseConnection();
}
}
public String helloReturn() throws Exception {
return "haha:" + client.handleStateDataRecipience("", "", "");
}
}
The Client is siarting up as well , however, the moment the client tries to retrieve the WSDL and/or tries to execute any of its methods i get:
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
...
As I previously mentioned, everything works fine as long as I use http instead of https.
I don't think that the problem are the keystores as I can finally read them and get their keys by using e.g.
private static void displayKeys(String ksForm, String alias, char[] ksPass, char[] kePass, String keystore) throws Exception {
System.out
.println("---------------------------------------------------------------------------------------------------------------------------");
KeyStore keyStore = KeyStore.getInstance(ksForm);
keyStore.load(new FileInputStream(keystore), ksPass);
Key key = keyStore.getKey(alias, kePass);
if (key instanceof PrivateKey) {
System.out.println("Get private key : ");
System.out.println(key.toString());
java.security.cert.Certificate[] certs = keyStore.getCertificateChain(alias);
System.out.println("Certificate chain length : " + certs.length);
for (Certificate cert : certs) {
System.out.println(cert.toString());
}
} else {
System.out.println("Get public key : ");
System.out.println(key.toString());
}
System.out
.println("---------------------------------------------------------------------------------------------------------------------------");
}
Caused by: java.io.EOFException: SSL peer shut down incorrectly
Thanks in advance and kind regards.
So, I was finally able to figure it out.
Actually there were several Problems at hand
The created keystore itself was fine, the extracted (for client use) cert wasn't
Loading keystore and truststore in both, server and client, was a huge mistake, especially since I've used the same store/certs for both (for this I think WSS4J Interceptors and CallBackHandlers are necessary)
During several trial and error periods I also seems to have mixed up entry and store password.
Below I will give you the code for all the classes that I've used to get a fully running example.
Key And Cert Generation
As I always had problems with the SunAPI and its code examples for certificate creation I decided to use BouncyCastle instead.
Even though I previously decided to not use a 3rd party tool, I changed my mind due to the fact that I use this only for keystore/cert creation.
The class you are about to see is a slightly modified version of the answer from 'Maarten Bodewes' to this question:
How to store and reuse keypair in Java?
The class is pretty straight forward, hence no method comments were added...
package playground.TEST.cxf_soap;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public class BCCertUtils {
public static KeyPair generateKeyPair(int keySize, String keyAlgo, String secureAlgo) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgo != null && !keyAlgo.trim().isEmpty() ? keyAlgo : "RSA");
keyGen.initialize(keySize, secureAlgo != null && !secureAlgo.trim().isEmpty() ? SecureRandom.getInstance(secureAlgo) : new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
return pair;
}
public static Certificate generateSelfSignedCertificate(KeyPair keyPair, String dn, String sigAlg, Date endDate)
throws OperatorCreationException, CertificateException {
// Setting bouncy castle provider to be able to create certs at all...
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
X500Name dnName = new X500Name(dn);
// Using the current timestamp as the certificate serial number
BigInteger certSerialNum = new BigInteger(String.valueOf(System.currentTimeMillis()));
// Setting start date
Date startDate = Calendar.getInstance().getTime();
// Use appropriate signature algorithm based on your keyPair algorithm.
String sigAlgorithm = sigAlg == null || sigAlg.trim().isEmpty() ? "SHA256WithRSA" : sigAlg;
SubjectPublicKeyInfo certPubKey = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(dnName, certSerialNum, startDate, endDate, dnName, certPubKey);
ContentSigner contentSigner = new JcaContentSignerBuilder(sigAlgorithm).setProvider(bcProvider).build(keyPair.getPrivate());
X509CertificateHolder certificateHolder = certBuilder.build(contentSigner);
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
}
public static void storeToPKCS12File(String alias, Certificate selfCert, String filename, char[] ksPass, char[] kePass, PrivateKey privKey)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, OperatorCreationException {
KeyStore p12Store = createP12Store(alias, selfCert, privKey, kePass);
try (FileOutputStream fos = new FileOutputStream(filename)) {
p12Store.store(fos, ksPass);
}
}
public static byte[] storeToPKCS12ByteArray(String alias, Certificate selfCert, char[] ksPass, char[] kePass, PrivateKey privKey)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, OperatorCreationException {
KeyStore p12Store = createP12Store(alias, selfCert, privKey, kePass);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
p12Store.store(bos, ksPass);
return bos.toByteArray();
}
}
private static KeyStore createP12Store(String alias, Certificate selfCert, PrivateKey privKey, char[] kePass)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore p12KeyStore = KeyStore.getInstance("PKCS12");
p12KeyStore.load(null, null);
KeyStore.Entry entry = new PrivateKeyEntry(privKey, new Certificate[] { selfCert });
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(kePass);
p12KeyStore.setEntry(alias, entry, param);
return p12KeyStore;
}
public static boolean moduliMatch(PublicKey originPubKey, PrivateKey certPrivKey) {
return ((RSAPublicKey) originPubKey).getModulus().equals(((RSAPrivateKey) certPrivKey).getModulus());
}
public static KeyPair loadKeysFromPKCS12File(String alias, String filename, char[] storePass, char[] entryPass) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(filename);) {
pkcs12KeyStore.load(fis, storePass);
}
return loadKeyPair(pkcs12KeyStore, alias, entryPass);
}
public static KeyPair loadKeysFromPKCS12ByteArray(String alias, byte[] storeBytes, char[] storePass, char[] entryPass) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (ByteArrayInputStream bis = new ByteArrayInputStream(storeBytes);) {
pkcs12KeyStore.load(bis, storePass);
}
return loadKeyPair(pkcs12KeyStore, alias, entryPass);
}
private static KeyPair loadKeyPair(KeyStore ks, String alias, char[] entryPass)
throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(entryPass);
Entry entry = ks.getEntry(alias, param);
if (!(entry instanceof PrivateKeyEntry)) {
throw new KeyStoreException("That's not a private key!");
}
PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
PublicKey publicKey = privKeyEntry.getCertificate().getPublicKey();
PrivateKey privateKey = privKeyEntry.getPrivateKey();
return new KeyPair(publicKey, privateKey);
}
public static Certificate loadCertFromPKCS12File(String alias, String filename, char[] storePass, char[] entryPass) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(filename);) {
pkcs12KeyStore.load(fis, storePass);
}
return loadCert(pkcs12KeyStore, alias, entryPass);
}
public static Certificate loadCertFromPKCS12ByteArray(String alias, byte[] storeBytes, char[] storePass, char[] entryPass)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException,
UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (ByteArrayInputStream bis = new ByteArrayInputStream(storeBytes);) {
pkcs12KeyStore.load(bis, storePass);
}
return loadCert(pkcs12KeyStore, alias, entryPass);
}
private static Certificate loadCert(KeyStore ks, String alias, char[] entryPass)
throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(entryPass);
Entry entry = ks.getEntry(alias, param);
if (!(entry instanceof PrivateKeyEntry)) {
throw new KeyStoreException("That's not a private key!");
}
PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
return privKeyEntry.getCertificate();
}
public static void storeToPEMFile(Certificate pubCert, String certPath) throws IOException {
JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(certPath));
pw.writeObject(pubCert);
pw.flush();
pw.close();
}
public static byte[] storeToPEMByteArray(Certificate pubCert) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos));
JcaPEMWriter pw = new JcaPEMWriter(writer);
pw.writeObject(pubCert);
pw.flush();
pw.close();
return baos.toByteArray();
}
}
Starter Class
This is the code in which I will actually generate the keys and startup the server and the client, as well as using the clients' methods.
package playground.test.cxf_soap;
import java.security.KeyPair;
import java.security.cert.Certificate;
import java.util.Calendar;
public class Starter {
public static void main(String[] args) {
try {
boolean enableSSL = true;
char[] entryPass = "entryPass".toCharArray();
char[] storePass = "storePass".toCharArray();
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 100);
// Server Store and Client cert.
KeyPair srvKeyPair = BCCertUtils.generateKeyPair(2048, "RSA", "SHA1PRNG");
Certificate srvPrivCert = BCCertUtils.generateSelfSignedCertificate(srvKeyPair, "CN=Test", "SHA256WithRSA", calendar.getTime());
byte[] srvStoreBytes = BCCertUtils.storeToPKCS12ByteArray("alias", srvPrivCert, storePass, entryPass, srvKeyPair.getPrivate());
KeyPair SvrCertKeys = BCCertUtils.loadKeysFromPKCS12ByteArray("alias", srvStoreBytes, storePass, entryPass);
if (!BCCertUtils.moduliMatch(srvKeyPair.getPublic(), SvrCertKeys.getPrivate())) {
System.err.println("ARRGL");
return;
}
Certificate clientCert = BCCertUtils.loadCertFromPKCS12ByteArray("alias", srvStoreBytes, storePass, entryPass);
byte[] clientCertBytes = BCCertUtils.storeToPEMByteArray(clientCert);
Server server = new Server(443, enableSSL, srvStoreBytes, storePass, entryPass);
while (!server.isRunning()) {
Thread.sleep(10);
}
Client client = new Client("https://localhost:" + 443 + "/signtest/", enableSSL, clientCertBytes);
System.out.println("Hello SOAP-Server :)");
System.out.println(" -> " + client.helloReturn("Stahler"));
System.out.println("Could you tell me if it is working?");
System.out.println(" -> " + client.isItWorking());
System.out.println("Awww finally, thank you server and goodbye.");
System.out.println(" -> " + client.gbyeReturn("Stahler"));
System.exit(0);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Server class
Following now I will show you my Server class In which I import the previously created PKCS12 store and adjust TLS Settings to work with the client.
package playground.mstahl.cxf_soap;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.List;
import javax.jws.WebService;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.configuration.security.ClientAuthentication;
import org.apache.cxf.configuration.security.FiltersType;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory;
public class Server extends Thread {
private boolean isRunning = false;
#WebService(name = "SoapService", serviceName = "SoapService", endpointInterface = "playground.mstahl.cxf_soap.SoapServiceDefinition")
private static final class ServerImpl implements SoapServiceDefinition {
#Override
public String sayHelloToMe(String caller) throws Exception {
return "oh Hello " + caller + ".";
}
#Override
public String askFunctionality() throws Exception {
return "Well, as I am answering I guess its working...duh";
}
#Override
public String sayGoodbyeToMe(String caller) throws Exception {
return "Goodbye doucheb...i mean..." + caller + ".";
}
}
private final int usedPort;
private final byte[] storeBytes;
private final char[] storePass;
private final char[] entryPass;
private final boolean sslEnabled;
public Server(int port, boolean sslEnabled, byte[] storeBytes, char[] storePass, char[] entryPass) {
super("CXF-SOAP-Playground");
setDaemon(true);
usedPort = port;
this.sslEnabled = sslEnabled;
this.storeBytes = storeBytes;
this.storePass = storePass;
this.entryPass = entryPass;
start();
}
#Override
public void run() {
System.out.println(" ... creating factory.");
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
System.out.println(" ... setting address and implementing service.");
sf.setAddress(String.format("http" + (sslEnabled ? "s" : "") + "://localhost:%d/signtest/", Integer.valueOf(usedPort)));
sf.setServiceClass(ServerImpl.class);
System.out.println(" ... setting up service bean.");
ServerImpl serviceBean = new ServerImpl();
sf.setServiceBean(serviceBean);
if (sslEnabled) {
try {
JettyHTTPServerEngineFactory factory = sf.getBus().getExtension(JettyHTTPServerEngineFactory.class);
factory.setTLSServerParametersForPort(usedPort, getTLSServerParameters());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(" ... starting actual SOAP-server.");
org.apache.cxf.endpoint.Server server = sf.create();
Endpoint endpoint = server.getEndpoint();
String endpointAddr = endpoint.getEndpointInfo().getAddress();
System.out.println("Server started at " + endpointAddr);
if (!server.isStarted()) {
return;
}
isRunning = true;
System.out.println("... done.");
while (!isInterrupted()) {
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
System.out.println("... stopping actual SOAP-server.");
server.stop();
System.out.println("... destroying its remnants.");
server.destroy();
}
public boolean isRunning() {
return isRunning;
}
private final TLSServerParameters getTLSServerParameters() {
TLSServerParameters tlsParams = null;
try {
// 1 - Load key store
KeyStore localKeyStore = KeyStore.getInstance("PKCS12");
localKeyStore.load(new ByteArrayInputStream(storeBytes), storePass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(localKeyStore, entryPass);
// 2 - Add the new keyManager to the tls settings.
tlsParams = new TLSServerParameters();
tlsParams.setKeyManagers(kmf.getKeyManagers());
// 3 - Adjust cipher suite filters
final List<String> cipherSuites = Arrays.asList(SSLContext.getDefault().getSocketFactory().getSupportedCipherSuites());
System.out.println(String.format("Suppored cipher suites : %s", cipherSuites.toString()));
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
// 4 - Disable client authentication
final ClientAuthentication ca = new ClientAuthentication();
ca.setRequired(false);
ca.setWant(false);
tlsParams.setClientAuthentication(ca);
} catch (final Exception e) {
e.printStackTrace();
System.err.println("Security configuration failed with the following: " + e.getMessage() + " " + e.getCause());
tlsParams = null;
}
return tlsParams;
}
}
Client Class
Last but not least, a small client class in which I imported the certificate which I previously exported from the servers keystore.
package playground.mstahl.cxf_soap;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.security.FiltersType;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.System.out.println4j.System.out.printlnger;
public class Client {
private static SoapServiceDefinition client;
public Client(String address, boolean sslEnabled, byte[] remoteCertBytes) {
System.out.println(" ... creating service factory.");
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(SoapServiceDefinition.class);
System.out.println(" ... setting host address to '" + address + "'.");
factory.setAddress(address);
System.out.println(" ... creating actual SOAP-client.");
client = (SoapServiceDefinition) factory.create();
final HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
if (sslEnabled) {
System.out.println(" ... configuring SSL.");
configureClientSideSSL(httpConduit, remoteCertBytes);
System.out.println(" ... done.");
}
System.out.println(" ... setting timeouts.");
final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
httpClientPolicy.setContentType("application/soap+xml");
httpConduit.setClient(httpClientPolicy);
try {
retrieveAndStoreWSDL(sslEnabled, address);
} catch (Exception e) {
e.printStackTrace();
}
}
private void configureClientSideSSL(final HTTPConduit conduit, byte[] remoteCertBytes) {
TLSClientParameters tlsParams = null;
try {
// 1 - Load the remote certificate
ByteArrayInputStream bis = new ByteArrayInputStream(remoteCertBytes);
X509Certificate remoteCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(new BufferedInputStream(bis));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry(Integer.toString(1), remoteCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
// 2 - Add the new trustmanager to the tls settings.
tlsParams = new TLSClientParameters();
tlsParams.setTrustManagers(tmf.getTrustManagers());
// 3 - Disable CN check
tlsParams.setDisableCNCheck(true);
// 4 - Set default SSL-context (necessary for e.g. the wsdl retrieval)
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLContext.setDefault(context);
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*");
include.add(".*_EXPORT_.*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
conduit.setTlsClientParameters(tlsParams);
} catch (final Exception e) {
e.printStackTrace();
System.out.println("Security configuration failed with the following: " + e.getCause());
}
}
private void retrieveAndStoreWSDL(boolean sslEnabled, final String address) throws Exception {
System.out.println(" ... retrieving the WSDL-file."); // TODO ssl enabled check (Necessary if we do this beforehand?)
URL wsdlUrl = new URL(address + "?wsdl");
URLConnection connection = wsdlUrl.openConnection();
HttpsURLConnection conn = (HttpsURLConnection) connection;
if (sslEnabled) {
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
conn.setRequestMethod("GET");
conn.connect();
String wsdl = IOUtils.toString(conn.getInputStream(), Charset.defaultCharset());
System.err.println(wsdl);
conn.disconnect();
}
public String helloReturn(String caller) throws Exception {
return client.sayHelloToMe(caller);
}
public String isItWorking() throws Exception {
return client.askFunctionality();
}
public String gbyeReturn(String caller) throws Exception {
return client.sayGoodbyeToMe(caller);
}
}
Thanks to everyone who read my question and thought of a possible solution.
Hopefully this can help others .
Kind regards
I used httpclient 4.4 to send get and post request. and i just created a simpile wrapper of httpclient for easy use:
package com.u8.server.sdk;
import com.sun.net.httpserver.Headers;
import com.u8.server.log.Log;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.CookiePolicy;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Created by ant on 2015/10/12.
*/
public class UHttpAgent {
private int connectTimeout = 5000; //5s
private int socketTimeout = 5000; //5s
private int maxTotalConnections = 200;
private static UHttpAgent instance;
private CloseableHttpClient httpClient;
private UHttpAgent(){
}
public static UHttpAgent getInstance(){
if(instance == null){
instance = new UHttpAgent();
}
return instance;
}
public static UHttpAgent newInstance(){
return new UHttpAgent();
}
public String get(String url, Map params){
return get(url, null, params, "UTF-8");
}
public String post(String url, Map params){
return post(url, null, params, "UTF-8");
}
public String get(String url , Map headers, Map params, String encoding){
if(this.httpClient == null){
init();
}
String fullUrl = url;
String urlParams = parseGetParams(params, encoding);
if (urlParams != null)
{
if (url.contains("?"))
{
fullUrl = url + "&" + urlParams;
}
else
{
fullUrl = url + "?" + urlParams;
}
}
Log.d("the full url is "+ fullUrl);
HttpGet getReq = new HttpGet(fullUrl.trim());
getReq.setHeaders(parseHeaders(headers));
ResponseHandler responseHandler = new ResponseHandler() {
#Override
public String handleResponse(HttpResponse httpResponse) throws IOException {
HttpEntity entity = httpResponse.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
}
};
try {
String res = httpClient.execute(getReq, responseHandler);
return res;
} catch (Exception e) {
e.printStackTrace();
}finally {
getReq.releaseConnection();
}
return null;
}
public String post(String url, Map headers, Map params, String encoding){
List pairs = new ArrayList();
if(params != null){
for(String key : params.keySet()){
pairs.add(new BasicNameValuePair(key, params.get(key)));
}
}
return post(url, headers, new UrlEncodedFormEntity(pairs, Charset.forName(encoding)));
}
public String post(String url, Map headers, HttpEntity entity){
if(this.httpClient == null) {
init();
}
HttpPost httpPost = new HttpPost(url);
httpPost.setHeaders(parseHeaders(headers));
httpPost.setEntity(entity);
ResponseHandler responseHandler = new ResponseHandler() {
#Override
public String handleResponse(HttpResponse httpResponse) throws IOException {
HttpEntity entity = httpResponse.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
}
};
try {
String body = httpClient.execute(httpPost, responseHandler);
return body;
} catch (IOException e) {
e.printStackTrace();
}finally {
httpPost.releaseConnection();
}
return null;
}
private Header[] parseHeaders(Map headers){
if(null == headers || headers.isEmpty()){
return getDefaultHeaders();
}
Header[] hs = new BasicHeader[headers.size()];
int i = 0;
for(String key : headers.keySet()){
hs[i] = new BasicHeader(key, headers.get(key));
i++;
}
return hs;
}
private Header[] getDefaultHeaders(){
Header[] hs = new BasicHeader[2];
hs[0] = new BasicHeader("Content-Type", "application/x-www-form-urlencoded");
hs[1] = new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");
return hs;
}
private String parseGetParams(Map data, String encoding){
if(data == null || data.size() keyItor = data.keySet().iterator();
while(keyItor.hasNext()){
String key = keyItor.next();
String val = data.get(key);
try {
result.append(key).append("=").append(URLEncoder.encode(val, encoding).replace("+", "%2B")).append("&");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return result.deleteCharAt(result.length() - 1).toString();
}
private void init(){
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(connectTimeout)
.setSocketTimeout(socketTimeout)
.setExpectContinueEnabled(true)
.setAuthenticationEnabled(true)
.build();
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
#Override
public boolean retryRequest(IOException e, int retryNum, HttpContext httpContext) {
if(retryNum >= 3){
return false;
}
if(e instanceof org.apache.http.NoHttpResponseException
|| e instanceof org.apache.http.client.ClientProtocolException
|| e instanceof java.net.SocketException){
return true;
}
return false;
}
};
try{
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslFactory)
.build();
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
connMgr.setMaxTotal(maxTotalConnections);
connMgr.setDefaultMaxPerRoute((connMgr.getMaxTotal()));
HttpClientBuilder builder = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.setSslcontext(sslContext)
.setConnectionManager(connMgr)
.setRetryHandler(retryHandler);
this.httpClient = builder.build();
}catch (Exception e){
e.printStackTrace();
}
}
public HttpClient getHttpClient(){
return this.httpClient;
}
public void destroy(){
if(this.httpClient != null){
try{
this.httpClient.close();
this.httpClient = null;
}catch (Exception e){
e.printStackTrace();
}
}
}
}
when I use this class to send post request. something strange happened:
the first time, I send a post request to the server, it's ok
after a minutes, I send a same request to the server, it's ok too.
but after a few minutes, I send a same request, something wrong:
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at org.apache.http.impl.conn.LoggingOutputStream.write(LoggingOutputStream.java:77)
at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:126)
at org.apache.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:138)
at org.apache.http.impl.io.SessionOutputBufferImpl.flush(SessionOutputBufferImpl.java:146)
at org.apache.http.impl.BHttpConnectionBase.doFlush(BHttpConnectionBase.java:175)
at org.apache.http.impl.DefaultBHttpClientConnection.flush(DefaultBHttpClientConnection.java:185)
at org.apache.http.impl.conn.CPoolProxy.flush(CPoolProxy.java:177)
at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:215)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:122)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:271)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:220)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:164)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:139)
at com.u8.server.sdk.UHttpAgent.post(UHttpAgent.java:259)
at com.u8.server.sdk.UHttpAgent.post(UHttpAgent.java:147)
at com.u8.server.sdk.baidu.BaiduSDK.verify(BaiduSDK.java:30)
at com.u8.server.web.UserAction.getLoginToken(UserAction.java:100)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
but then , I still send a same request to the server, it's ok again.
Every time I tried according to the above steps, The same thing happened.
Anyone can help me ? Thanks a lot.
The peer of your client is the server. So "Connection reset by peer" means the server reset the socket. Reset means forceably closed.
This might be because of a bug in the server. If you also wrote the server or servlet (as will be the case for a custom protocol), you need to examine the behaviour of the server to examine the cause of this. The log files of the server might provide clues.
If the server has protection against bisbehaving or malicious clients, the server might have reset the socket because it has classified your client as misbehaving. If you implemented the client protocol code it might be because of a bug in your protocol implementation. If you are using third party code for handling the communication protocol you might still be misusing it; for example by sending excessively large requests. It is not uncommon for HTTP servers to protect themselves against denial of service attacks by imposing maximum lengths for header fields and bodies, and to require that clients send data at a reasonably fast rate (without pausing for long periods). Your client might have fallen foul of these protections.