java 如何将 jar 中的文件用作 javax.net.ssl.keystore?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/344748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:02:09  来源:igfitidea点击:

How to use a file in a jar as javax.net.ssl.keystore?

javajarexecutable-jar

提问by darrickc

I'm trying to do something like

我正在尝试做类似的事情

URL clientks = com.messaging.SubscriptionManager.class.getResource( "client.ks" );
String path = clientks.toURI().getPath();
System.setProperty( "javax.net.ssl.keyStore", path);

Where client.ks is a file stored in com/messaging in the jar file that I'm running.

其中 client.ks 是存储在我正在运行的 jar 文件中的 com/messaging 中的文件。

The thing that reads the javax.net.ssl.keyStore is expecting a path to the client.ks file which is in the jar. I'd rather not extract the file and put in on the client's machine if possible. So is it possible to reference a file in a jar?

读取 javax.net.ssl.keyStore 的东西需要一个路径到 jar 中的 client.ks 文件。如果可能的话,我宁愿不提取文件并将其放在客户端的机器上。那么是否可以引用 jar 中的文件?

This doesn't work as getPath() returns null. Is there another way to do this?

这不起作用,因为 getPath() 返回 null。有没有其他方法可以做到这一点?

回答by user2529737

Still working on implementation, but I believe it is possible to load the keystore from the jar via InputStream and explicitly set the TrustStore programatically (vs setting the System properties). See the article: Setting multiple truststore on the same JVM

仍在实施中,但我相信可以通过 InputStream 从 jar 加载密钥库并以编程方式显式设置 TrustStore(与设置系统属性相比)。请参阅文章:在同一个 JVM 上设置多个信任库

Got it working!

搞定了!

InputStream keystoreInput = Thread.currentThread().getContextClassLoader()
    .getResourceAsStream(<path in jar>/client.ks");
InputStream truststoreInput = Thread.currentThread().getContextClassLoader()
    .getResourceAsStream(<path in jar>/client.ts");
setSSLFactories(keystoreInput, "password", truststoreInput);
keystoreInput.close();
truststoreInput.close();

private static void setSSLFactories(InputStream keyStream, String keyStorePassword, 
    InputStream trustStream) throws Exception
{    
  // Get keyStore
  KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());    

  // if your store is password protected then declare it (it can be null however)
  char[] keyPassword = keyStorePassword.toCharArray();

  // load the stream to your store
  keyStore.load(keyStream, keyPassword);

  // initialize a key manager factory with the key store
  KeyManagerFactory keyFactory = 
  KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());    
  keyFactory.init(keyStore, keyPassword);

  // get the key managers from the factory
  KeyManager[] keyManagers = keyFactory.getKeyManagers();

  // Now get trustStore
  KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());    

  // if your store is password protected then declare it (it can be null however)
  //char[] trustPassword = password.toCharArray();

  // 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();

  // initialize an ssl context to use these managers and set as default
  SSLContext sslContext = SSLContext.getInstance("SSL");
  sslContext.init(keyManagers, trustManagers, null);
  SSLContext.setDefault(sslContext);    
}

回答by Jason Day

You can get an InputStreamto a resource in a jar file, but not a File. If the "thing" that ultimately reads the keystore expects a Fileor a path to a file, your only option is to extract it to the filesystem.

您可以获取InputStreamjar 文件中的资源,但不能获取File. 如果最终读取密钥库的“事物”需要File文件的路径或路径,则唯一的选择是将其提取到文件系统。

回答by eis

Here's a cleaned-up version of user2529737's answer, in case it helps. It has removed unneeded trust store setup and added required imports, parameters for keystore type and key password.

这是user2529737's answer的清理版本,以防万一。它删除了不需要的信任存储设置并添加了必需的导入、密钥库类型和密钥密码的参数。

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyStore;

public class PlainJavaHTTPS2Test {

    public void setUp() throws Exception {
        final String KEYSTOREPATH = "clientkeystore.p12"; // or .jks

        // store password can be null if there is no password
        final char[] KEYSTOREPASS = "keystorepass".toCharArray();

        // key password can be null if there is no password
        final char[] KEYPASS = "keypass".toCharArray();

        try (InputStream storeStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) {
            setSSLFactories(storeStream, "PKCS12", KEYSTOREPASS, KEYPASS);
        }
    }
    private static void setSSLFactories(InputStream keyStream, String keystoreType, char[] keyStorePassword, char[] keyPassword) throws Exception
    {
        KeyStore keyStore = KeyStore.getInstance(keystoreType);

        keyStore.load(keyStream, keyStorePassword);

        KeyManagerFactory keyFactory =
                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

        keyFactory.init(keyStore, keyPassword);

        KeyManager[] keyManagers = keyFactory.getKeyManagers();

        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(keyManagers, null, null);
        SSLContext.setDefault(sslContext);
    }
}