2010-05-10 14 views
7

Besoin de conseils.Java Webstart Truststore SSL

J'ai java webstart app et je veux qu'il se connecte à un serveur via SSL.juste en ajoutant une propriété comme: System.setProperty ("javax.net.ssl.trustStore", "my.keystore"); Mais depuis un programme JAWS téléchargé à partir du serveur n'a pas fonctionné et n'a pas de my.keystore sur le système de fichiers local. Alors décidé de distribuer le certificat à tous les clients.J'ai fait ce qui suit et cela a fonctionné.

  1. Lisez ce fichier de clés en tant que flux (utilisez la méthode getResourceAsStream).
  2. Enregistrez-le dans n'importe quel fichier sur l'ordinateur client (sometemp)
  3. Appelez System.setProperty ("javax.net.ssl.trustStore", trustStorePath);

Mais je suis sûr qu'il doit y avoir de meilleures solutions que cela .. Des idées pour le rendre meilleur?

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

Laz remercie de votre patience, en essayant d'apprendre quand je avoir du temps. J'ai commencé à écrire mon propre CustomSSLSocketFactory..right maintenant je contourne la sécurité ... basé sur l'exemple par des solutions de platine.Si je fais cela ... l'information passera-t-elle comme un texte clair sur le réseau?

Maintenant, je me demande ce que je devrais faire avec le fichier truststore J'ai un fichier "sometruststore.jks". Que dois-je faire avec ça? Est-ce que j'ai écrit mon propre logiciel de confiance personnalisé? S'il vous plaît me guider dans la bonne direction.

-padur

+0

L'information ne sera pas en texte clair. Il sera crypté, mais pas authentifié puisque ce code considère tous les certificats à approuver. Vous n'avez pas besoin d'écrire votre propre gestionnaire de confiance pour gérer le fichier .jks. Jetez un oeil à ma réponse ci-dessous et voyez que vous pouvez passer une instance de KeyStore à la sous-classe SSLSocketFactory. Vous pouvez obtenir cette instance de la même manière que vous êtes dans votre code d'origine en chargeant si vous n'êtes pas dans le classpath. – laz

Répondre

3

Vous pouvez le faire sans avoir à compter sur les propriétés du système et le système de fichiers. Lire le keystore comme un flux comme vous le faites et créer votre propre SSLSocketFactory serait beaucoup plus propre.

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

... 

Je n'ai pas vérifié mais je ne vois pas pourquoi cela ne devrait pas fonctionner via Webstart.

Mise à jour:

Vous mentionnez que vous cherchez à vous connecter à Active Directory, donc je devine que vous allez utiliser LDAPS comme protocole? Si oui, peut-être que le code this URL peut servir d'inspiration? Vous devrez créer une sous-classe de javax.net.ssl.SSLSocketFactory (voir BlindSSLSocketFactoryTest à ce lien platinesolutions) qui enveloppe la logique ci-dessus de créer le SSLContext et délègue des appels au SSLSocketFactory que context.getSocketFactory() crée.

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

J'espère que cela compile, je suis incapable de le tester pour le moment! Notez également la paresse avec la clause throws sur initTrustedSSLSocketFactory.

Ensuite, lorsque vous configurez l'environnement LDAP, utilisez

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

de manière similaire à l'exemple de code à platinumsolutions. J'espère que c'est plus de ce que vous cherchez?

+0

Merci laz pour la solution. La dernière fois que je n'ai pas posé la question correctement. Je suis supposé me connecter au répertoire actif non serveur HTTPS et j'ai besoin de valider les informations utilisateur. Dans ce cas, ils n'ont fourni aucune URL, ils m'ont donné un certificat un fichier .jks. Donc HTTPURLConnection ne sera pas une bonne idée je pense. Je suppose qu'après avoir obtenu le SSLContext, j'ai besoin d'appeler une API différente pour le vérifier. S'il vous plaît laissez-moi savoir si vous avez d'autres idées. -Padur – SPD

+0

Bonjour Laz..désolé répondant tard. Je comprends ce que vous essayez de dire. Je n'ai pas pu obtenir ce que fait le programme (exemple de code sur platinumsolutions). Est-ce en passant la sécurité? – SPD

+0

Oui, le code platinumsolutions contourne la validation du certificat (voir http://blog.platinumsolutions.com/node/79). Prenez-le comme un exemple du concept plus que exactement ce que vous devriez faire. – laz