2011-01-06 13 views
10

Potrzebuję połączyć się z katalogiem LDAP przez SSL.jak akceptować certyfikaty z podpisem własnym dla połączeń JNDI/LDAP?

W środowiskach nieprodukcyjnych, używamy certyfikatów z podpisem własnym, które, oczywiście, nie zgłosił zatwierdź:

javax.naming.CommunicationException: simple bind failed: ldapserver:636 [Root exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target] 
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:197) 
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2694) 
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293) 
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175) 
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193) 
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136) 
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66) 
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667) 
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) 
at javax.naming.InitialContext.init(InitialContext.java:223) 
at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134) 

Jestem świadomy tego, jak używać custom trust manager for SSL-enabled connections, ale nie wiem jak użyj jednego w połączeniu z interfejsem API JNDI, w którym nie zarządzam rzeczywistym połączeniem. To znaczy, gdzie jest następująca standardowa konfiguracja, czy będę mógł podłączyć menedżera zaufania?

Z góry dziękuję.

Hashtable env = new Hashtable(); 
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
env.put(Context.PROVIDER_URL, "ldaps://ldapserver:636"); 
env.put(Context.SECURITY_PROTOCOL, "ssl"); 
env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
env.put(Context.SECURITY_PRINCIPAL, "myUser"); 
env.put(Context.SECURITY_CREDENTIALS, "myPassword"); 
LdapContext ctx = new InitialLdapContext(env, null); 
ctx.search (...) 

Odpowiedz

18

Zgodnie z dokumentacją JNDI wydaje się możliwe, aby ustawić niestandardową SSLSocketFactory

http://download.oracle.com/javase/1.5.0/docs/guide/jndi/jndi-ldap-gl.html#socket

public class MySSLSocketFactory extends SocketFactory { 
    private SSLSocketFactory sf; 

    public MySSLSocketFactory() { 
     KeyStore keyStore = ... /* Get a keystore containing the self-signed certificate) */ 
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(); 
     tmf.init(keyStore); 
     SSLContext ctx = SSLContext.getInstance("TLS"); 
     ctx.init(null, tmf.getTrustManagers(), null); 
     sf = ctx.getSocketFactory(); 
    } 

    /* delegate SSLSocketFactory public methods to sf */ 
    ... 
} 

skonfigurować środowisko aby skorzystać z tej fabryki gniazda

env.put("java.naming.ldap.factory.socket", "com.example.MySSLSocketFactory"); 
+0

Dzięki. Myślę, że to słuszne; Mam pewne problemy z systemem go wewnątrz JBoss, podejrzewam różne classloaders spowodować „java.lang.IllegalArgumentException: obiekt nie jest instancją deklarując klasę”, gdy gniazdo jest tworzony poprzez odbicie w com.sun.jndi.ldap.Connection.createSocket (Connection.java:317) ale to inny problem. – wishihadabettername

+9

Po prostu, aby pomóc komuś, kto wpadł na Nielegalny Wyjątek Dokumentów; musisz zaimplementować statyczną metodę getDefault() w swoim niestandardowym (SSL) SocketFactory. –

1

Minęło około 5 lat, od kiedy to zrobiłem, więc moja odpowiedź będzie nieco mglista, obawiam się; ale myślę, że jeśli zastosujesz zaufanego dostawcę w java.security, który powinieneś znaleźć w/usr/java/jre/lib/security /; następnie zaakceptuje certyfikat jako zaufany.

nie mam dostępu do moich notatek w tej chwili, ale będę musiał przekopywać się przez nich później

6

Można przyjąć żadnego certyfikatu, jeśli przesłonić Trustmanager:

DummyTrustmanager.java

public class DummyTrustmanager implements X509TrustManager { 
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { 
     // do nothing 
    } 

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { 
     // do nothing 
    } 

    public X509Certificate[] getAcceptedIssuers() { 
     return new java.security.cert.X509Certificate[0]; 
    } 
} 

MySSLSocketFactory.java

public class MySSLSocketFactory extends SSLSocketFactory { 
    private SSLSocketFactory socketFactory; 

    public MySSLSocketFactory() { 
     try { 
      SSLContext ctx = SSLContext.getInstance("TLS"); 
      ctx.init(null, new TrustManager[] { new DummyTrustmanager() }, new SecureRandom()); 
      socketFactory = ctx.getSocketFactory(); 
     } catch (Exception ex) { 
      ex.printStackTrace(System.err); 
      /* handle exception */ 
     } 
    } 

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

    @Override 
    public String[] getDefaultCipherSuites() { 
     return socketFactory.getDefaultCipherSuites(); 
    } 

    @Override 
    public String[] getSupportedCipherSuites() { 
     return socketFactory.getSupportedCipherSuites(); 
    } 

    @Override 
    public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException { 
     return socketFactory.createSocket(socket, string, i, bln); 
    } 

    @Override 
    public Socket createSocket(String string, int i) throws IOException, UnknownHostException { 
     return socketFactory.createSocket(string, i); 
    } 

    @Override 
    public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException { 
     return socketFactory.createSocket(string, i, ia, i1); 
    } 

    @Override 
    public Socket createSocket(InetAddress ia, int i) throws IOException { 
     return socketFactory.createSocket(ia, i); 
    } 

    @Override 
    public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException { 
     return socketFactory.createSocket(ia, i, ia1, i1); 
    } 
} 

Main.java

public class Main { 
    public static void main(String[] args) throws NamingException { 
     Hashtable env = new Hashtable(11); 
     env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
     env.put(Context.PROVIDER_URL, "ldaps://ldapserver:636/"); 
     env.put(Context.SECURITY_PROTOCOL, "ssl"); 
     env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
     env.put(Context.SECURITY_PRINCIPAL, "myUser"); 
     env.put(Context.SECURITY_CREDENTIALS, "myPassword"); 
     env.put("java.naming.ldap.factory.socket", "ldapsecure.MySSLSocketFactory"); 
     LdapContext ctx = new InitialLdapContext(env, null); 
    } 
} 
+6

W ten sposób nie akceptujesz samopodpisanego certyfikatu, całkowicie uniemożliwiając weryfikację zaufania. W związku z tym akceptujesz także każdy certyfikat, w tym potencjalnie MITM atakujący twoje połączenie. – Bruno

+0

Przetworzone lubiane masło, dzięki! – Sohan

2

@Jcs odpowiedź jest poprawna, ale jeśli nie chcesz używać niestandardowego TrustManagera i jeśli chcesz, aby ten samopodpisany certyfikat był zaufanym ośrodkiem dla innych zastosowań w VM, musisz może albo:

  • dodać ten certyfikat do domyślnej truststore (zwykle cacerts w katalogu zabezpieczeń JRE) lub
  • utworzenia nowego magazynu zaufanych certyfikatów w innym miejscu (prawdopodobnie w oparciu o kopię domyślnie cacerts), które zawierać ten konkretny certyfikat i używać go jako domyślnego magazynu zaufanych certyfikatów, ale ustawiając właściwości systemowe javax.net.ssl.trustStore* .
1

Pomijając JNDI całkowicie niektóre ramy będą odnosić się do lokalnej konfiguracji LDAP SYSTEM (jest to zazwyczaj /etc/ldap.conf czy coś takiego). Kiedy mówię LOCAL, mam na myśli system (y), na którym działa twoja operacja JNDI.

Przynajmniej w przypadku najbardziej LDAP Linux Oss, wewnątrz takiego pliku konfiguracyjnego LDAP jest (zazwyczaj) linia, która brzmi:

TLS_REQCERT demand 

Jest to ustawienie domyślne TLS/krytyczności SSL (i najbardziej rygorystyczna), ponieważ nie powiedzie się połączenie, jeśli WSZYSTKIE WHATSOEVER jest nie tak z certyfikatem (obejmuje to również samopodpisanie).

Można eksperymentować z różnymi ustawieniami zamiast „żądanie” (odtwarzanie z „pozwolić” lub „nie”). Gdy to zrobisz, spróbuj ponownie wykonać operację i sprawdź, czy Twój problem się zmniejszył. Ponownie, nie wszystkie takie rzeczy będą odczytywać, a nawet wykrywać lokalne ustawienia systemu. Niektórzy tak, niektórzy nie. Warte zobaczenia.

Mam nadzieję, że to pomaga ...

Max

4

Nie wymaga kodu. Po prostu dodaj certyfikat do zaufanych klientów testowych.

Nie napisać dodatkowy kod dla tego produktu. Jest niezabezpieczony i istnieje duże ryzyko, że kod zostanie wprowadzony do produkcji. Naprawdę tego nie chcesz.

Powiązane problemy