[英]Load java trust store at runtime - after jvm have been launched?
In my java application I need to send POST requests to a server sitting behind https.在我的 Java 应用程序中,我需要将 POST 请求发送到位于 https 后面的服务器。 On the machine where my java application is running there is a java trust store in:
/usr/local/comp.jks
that contains the certificate for the server I need to interact with (its already imported).在运行我的 java 应用程序的机器上有一个 java 信任存储:
/usr/local/comp.jks
包含我需要与之交互的服务器的证书(它已经导入)。
The problem is that I cannot control how the JVM is started that will run my java application - eg by adding:问题是我无法控制如何启动将运行我的 java 应用程序的 JVM - 例如通过添加:
-Djavax.net.ssl.trustStore=/usr/local/comp.jks
to the VM arguments. -Djavax.net.ssl.trustStore=/usr/local/comp.jks
到 VM 参数。
Is it possible to load the trust store in the above path at runtime from my application after the JVM has started so I can authenticate against the https site?在 JVM 启动后,是否可以在运行时从我的应用程序加载上述路径中的信任存储,以便我可以针对 https 站点进行身份验证?
I have only found guides on how to import certificates at runtime but that I cannot use - also since I don't have the password for /usr/local/comp.jks
我只找到了有关如何在运行时导入证书的指南,但我无法使用 - 也是因为我没有
/usr/local/comp.jks
的密码
Below my current implementation (in groovy):在我当前的实现下面(在 groovy 中):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.Base64;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpsClientImpl extends AbstractHttpClient {
private String username = null;
private String password = null;
public HttpsClientImpl (String username, String password) {
this.username=username;
this.password=password;
}
@Override
public String sendRequest(String request, String method) {
System.setProperty( "javax.net.ssl.trustStore", "/usr/local/comp.jks" );
URL url = new URL(request);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection()
// Set auth
byte[] name = (username + ":" + password).getBytes();
String authStr = Base64.getEncoder().encodeToString(name);
con.setRequestProperty("Authorization", "Basic " + authStr)
con.setRequestMethod(method);
writeResult(con);
return con.getResponseCode();
}
private void writeResult(HttpsURLConnection con) throws IOException {
if(con!=null){
BufferedReader br = null;
if (200 <= con.getResponseCode() && con.getResponseCode() <= 299) {
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
} else {
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
}
try {
String input;
while ((input = br.readLine()) != null){
System.out.println(input);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
When I run that I get:当我运行时,我得到:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
Caused: sun.security.validator.ValidatorException: PKIX path building failed
Assuming you haven't instantiated any SSL connections yet, you can simply call假设您还没有实例化任何 SSL 连接,您可以简单地调用
System.setProperty( "javax.net.ssl.trustStore", "/usr/local/comp.jks" );
You'll probably also need to set javax.net.ssl.trustStorePassword
and maybe javax.net.ssl.trustStoreType
.您可能还需要设置
javax.net.ssl.trustStorePassword
和javax.net.ssl.trustStoreType
。
If the default SSL infrastructure has alredy been instantiated, you'll probably have to create your own SSLContext
and SSLSocketFactory
using your keystore.如果默认 SSL 基础结构已经实例化,您可能必须使用您的密钥库创建您自己的
SSLContext
和SSLSocketFactory
。
You can load the truststore in you class.您可以在类中加载信任库。 What I would suggest is to use both your truststore and load the JDK truststore and use both.
我的建议是同时使用您的信任库并加载 JDK 信任库并同时使用两者。 Here I am giving and example regarding how you can do it.
在这里,我给出了有关如何做到这一点的示例。
public class TrustManagerComposite implements X509TrustManager {
private final List<X509TrustManager> compositeTrustmanager;
public TrustManagerComposite() {
List<X509TrustManager> trustManagers = new ArrayList<>();
try (InputStream truststoreInput = PATH_TO_YOUR_TRUSTSTORE) {
trustManagers.add(getCustomTrustmanager(truststoreInput));
trustManagers.add(getDefaultTrustmanager());
} catch (Exception e) {
//log it
}
compositeTrustmanager = trustManagers;
}
private static X509TrustManager getCustomTrustmanager(InputStream trustStream) throws Exception {
return createTrustManager(trustStream);
}
private static X509TrustManager getDefaultTrustmanager() throws Exception {
return createTrustManager(null);
}
private static X509TrustManager createTrustManager(InputStream trustStream) throws Exception {
// Now get trustStore
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// load the stream to your store
trustStore.load(trustStream, null);
// initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
// get the trust managers from the factory
TrustManager[] trustManagers = trustFactory.getTrustManagers();
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
for (X509TrustManager trustManager : compositeTrustmanager) {
try {
trustManager.checkClientTrusted(chain, authType);
return;
} catch (CertificateException e) {
// maybe the next trust manager will trust it, don't break the loop
}
}
throw new CertificateException("None of the TrustManagers trust this certificate chain");
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
for (X509TrustManager trustManager : compositeTrustmanager) {
try {
trustManager.checkServerTrusted(chain, authType);
return;
} catch (CertificateException e) {
// maybe the next trust manager will trust it, don't break the loop
}
}
throw new CertificateException("None of the TrustManagers trust this certificate chain");
}
@Override
public X509Certificate[] getAcceptedIssuers() {
List<X509Certificate> certs = new ArrayList<>();
for (X509TrustManager trustManager : compositeTrustmanager) {
for (X509Certificate cert : trustManager.getAcceptedIssuers()) {
certs.add(cert);
}
}
return certs.toArray(new X509Certificate[0]);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.