Java SSL - 使用 pkcs12 (.p12) 文件连接到安全 Rest 服务
Java SSL - Connect to secure Rest Service using pkcs12 (.p12) file
我正在为我的 Web 应用程序使用休息服务。并且服务提供商提供了一个带有密码的 .p12 文件以连接到他们的服务。
出于测试目的,我在 postman 中安装了证书文件,它有效 fine.Now 我必须将它集成到我的 java 代码中。
这是我的 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);
}
}
}
我总是得到如下的回复。这与我在未向其添加证书文件的情况下使用 postman 对其进行测试时得到的响应相同。
400 Bad Request:{
"error": {
"message": "No SSL cetificate"
}
}
有人可以指出我在这里做错了什么吗?
我是 java 安全方面的新手 area.To 老实说,我是按照指南写的 code/Is 尝试连接时有一个清单可以遵循吗? (比如将文件添加到密钥库或 truststore.At 至少有一个指南可以帮助我)
非常感谢。
你能试试这段代码吗?我对加载信任库做了一些更改。确保从您的代码中传递系统信任库的路径。
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: 我无法验证此代码,因为我没有证书和密钥。 :)
您不必硬编码任何东西来让它工作,只需为 Java 添加一些启动参数,例如:
-Djavax.net.ssl.keyStore=C:\Users\my_cert.p12
。 (尽管它们随后被应用程序中的所有线程和代码 运行 共享,这可能是不可接受的)检查这个问题和提供的答案:
java SSL and cert keystore
此外,了解幕后发生的事情可能非常有用,您可以通过启用一些额外的日志记录来查看这些幕后情况,例如:
-Djavax.net.debug=all
试试这个 approach.I 无法测试这个,因为我没有证书文件,但我希望稍作修改,它会起作用。
请将您的证书文件包含在资源文件夹中。
@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;
}
}
如果有效请告诉我。
我正在为我的 Web 应用程序使用休息服务。并且服务提供商提供了一个带有密码的 .p12 文件以连接到他们的服务。
出于测试目的,我在 postman 中安装了证书文件,它有效 fine.Now 我必须将它集成到我的 java 代码中。
这是我的 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);
}
}
}
我总是得到如下的回复。这与我在未向其添加证书文件的情况下使用 postman 对其进行测试时得到的响应相同。
400 Bad Request:{
"error": {
"message": "No SSL cetificate"
}
}
有人可以指出我在这里做错了什么吗?
我是 java 安全方面的新手 area.To 老实说,我是按照指南写的 code/Is 尝试连接时有一个清单可以遵循吗? (比如将文件添加到密钥库或 truststore.At 至少有一个指南可以帮助我)
非常感谢。
你能试试这段代码吗?我对加载信任库做了一些更改。确保从您的代码中传递系统信任库的路径。
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: 我无法验证此代码,因为我没有证书和密钥。 :)
您不必硬编码任何东西来让它工作,只需为 Java 添加一些启动参数,例如:
-Djavax.net.ssl.keyStore=C:\Users\my_cert.p12
。 (尽管它们随后被应用程序中的所有线程和代码 运行 共享,这可能是不可接受的)检查这个问题和提供的答案:
java SSL and cert keystore
此外,了解幕后发生的事情可能非常有用,您可以通过启用一些额外的日志记录来查看这些幕后情况,例如:
-Djavax.net.debug=all
试试这个 approach.I 无法测试这个,因为我没有证书文件,但我希望稍作修改,它会起作用。
请将您的证书文件包含在资源文件夹中。
@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;
}
}
如果有效请告诉我。