2010-05-10 89 views
7

需要一些指导。Java Webstart Truststore SSL

我有java webstart应用程序,我希望它通过SSL连接到服务器。只需添加如下属性:System.setProperty(“javax.net.ssl.trustStore”,“my.keystore”);但既然从服务器下载的JAWS程序无法正常工作,并且本地文件系统上没有my.keystore。所以决定将证书分发给所有的客户。我做了以下工作。

  1. 以流的形式读取此信任存储(使用getResourceAsStream方法)。
  2. 将其保存在客户机上的任何文件中(sometemp)
  3. 调用System.setProperty(“javax.net.ssl.trustStore”,trustStorePath);

但我相信肯定有比这更好的解决方案..任何想法,使其更好?

​​

-Padur =========================== ** =========== ==

/** 

* */

package util; 

/** 
* @author spaduri 
* 
*/ 
import java.io.IOException; 
import java.net.InetAddress; 
import java.net.Socket; 

import javax.net.SocketFactory; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.SSLSocketFactory; 
import javax.net.ssl.TrustManager; 

public class CustomSSLSocketFactory extends SSLSocketFactory { 

    private SSLSocketFactory factory; 

    public CustomSSLSocketFactory() { 
     try { 
      SSLContext sslcontext = null; 
       // Call getKeyManagers to get suitable key managers 
      KeyManager[] kms=getKeyManagers(); 
      if (sslcontext == null) { 
       sslcontext = SSLContext.getInstance("SSL"); 
       sslcontext.init(kms, 
       new TrustManager[] { new CustomTrustManager() }, 
       new java.security.SecureRandom()); 
      } 
      factory = (SSLSocketFactory) sslcontext.getSocketFactory(); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 


    public static SocketFactory getDefault() { 
     return new CustomSSLSocketFactory(); 
    } 

    public Socket createSocket(Socket socket, String s, int i, boolean flag) throws IOException { 
     return factory.createSocket(socket, s, i, flag); 
    } 

    public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1, int j) throws IOException { 
     return factory.createSocket(inaddr, i, inaddr1, j); 
    } 

    public Socket createSocket(InetAddress inaddr, int i) throws IOException { 
     return factory.createSocket(inaddr, i); 
    } 

    public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException { 
     return factory.createSocket(s, i, inaddr, j); 
    } 

    public Socket createSocket(String s, int i) throws IOException { 
     return factory.createSocket(s, i); 
    } 

    public String[] getDefaultCipherSuites() { 
     return factory.getSupportedCipherSuites(); 
    } 

    public String[] getSupportedCipherSuites() { 
     return factory.getSupportedCipherSuites(); 
    } 

protected KeyManager[] getKeyManagers() 
     throws IOException, GeneralSecurityException 
     { 
     // First, get the default KeyManagerFactory. 
     String alg=KeyManagerFactory.getDefaultAlgorithm(); 
     KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg); 

     // Next, set up the KeyStore to use. We need to load the file into 
     // a KeyStore instance. 

     ClassLoader cl = CustomSSLSocketFactory.class.getClassLoader(); 
     // read the file someTrustStore from the jar file from a classpath 
     InputStream in = cl.getResourceAsStream("ssl/someTruststore.jks"); 
     //FileInputStream fis=new FileInputStream(adentTruststore.jks); 
     KeyStore ks=KeyStore.getInstance("jks"); 
     ks.load(in, null); 
     in.close(); 

     // Now we initialise the KeyManagerFactory with this KeyStore 
     kmFact.init(ks, null); 

     // And now get the KeyManagers 
     KeyManager[] kms=kmFact.getKeyManagers(); 
     return kms; 
     } 
} 

package util; 
import java.security.cert.X509Certificate; 

import javax.net.ssl.X509TrustManager; 

public class CustomTrustManager implements X509TrustManager { 

    public void checkClientTrusted(X509Certificate[] cert, String authType) { 
     return; 
    } 

    public void checkServerTrusted(X509Certificate[] cert, String authType) { 
     return; 
    } 

    public X509Certificate[] getAcceptedIssuers() { 
     return new X509Certificate[0]; 
    } 
} 

拉兹感谢您的耐心,努力学习,当我得到一些时间。 我开始写我自己的CustomSSLSocketFactory ..现在我正在绕过安全......基于白金解决方案的例子。如果我这样做......将信息作为网络上的明文传递?

现在我想知道我应该如何处理信任库文件“sometruststore.jks”文件。我应该怎么做..我有我自己的定制信任管理软件吗? 请指导我正确的方向。

-padur

+0

该信息不会是明文。它将被加密,但未经过验证,因为此代码认为所有证书都是可信的。 您不必编写自己的信任管理器来处理.jks文件。看看下面的答案,看看你可以传递一个KeyStore实例到SSLSocketFactory子类。您可以通过加载(如果不在类路径中),以与原始代码中相同的方式获取该实例。 – laz 2010-06-08 18:49:57

回答

3

你可以做到这一点,而不必依赖于系统属性和文件系统。像你正在做的流一样读密钥库并创建你自己的SSLSocketFactory将会更清晰。

import java.net.URL; 
import java.security.KeyStore; 
import java.security.SecureRandom; 

import javax.net.ssl.HttpsURLConnection; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.TrustManagerFactory; 

... 

    // assume keyStore is the KeyStore you read via getResourceAsStream 
    final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); 
    trustManagerFactory.init(keyStore); 

    final SSLContext context = SSLContext.getInstance("SSL"); 
    context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); 

    final URL url = new URL("https://whatever"); 
    final HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); 
    urlConnection.setSSLSocketFactory(context.getSocketFactory()); 

... 

我还没有验证,但我没有看到为什么这不应该通过Webstart工作。

更新时间:

你提到你正在寻找连接到Active Directory,所以我猜你要使用LDAPS作为协议?如果是这样,也许在this URL的代码可以作为灵感?您必须创建一个javax.net.ssl.SSLSocketFactory(参见BlindSSLSocketFactoryTest at the platinumsolutions链接)的子类,该子类包含创建SSLContext的上述逻辑并委托context.getSocketFactory()创建的SSLSocketFactory的调用。

public class TrustedSSLSocketFactory extends SSLSocketFactory { 
    private static SSLContext context; 
    public static void initTrustedSSLSocketFactory(final KeyStore keyStore) throws Exception { 
     final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); 
     trustManagerFactory.init(keyStore); 

     final SSLContext context = SSLContext.getInstance("SSL"); 
     context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); 
    } 

    public static SocketFactory getDefault() { 
     return context.getSocketFactory(); 
    } 

    public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException { 
     return trustedFactory.createSocket(arg0, arg1); 
    } 

    public Socket createSocket(InetAddress arg0, int arg1) throws IOException { 
     return trustedFactory.createSocket(arg0, arg1); 
    } 

    public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException { 
     return trustedFactory.createSocket(arg0, arg1, arg2, arg3); 
    } 

    public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException { 
     return trustedFactory.createSocket(arg0, arg1, arg2, arg3); 
    } 
} 

希望编译,我目前无法测试它!还请注意initTrustedSSLSocketFactory上的throws子句的懒惰。

然后,当你设置的LDAP环境中,使用

TrustedSSLSocketFactory.initTrustedSSLSocketFactory(keyStore); 
env.put("java.naming.ldap.factory.socket", TrustedSSLSocketFactory.class.getName()) 

以类似的方式来示例代码在platinumsolutions。希望这是更多你正在寻找什么?

+0

谢谢拉斯的解决方案。 上次我没有正确地提出问题。我应该连接到活动目录而不是HTTPS服务器,我需要验证用户信息。在这种情况下,他们没有提供任何URL,他们给了我一个.jks文件的证书。所以我认为HTTPURLConnection不是一个好主意。 我想在得到SSLContext后,我需要调用不同的API来验证它。如果您有任何其他想法,请告诉我。 -Padur – SPD 2010-05-10 19:10:55

+0

你好Laz..sorry回应迟了。 我明白你在说什么。我无法得到什么程序(铂金解决方案示例代码)在做什么。这是通过安全吗? – SPD 2010-05-18 23:55:27

+0

是的,铂解决方案代码绕过了证书验证(请参阅http://blog.platinumsolutions.com/node/79)。把它作为一个概念的例子,而不仅仅是你应该做的事情。 – laz 2010-05-19 02:03:50