简体   繁体   English

Java SSL - 使用 pkcs12 (.p12) 文件连接到安全 Rest 服务

[英]Java SSL - Connect to secure Rest Service using pkcs12 (.p12) file

I am consuming a rest service for my web application.我正在为我的 web 应用程序使用 rest 服务。 And the service provider has provided a.p12 file with a password to connect to their service.并且服务提供商提供了一个带有密码的.p12 文件来连接到他们的服务。

I installed the certificate file in postman for testing purposes and it works fine.Now I have to integrate it to my java code.我在 postman 中安装了证书文件以进行测试,它工作正常。现在我必须将它集成到我的 java 代码中。

This is my java code for integration.这是我的 java 集成代码。

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

@Service
public class DemoIntegration
{

    String key = "XYX";
    String value = "12BN";
    String encVal= "343fhh22343mm90ddfd61lcsert";
    private static String certPw = "44vvxxffx";  //Password to cerfificate file

    public void checkConnection()
    {
        try
        {
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders httpHeaders = new HttpHeaders();

            String uri = "https://my_demo_uri";

            KeyStore ks = KeyStore.getInstance("pkcs12");
            ks.load(new FileInputStream("C:\\Users\\my_cert.p12"), certPw.toCharArray()); //my_cert.p12 is my cerfificate file 

            KeyStore jks = KeyStore.getInstance("JKS");
            jks.load(null);

            for (Enumeration<String> t = ks.aliases(); t.hasMoreElements();)
            {
                String alias = t.nextElement();
                System.out.println("@:" + alias);
                if (ks.isKeyEntry(alias))
                {
                    Certificate[] a = ks.getCertificateChain(alias);
                    for (int i = 0; i < a.length; i++)
                    {
                        X509Certificate x509 = (X509Certificate) a[i];
                        System.out.println(x509.getSubjectDN().toString());
                        if (i > 0)
                        {
                            jks.setCertificateEntry(x509.getSubjectDN().toString(), x509);
                        }
                        System.out.println(ks.getCertificateAlias(x509));
                        System.out.println("ok");
                    }
                }
            }

            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(ks, certPw.toCharArray());

            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(jks);

            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            httpHeaders.set("API_KEY", api_key);
            httpHeaders.set("Signature", SHA256Val);

            String r2 = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class).getBody();
            System.out.println("Result " + r2);
        }
        catch (Exception ex)
        {
            System.out.println("Error " + ex.toString());
            Logger.getLogger(DemoIntegration.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

And always I get the response like below.我总是得到如下回复。 This is the same response I got when I tested it with postman without adding the certificate file to it.这与我在没有添加证书文件的情况下使用 postman 对其进行测试时得到的响应相同。

400 Bad Request:{
  "error": {
    "message": "No SSL cetificate"
  }
}

Can someone point out what am I doing wrong here?有人可以指出我在这里做错了什么吗?

I am a newbie when it comes to java security area.To be honest I followed a guide to write this code/Is there a checklist to follow when trying to connect?我是 java 安全区域的新手。老实说,我按照指南编写此代码/尝试连接时是否有要遵循的清单? (Like adding the file to keystore or truststore.At least a guide would help me here) (就像将文件添加到密钥库或信任库一样。至少有一个指南可以帮助我)

Thanks a lot in advance.提前非常感谢。

Can you give this code a try?你可以试试这个代码吗? I have made some changes to the load Truststore.我对负载信任库进行了一些更改。 Make sure to pass the path of the system Truststore from your code.确保从您的代码中传递系统信任库的路径。

package com.jerry;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.*;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;


public class SSLTest {
    private String api_key = "XYX";
    private  String api_secret = "12BN";
    private String SHA256Val = "343fhh633343mm90ddfd61lcsert";
    private static String certPw = "44vvxxffx";  //

    String trustStorePath = "C:/Program Files/Java/jre1.8.0_91/lib/security/cacerts";
    String trustStorePassword = "changeit"; // default trust store password

    public void checkConnection()
    {
        try
        {
//            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders httpHeaders = new HttpHeaders();

            String uri = "https://my_demo_uri";

            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(new FileInputStream("C:\\Users\\IB\\Downloads\\my_cert.p12"), certPw.toCharArray()); //my_cert.p12 is my cerfificate file

            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, certPw.toCharArray());
            KeyManager[] kms = kmf.getKeyManagers();

            KeyStore jks = KeyStore.getInstance("JKS");
            jks.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
//
//            for (Enumeration<String> t = ks.aliases(); t.hasMoreElements();)
//            {
//                String alias = t.nextElement();
//                System.out.println("@:" + alias);
//                if (ks.isKeyEntry(alias))
//                {
//                    Certificate[] a = ks.getCertificateChain(alias);
//                    for (int i = 0; i < a.length; i++)
//                    {
//                        X509Certificate x509 = (X509Certificate) a[i];
//                        System.out.println(x509.getSubjectDN().toString());
//                        if (i > 0)
//                        {
//                            jks.setCertificateEntry(x509.getSubjectDN().toString(), x509);
//                        }
//                        System.out.println(ks.getCertificateAlias(x509));
//                        System.out.println("ok");
//                    }
//                }
//            }


            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(jks);
            TrustManager[] tms = tmf.getTrustManagers();


            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
            SSLSocketFactory socketFactory = new SSLSocketFactory(ks, certPw, jks);

            HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(
                    socketFactory).build();
            ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
                    httpClient);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            httpHeaders.set("API_KEY", api_key);
            httpHeaders.set("Signature", SHA256Val);

            HttpEntity<String> entity = new HttpEntity<>("body", httpHeaders);

            String r2 = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class).getBody();
            System.out.println("Result " + r2);
        }
        catch (Exception ex)
        {
            System.out.println("Error " + ex.toString());
        }
    }
}

PS: I could not validate this code because i dont have the certificate and key. PS:我无法验证此代码,因为我没有证书和密钥。 :) :)

You should not have to hardcode anything to get this to work but just add some startup parameters for Java, like:您不必硬编码任何东西来使其工作,只需为 Java 添加一些启动参数,例如:

-Djavax.net.ssl.keyStore=C:\Users\my_cert.p12

. . (although they are then shared by all threads and code running in your application which may not be acceptable) Check out this question and the answers provided: (尽管它们随后被应用程序中运行的所有线程和代码共享,这可能是不可接受的)查看这个问题和提供的答案:

java SSL and cert keystore java SSL 和证书密钥库

Further it can be very useful to know what is going on behind the curtain which you can see with some extra logging enabled with eg:此外,了解幕后发生的事情可能非常有用,您可以通过启用一些额外的日志记录来看到这些情况,例如:

-Djavax.net.debug=all

Try this approach.I cannot test this since I do not have the certificate file but I hope with some minor modifications,it will work.试试这个方法。我无法测试这个,因为我没有证书文件,但我希望通过一些小的修改,它会起作用。

Please include your certificate file in the resources folder.请将您的证书文件包含在资源文件夹中。

@Service
public class DemoIntegration
{
    String key = "XYX";
    String value = "12BN";
    String encVal= "343fhh22343mm90ddfd61lcsert";
    private static String certPw = "44vvxxffx";

    public void checkConnection()
    {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.set("API_KEY", api_key);
        httpHeaders.set("Signature", SHA256Val);

        String uri = "https://my_demo_uri";

        try
        {
            RestTemplate restTemplate = getRestTemplateClientAuthentication();

            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            httpHeaders.set("API_KEY", api_key);
            httpHeaders.set("Signature", SHA256Val);

            String r2 = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class).getBody();
            System.out.println("Result " + r2);
        }
        catch (Exception ex)
        {
            System.out.println("Error " + ex.toString());
            Logger.getLogger(PesonetService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private RestTemplate getRestTemplateClientAuthentication() throws Exception
    {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(ResourceUtils.getFile("classpath:my_cert.p12"),
                 certPw.toCharArray(), certPw.toCharArray())
                .build();

        CloseableHttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();

        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(client);

        RestTemplate restTemplate = new RestTemplate(requestFactory);
        return restTemplate;
    }
}

Let me know if it works.让我知道它是否有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM