JDK-4779765 : LDAP provider hangs when doing DIGEST-MD5 authentication
  • Type: Bug
  • Component: core-libs
  • Sub-Component: javax.naming
  • Affected Version: 1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux,solaris_8
  • CPU: x86,sparc
  • Submitted: 2002-11-15
  • Updated: 2003-01-14
  • Resolved: 2003-01-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 b13Fixed
Related Reports
Relates :  
Relates :  
Description
From: "Michael Maier" <###@###.###>
Date: Fri, 15 Nov 2002 15:48:26 +0100

I think I found a bug concerning DirContext.
I use JNDI to connect to a Sun ONE Directory Server 5.1. My Java Version is
1.4.1 but I also tried it with 1.4.0 and 1.3.2. When I create lots of
DirContexts, sometimes Java just hangs after delivering some results. The
problem occurs only, when using DIGEST-MD5 as authentication type. When I
use simple authentication everything goes well.
I first thought it's a Problem with the server but when I looked at the
packages sent, I realized that the last package always is a result from the
server. I also tried if it becomes better when I close the connection using
ctx.close() but that does not help at all.

Florian


Here is the code I used for testing:
for (int i; i<20; i++)
{
Hashtable env = new Hashtable ();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL,ldapPath);
env.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5");
env.put(Context.SECURITY_PRINCIPAL,"dn:uid=aUser,ou=People,o=anOrganization"
);
env.put(Context.SECURITY_PROTOCOL, "ssl");
System.setProperty("javax.net.ssl.trustStore", "config/trustedCAs");
env.put(Context.SECURITY_CREDENTIALS,password);
try {
DirContext ctx = new InitialDirContext(env);   // <---HANGS HERE
Attributes attrs =
ctx.getAttributes("uid=someUser,ou=People,o=anOrganization", attrIDs);
String entryid = (String) attrs.get("entryid").get();
}catch (NamingException e) {
System.err.println("Problem getting attribute:" +e);
}
}

-------------------------------
From: "Michael Maier" <###@###.###>
Date: Fri, 15 Nov 2002 17:22:41 +0100
SSL does not cause the problem, I can even use a not encrypted connection.
The problem is still the same. I also encountered that the problem is not
occuring always. I just tried it once again on two different computers. The
first is a Win2000 machine with about 1600MHz, on which the Directory server
itself runs. The second machine is a Win98 650MHz machine. On the first
machine I got between 1 and 4 result, then it hanged. On the second I also
had to increase the value to 20000 (!), after the 5194 successful responses
it hanged, too. Perhaps it is a speed problem?



-----Ursprungliche Nachricht-----
Von: Rosanna Lee [mailto:###@###.###
Gesendet: Freitag, 15. November 2002 16:35
An: ###@###.###
Cc: ###@###.###
Betreff: Re: Your Message Sent on Fri, 15 Nov 2002 15:48:26 +0100


I tried to reproduce the problem by using your test program but could not.
After increasing 20 to 200, the program still did not hang.
I noticed that you are using SSL, perhaps it is a problem related to that.
You can enable SSL tracing by setting the javax.net.debug system property
to 'all'.



Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis-beta FIXED IN: mantis-beta INTEGRATED IN: mantis-b13 mantis-beta
02-09-2004

EVALUATION Date: Fri, 29 Nov 2002 21:16:54 +0530 (IST) From: Jayalaxmi Hangal <###@###.###> Subject: The cause of hang Rosanna, I just wanted to update you on where I am at working on the bug that is causing a hang. I don't expect you to see this message till you get back from vacation. I recompiled LDAP classes with debug enabled and was able to make out the code responsible for the hang (after adding some more debug messages) As you had guessed, there is a race condition that occurs when reading with SASL authentication or start TLS. Here is one of the scenarios: Here two consecutive ldap requests are sent and the corresponding responses are read. a) Normal operation: main Thread connection reader Thread 1) unpause the reader 3) Reads the response for R1 2) Write request - R1 5) pauses 4) Waiting to get the response for R1 6) Gets the response for R1 7) unpause the reader 9) Reads the response for R2 8) Write request -R2 11) pauses 10) Waiting to get the response for R2 12) Gets the response for R2 b) when program hangs: main Thread connection reader Thread 1) unpauses the reader 4) Reads the response for R1 2) Writes request - R1 8) pauses 3) Waiting to get the response for R1 5) Gets the response for R1 6) unpauses the reader Writes request - R2 7) Waiting to get the response for R2 9) Waiting to get the response for R2 : : : In case of b the connection read thread falls behind and pauses very late. By this time the main thread moves ahead and finishes the write and moves with a read where it sees no response available yet and keeps waiting for a response. The connection read now gets a chance and pauses resulting in a deadlock.
02-09-2004

SUGGESTED FIX The fix is to ensure that the reader thread is in paused state as soon as it finds out it needs to pause, before the main thread gets access to the result (that the reader just processed). This ensures that the main thread's subsequent unpause of the reader won't be missed. The old logic in the reader was 1. Get result <result now available to main thread> 2. If need pause, grab pauseLock, pause (release pauseLock). The new logic is 1. Grab pauseLock 2. Get result 3. If need pause, pause (releases pauseLock), otherwise release pauseLock <result now available to main thread> The fix has the overhead of grabbing the pauseLock for each read. Here are the code changes to the com.sun.jndi.ldap.Connection class. In run(): OLD: boolean needPause = false; if (inMsgId == 0) { // Unsolicited Notification parent.processUnsolicited(retBer); } else { LdapRequest ldr = findRequest(inMsgId); if (ldr != null) { needPause = ldr.addReplyBer(retBer); } else { // System.err.println("Cannot find LdapRequest for " + inMsgId); } } if (needPause) { pauseReader(); // wait until unpause } -------- NEW: if (inMsgId == 0) { // Unsolicited Notification parent.processUnsolicited(retBer); } else { LdapRequest ldr = findRequest(inMsgId); if (ldr != null) { // Grab pauseLock before making reply available // to ensure that reader goes into paused stated // before writer can attempt to unpause reader synchronized (pauseLock) { boolean needPause = ldr.addReplyBer(retBer); if (needPause) { // Go into paused state; release pauseLock pauseReader(); } // else release pauseLock } } else { // System.err.println("Cannot find LdapRequest for " + inMsgId); } } ------------ Updated pauseReader(): (Only change is to remove 'synchronized' wrapper). /* * Pauses reader so that it stops reading from the input stream. * Reader blocks on pauseLock instead of read(). * MUST be called from within synchronized (pauseLock) clause. */ private void pauseReader() throws IOException { if (debug) { System.err.println("Pausing reader; was reading from: " + inStream); } paused = true; try { while (paused) { pauseLock.wait(); // notified by unpauseReader } } catch (InterruptedException e) { throw new InterruptedIOException( "Pause/unpause reader has problems."); } } ---------------- Add unpauseReader() to cleanup() after the socket has been closed to ensure that thread exits. ###@###.### 2002-12-05
05-12-2002