A DESCRIPTION OF THE PROBLEM :
When being connected to a domain controller using LDAP the javax.naming library creates a reader thread in order to receive the response from the server.
Calling the reconnect method on the LdapContext instance performs a reconnect and creates a new reader thread. However, it does not stop the old reader thread from the previous connection. That leads to a resource leak, because with every reconnect call, a new thread gets created and the old threads are not being stopped.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Open a LDAP connection:
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put (Context.SECURITY_PRINCIPAL, username);
env.put (Context.SECURITY_CREDENTIALS, password);
if((this.security == SecurityProtocol.NONE) || (this.security == SecurityProtocol.TLS)) {
env.put(Context.PROVIDER_URL, String.format ("ldap://%s:%d", this.hostname, this.port));
}
else if(this.security == SecurityProtocol.LDAPS) {
env.put(Context.PROVIDER_URL, String.format ("ldaps://%s:%d", this.hostname, this.port));
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put("java.naming.ldap.factory.socket", "com.jdisc.inventory.protocols.ldap.LdapSslSocketFactory");
}
else {
throw new IllegalArgumentException("Illegal security setting");
}
env.put("java.naming.ldap.attributes.binary", "objectGUID objectSID");
env.put(CONNECT_TIMEOUT_KEY, Integer.toString (connectTimeout));
env.put(READ_TIMEOUT_KEY, Integer.toString (readTimeout));
connCtls = new Control[] {new FastBindConnectionControl()};
ctx = new InitialLdapContext(env, connCtls);
if(this.security == SecurityProtocol.TLS) {
StartTlsResponse tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
tls.setHostnameVerifier (new LdapHostnameVerifier());
tls.negotiate(new LdapSslSocketFactory());
}
// This creates the additional thread and the original reader thread never stops.
ctx.reconnect();
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The reconnect method should either reuse the existing thread or first stop the existing thread and then create the new reader-thread.
ACTUAL -
After the reconnect method, we have two reader threads for the same connection. One of them will never disappear. Even when you disconnect the LDAP context.
---------- BEGIN SOURCE ----------
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put (Context.SECURITY_PRINCIPAL, username);
env.put (Context.SECURITY_CREDENTIALS, password);
if((this.security == SecurityProtocol.NONE) || (this.security == SecurityProtocol.TLS)) {
env.put(Context.PROVIDER_URL, String.format ("ldap://%s:%d", this.hostname, this.port));
}
else if(this.security == SecurityProtocol.LDAPS) {
env.put(Context.PROVIDER_URL, String.format ("ldaps://%s:%d", this.hostname, this.port));
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put("java.naming.ldap.factory.socket", "com.jdisc.inventory.protocols.ldap.LdapSslSocketFactory");
}
else {
throw new IllegalArgumentException("Illegal security setting");
}
env.put("java.naming.ldap.attributes.binary", "objectGUID objectSID");
env.put(CONNECT_TIMEOUT_KEY, Integer.toString (connectTimeout));
env.put(READ_TIMEOUT_KEY, Integer.toString (readTimeout));
connCtls = new Control[] {new FastBindConnectionControl()};
ctx = new InitialLdapContext(env, connCtls);
if(this.security == SecurityProtocol.TLS) {
StartTlsResponse tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
tls.setHostnameVerifier (new LdapHostnameVerifier());
tls.negotiate(new LdapSslSocketFactory());
}
// The reconnect causes the issue.
ctx.reconnect();
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No workaround known when reconnect required.
FREQUENCY : always