0

The meaning of following example code is not important, what I want to ask is how to send the "certFileName" in to socketFactory as a params, for I need to use different certFile to different endPoint, thanks

public class LdapConnection
{

    private String host = "1.2.3.4"; //the correct ip...
    private String baseDn = "dc=x,dc=y,dc=com"; //the correct base DN

    private String username = "myUsername";
    private String password = "myPassword";

    private String connectionUrl = null;

    public void connectLdaps() throws Exception
    {
        connectionUrl = "ldaps://" + host + "/" + baseDn;

        System.out.println("Trying to connect to " + connectionUrl + " using LDAPS protocol");

        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put("java.naming.ldap.derefAliases", "finding");
        env.put(Context.PROVIDER_URL, connectionUrl);
        env.put(Context.SECURITY_AUTHENTICATION, "Simple");
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);
        env.put("java.naming.ldap.factory.socket", MySocketFactory.class.getName());

        new InitialLdapContext(env, null);

        System.out.println("Connected successfully!");
    }

    public static void main(String[] args) throws Exception
    {
        LdapConnection ldapConnection = new LdapConnection();
        ldapConnection.connectLdaps();
    }

}

public class MySocketFactory extends SocketFactory
{
    private static MySocketFactory instance = null;
    private SSLContext sslContext = null;

    //I want to send this var from outside
    **private static String certFileName = "C:\\certs\\cert_by_hostname.cer";**

    public static SocketFactory getDefault()
    {
        if (instance == null)
        {
            try
            {
                instance = new MySocketFactory();
                instance.initFactory();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                System.out.println("Returning null socket factory");
            }
        }

        return instance;
    }
}

may be like this way: what should I do in the "outside" code

public class MySocketFactory extends SocketFactory
{
    private MySocketFactory instance = null;
    private SSLContext sslContext = null;

    //I want to send this var from outside
    private String certFileName = null

    public MySocketFactory(String varCert)
    {
       certFileName = varCert;
    }
}

thanks!

Bruno
  • 119,590
  • 31
  • 270
  • 376
SoYoung
  • 315
  • 1
  • 3
  • 10
  • @TerryGardner, why do you keep removing `ldap` tags (see [this question on meta](http://meta.stackexchange.com/q/118827/148833))? – Bruno Mar 26 '12 at 09:21
  • @Bruno Some of those removals make sense, e.g. when the question is really about how to configure a specific server like OpenLDAP and has no relevance to LDAP per se. This one is another reasonable case: it is really about the interaction between JSSE and JNDI, nothing really to do with LDAP *per se* at all. I think I edited the tags on this question myself too. – user207421 Mar 26 '12 at 09:42
  • @downvoter please explain. Otherwise nobody learns anything. – user207421 Mar 26 '12 at 09:46
  • @EJP, OK, fair enough, but I think leaving the tag makes it easier to search for questions about [LDAP and Java together](http://stackoverflow.com/questions/tagged/java+ldap). It's not about LDAP per se, but about `com.sun.jndi.ldap.LdapCtxFactory` and `java.naming.ldap.factory.socket`, which fits well within Java+LDAP (I think). I think broader tagging can be useful here, but I'm not sure... – Bruno Mar 26 '12 at 09:52
  • @Bruno Look at it from what I assume is probably Terry's perspective. He is clearly an LDAP expert, but perhaps not too interested in JNDI, which he recommends against, and maybe not JSSE or OpenLDAP either. I, on the other hand, am not so much an LDAP expert to Terry's level but I know OpenLDAP and JNDI and JSSE very well indeed. We have quite different needs. In this case I am competent to answer the question and maybe he is not, or at least not interested. OTOH maybe neither Terry nor I is adequately considering users trying to find existing answers to this question. – user207421 Mar 26 '12 at 09:57

2 Answers2

1

I don’t believe there is a way to pass a variable from outside the code. Well, not in the usual way at least. You could use a work around though.

Instead of passing a variable directly, hard code the certFileName variable to read from a user-defined System property. Then set that user-defined system property outside the code.

For example:

You have:
private String certFileName = "C:\\certs\\cert_by_hostname.cer";

Instead do something like:
private String certFileName = System.getProperty("custom.ldap.cert.file.loc");

Now, you can set the custom.ldap.cert.file.loc property outside your code.

So, putting it all together you'll have something similar to this. I've placed calls to System.setProperty() and System.getProperty() at suitable places in your code:

public class LdapConnection
{

    private String host = "1.2.3.4"; //the correct ip...
    private String baseDn = "dc=x,dc=y,dc=com"; //the correct base DN

    private String username = "myUsername";
    private String password = "myPassword";

    private String certFileLocation = "C:\\certs\\cert_by_hostname.cer";

    private String connectionUrl = null;

    public void connectLdaps() throws Exception
    {
        connectionUrl = "ldaps://" + host + "/" + baseDn;

        System.out.println("Trying to connect to " + connectionUrl + " using LDAPS protocol");

        System.setProperty("custom.ldap.cert.file.loc", certFileLocation);

        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put("java.naming.ldap.derefAliases", "finding");
        env.put(Context.PROVIDER_URL, connectionUrl);
        env.put(Context.SECURITY_AUTHENTICATION, "Simple");
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);
        env.put("java.naming.ldap.factory.socket", MySocketFactory.class.getName());

        new InitialLdapContext(env, null);

        System.out.println("Connected successfully!");
    }

    public static void main(String[] args) throws Exception
    {
        LdapConnection ldapConnection = new LdapConnection();
        ldapConnection.connectLdaps();
    }

}


public class MySocketFactory extends SocketFactory
{
    private static MySocketFactory instance = null;
    private SSLContext sslContext = null;

    //Now reference the system property here. This system property is set outside.
    private String certFileName = System.getProperty("custom.ldap.cert.file.loc");

    public static SocketFactory getDefault()
    {
        if (instance == null)
        {
            try
            {
                instance = new MySocketFactory();
                instance.initFactory();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                System.out.println("Returning null socket factory");
            }
        }

        return instance;
    }

    private void someMethodThatMakesUseOfTheCertFile()
    {
          //do something with the variable: certFileName
    }
}

A word of caution. You must set the System property to the cert file prior to calling:
new InitialLdapContext(env, null); This is very important.

Please note that if you need to keep changing the cert file name or location, you may do so, by first updating the System property and then calling: new InitialLdapContext(env, null);. However, if you are making connections to different LDAP directories in different threads, then you may be better of using ThreadLocal variables rather than System properties. The concept should be the same.

Finally, if the LDAP directories that you'll be connecting to are always known, then you could pre-download each of their public certificates, and put all of them in a single truststore. That way, your LDAP connection need only read a single truststore rather than multiple individual certificate files.

Using this approach, you could simply set the appropriate built-in system properties as others have suggested. For example:

System.setProperty("javax.net.ssl.trustStore", "/path/to/truststore");
System.setProperty("javax.net.ssl.trustStorePassword", "the truststore password");

If setting the appropriate built-in system properties is not an option for your particular situation, then the above-mentioned method of using custom System properties or ThreadLocals can be used to read from truststores too.

Mody
  • 86
  • 3
1

You don't need to write a socket factory at all. See the JSSE Reference Guide. Just set the appropriate system properties.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • but I need to use different cert to different endPoint. using the system properties only solve the problem that has one endPoint – SoYoung Mar 26 '12 at 02:02
  • @SoYoung so put that constraint into your question. – user207421 Mar 26 '12 at 02:04
  • So do you have any solution? I had look through all the search result – SoYoung Mar 26 '12 at 02:14
  • @SoYoung the solution is to see the JSSE Reference Guide. It tells you how to construct a KeyManager, that loads your keystore; then you make an SSLContext, then you get the SSLSocketFactory from that, then you use theput to construct your Sockets. – user207421 Mar 26 '12 at 02:45
  • but when you using the ldapcontext, just like : env.put("java.naming.ldap.factory.socket", MySocketFactory.class.getName()); this part just allow you input the name of socketFactory class – SoYoung Mar 26 '12 at 02:51
  • @SoYoung all that stuff goes into your socket factory. – user207421 Mar 26 '12 at 02:53
  • i still don't understand, there is not place to put the certFile, could you explan more details? thanks – SoYoung Mar 26 '12 at 02:59
  • @SoYoung I've answered that. You load it into the KeyManager. I suspect you haven't even looked at the JSSE document yet. It won't make much sense until you do. – user207421 Mar 26 '12 at 03:01
  • @SoYoung, you may also be interested in [this question](http://stackoverflow.com/q/9865666/372643). – Bruno Mar 26 '12 at 09:23
  • @SoYoung, hello I know this post were exchanged a long time ago, but did you finally found an answer/solution to your question as I've got exactly the same situation ? Thx – fckbo Apr 04 '20 at 06:38