简体   繁体   中英

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. 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).

The problem is that I cannot control how the JVM is started that will run my java application - eg by adding:

-Djavax.net.ssl.trustStore=/usr/local/comp.jks to the VM arguments.

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?

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

Below my current implementation (in 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

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 .

If the default SSL infrastructure has alredy been instantiated, you'll probably have to create your own SSLContext and SSLSocketFactory using your keystore.

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. 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]);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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