RFR: 8362268: NPE thrown from SASL GSSAPI impl when TLS is used with QOP auth-int against Active Directory

Daniel Fuchs dfuchs at openjdk.org
Mon Feb 9 21:26:05 UTC 2026


On Mon, 9 Feb 2026 14:47:43 GMT, Jaikiran Pai <jpai at openjdk.org> wrote:

> Can I please get a review of this change which proposes to fix the issue reported in https://bugs.openjdk.org/browse/JDK-8362268?
> 
> The underlying issue here is simple - A `javax.naming.Context` for LDAP is backed by a JDK internal `com.sun.jndi.ldap.LdapCtx` instance. Each `LdapCtx` uses a `com.sun.jndi.ldap.LdapClient` instance to do the LDAP operations. Each `LdapClient` further uses a `com.sun.jndi.ldap.Connection` instance. Each `Connection` instance uses a `Socket` and the socket's `InputStream` and `OutputStream` to read/write LDAP messages from/to a LDAP server. Each `Connection` instance spawns a `Thread` to read (over the InputStream) and queue incoming messages from the LDAP server.
> 
> When a LDAP backed `javax.naming.Context` initiates an operation, for example a `Context.lookup()`, then internally the LdapCtx initiates a LDAP request over the Connection's `OutputStream` and then waits for a LDAP response to arrive. In the issue reported here, it so happens that while reading over the `Connection`'s `InputStream`, the `InputStream.read()` raises an `IOException` (for whatever reason). That `IOException` rightly initiates the close of the `Connection` instance. Closing a `Connection` instance involves queuing a marker response for all waiting thread(s) to notice and raise an IOException, which they can ulimately propagate as a `NamingException` to the application. Additionally, the closing of the `Connection` also closes the `InputStream` and `OutputStream` of that `Connection`.
> 
> When a thread that was waiting for a LDAP response, in LdapCtx, wakes up due to an IOException, it attempts to send a "abandon request" LDAP message over the `Connection`, so that the server knows that the client has abandoned the request. Since the Connection and its Input/OutputStream(s) are already closed, trying to write a message over the OutputStream can/will lead to an exception. The implementation of `Connection.abandonRequest(LdapRequest ldr, Control[] reqCtls)` which is where this code resides, guards against such exceptions by catching and ignoring an `IOException` from an `OutputStream.write(...)/flush()` call.
> 
> Although `OutputStream.write(...)` is specified to throw an IOException if that stream is already closed, not all implementations adhere to that specification. For example, `java.io.BufferedOutputStream` does not throw any exception when `write(...)` is invoked on a closed `OutputStream`. Incidentally, the `Connection` instance's `OutputStream` is a `Bu...

src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java line 554:

> 552:                     // on a (closed) stream of a connection that can no longer be used.
> 553:                     return;
> 554:                 }

I am not sure this is the right test. If I am not mistaken, this means that "abandon request" will never be sent to the server, ever, since the flag is set to false in cleanup() before abandonning requests. 
Should we instead test whether the socket output is closed here?

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/29638#discussion_r2783554381


More information about the core-libs-dev mailing list