2010-05-10 4 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. Call System.setProperty ("javax.net.ssl.trustStore", trustStorePath);

Но я уверен, что должно быть лучшее решение, чем это. Любые идеи, чтобы сделать его лучше?

public boolean validateUserFromActiveDirectory(String userId) { 
        final String MEMBER_GROUP = "CN=asdadasd,OU=asdasdasd Accounts,OU=adasdas,OU=asdasdas,DC=asdasdas,DC=asdasdas,DC=adasdasd,DC=asdasdasd"; 
      String employeeNumber = ""; 
      final String LDAP_INIT_CTX = "com.sun.jndi.ldap.LdapCtxFactory"; 
      final String LDAP_URL = "ldap://xx-ssssssss.eee.eee.eeeee.eeeee:636"; 
      final String MY_ATTRS[] = { "employeeNumber" }; 
      String adminPassword = "somepassword"; 
      String securityProtocol = "ssl"; 
      boolean isValidUser = false; 
      try { 

        Hashtable env = new Hashtable(); 
        env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_INIT_CTX); 
        env.put(Context.PROVIDER_URL, LDAP_URL); 
        env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
        env.put(Context.REFERRAL, "follow"); 
        env.put(Context.SECURITY_PRINCIPAL, MEMBER_GROUP); 
        env.put(Context.SECURITY_CREDENTIALS, adminPassword); 
        env.put(Context.SECURITY_PROTOCOL, securityProtocol); 

      //C:\Documents and Settings\yourusername\Local Settings\Temp 
      File tf = File.createTempFile("someTruststore", ".jks"); 
      tf.deleteOnExit(); 
      byte buffer[] = new byte[0x1000]; 
       ClassLoader cl = JNDI.class.getClassLoader(); 
      InputStream in = cl.getResourceAsStream(
        "someTruststore.jks"); 
      FileOutputStream out = new FileOutputStream(tf); 
      int cnt; 
      while ((cnt = in.read(buffer)) != -1) 
       out.write(buffer, 0, cnt); 
      in.close(); 
      out.close(); 
      System.setProperty("javax.net.ssl.trustStore", tf 
          .getAbsolutePath()); 

        DirContext context = new InitialLdapContext(env, null); 
        SearchControls searchControls = new SearchControls(); 
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); 
        NamingEnumeration results = context.search(
           "XX=ent,XX=abc,XX=aaaaa,XX=aaaa", "(sAMAccountName=" 
              + userId + ")", searchControls); 

        if (results != null && results.hasMore()) { 
         //some logic 

         } 
        } 
      } catch (Exception e) { 
        e.printStackTrace(); 
      } 
      return isValidUser; 
     } 

-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. Теперь я обойду безопасность ... на основе примера платиновыми решениями. Если я это сделаю ... информация будет передаваться как чистый текст в сети?

Теперь интересно, что мне делать с файлом truststore, у меня есть файл «sometruststore.jks». Что я должен делать с этим. .. У меня есть собственное собственное программное обеспечение trustmanager? Пожалуйста, направляйте меня в правильном направлении.

-padur

+0

Информация не будет четким текстом. Он будет зашифрован, но не аутентифицирован, так как этот код рассматривает все сертификаты, которым нужно доверять. Вам не нужно писать собственный менеджер доверия для обработки файла .jks. Взгляните на мой ответ ниже и убедитесь, что вы можете передать экземпляр KeyStore в подкласс SSLSocketFactory. Вы можете получить этот экземпляр так же, как и в исходном коде, загрузив его из класса. – laz

ответ

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.

Обновлено:

Вы сказали, что вы хотите подключиться к активной директории, так что я предполагаю, что Вы собираетесь использовать LDAPS в качестве протокола? Если да, может быть, код в this URL может послужить вдохновением? Вам нужно будет создать подкласс javax.net.ssl.SSLSocketFactory (см. BlindSSLSocketFactoryTest на этой ссылке platinumsolutions), которая обертывает логику выше создания SSLContext и делегирует вызовы SSLSocketFactory, которые создает context.getSocketFactory().

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

Надеюсь, что это компиляция, я не могу проверить это на данный момент! Также обратите внимание на лень с предложением throws на initTrustedSSLSocketFactory.

Затем при настройке среды LDAP, используйте

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

аналогичным образом на примере кода в platinumsolutions. Надеюсь, это больше того, что вы ищете?

+0

Благодарим вас за решение. В прошлый раз я не задал вопрос правильно. Я должен подключиться к активному каталогу, а не к HTTPS-серверу, и мне нужно проверить данные пользователя. В этом случае они не предоставили никакого URL-адреса, они дали мне сертификат .jks-файла. Так что HTTPURLConnection не будет хорошей идеей, я думаю. Я думаю, что после получения SSLContext мне нужно вызвать другой API для его проверки. Пожалуйста, дайте мне знать, если у вас есть другие идеи. -Padur – SPD

+0

Hello Laz..извинитесь ответ поздно. Я понимаю, что вы пытаетесь сказать. Я не мог получить то, что делает программа (пример кода в platinumsolutions). Это путем обеспечения безопасности? – SPD

+0

Да, этот код platinumsolutions обходит проверку сертификата (см. Http://blog.platinumsolutions.com/node/79). Возьмите его как пример концепции больше, чем то, что вы должны делать. – laz

Смежные вопросы