Two unhandled NullPointerExceptions in DSMLServlet.doPost(), found while triaging an unrelated report against the same file. Both escape doPost() and reach the container as a 500; the first one additionally leaks the LDAP connection to the directory server.
File: opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java
1. abandonRequest causes an NPE and leaks the LDAP connection
performLDAPRequest() deliberately returns null for an abandon request:
} else if (request instanceof AbandonRequest) {
// Process the abandon request.
...
ao.doOperation(objFactory, ar, controls);
return null;
}
The caller guards the null only when adding to the response list, then dereferences it unconditionally:
JAXBElement<?> result = performLDAPRequest(connection, objFactory, proxyAuthzControl, request);
if ( result != null ) {
batchResponses.add(result);
}
// evaluate response to check if an error occurred
Object o = result.getValue(); // NPE when the request was an abandonRequest
abandonRequest is a valid child of batchRequest in DSMLv2.xsd, so <abandonRequest abandonID="1"/> inside a batch reaches this line whenever DSMLAbandonOperation.doOperation succeeds (it only throws for a non-numeric abandonID, which would be turned into an error response instead).
The block that opens the connection is not wrapped in try/finally:
if ( connected ) {
for (DsmlMessage request : list) { ... } // NPE thrown here
}
// close connection to LDAP server
if ( connection != null ) {
connection.close(nextMessageID); // never reached
}
so connection.close(...) is skipped. org.opends.server.tools.LDAPConnection has no finalizer and closes its socket only in close(), so the socket to the directory server stays open. Every such request leaks one connection, which is trivially repeatable and ends in connection-handler exhaustion on the server.
Reproduce: POST a SOAP batch containing a single <abandonRequest abandonID="1"/> to /DSMLServlet. Expected: a batch response with no entry for the abandon (per DSMLv2). Actual: HTTP 500, and one leaked LDAP connection per request.
Fix: continue when result is null, and move the connection cleanup into a finally.
2. NPE when the request has no Content-Type header
messageFactory is assigned only inside the header loop, when a content-type header is present and matches SOAP 1.1 or 1.2. A POST without a Content-Type header is legal HTTP, and leaves messageFactory at null:
SOAPMessage message = messageFactory.createMessage(mimeHeaders, is); // NPE
Only SOAPException is caught there, so the NPE escapes doPost() → 500.
The same field is dereferenced again on the response path, which produces a second, quieter symptom: when an error response was already queued (for example invalid credentials) the parsing block is skipped, and
sendResponse(doc, messageFactory, messageContentType, res);
throws the NPE inside a catch (Exception e) { e.printStackTrace(); }. The client then receives an empty HTTP 200 instead of the credentials error.
Fix: treat a missing or unsupported Content-Type as a malformed request and return a proper malformedRequest batch response (a default message factory for the response path, or an early rejection), rather than dereferencing null.
Both are long-standing and predate the Open Identity Platform fork.
Two unhandled
NullPointerExceptions inDSMLServlet.doPost(), found while triaging an unrelated report against the same file. Both escapedoPost()and reach the container as a 500; the first one additionally leaks the LDAP connection to the directory server.File:
opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java1.
abandonRequestcauses an NPE and leaks the LDAP connectionperformLDAPRequest()deliberately returnsnullfor an abandon request:The caller guards the
nullonly when adding to the response list, then dereferences it unconditionally:abandonRequestis a valid child ofbatchRequestinDSMLv2.xsd, so<abandonRequest abandonID="1"/>inside a batch reaches this line wheneverDSMLAbandonOperation.doOperationsucceeds (it only throws for a non-numericabandonID, which would be turned into an error response instead).The block that opens the connection is not wrapped in
try/finally:so
connection.close(...)is skipped.org.opends.server.tools.LDAPConnectionhas no finalizer and closes its socket only inclose(), so the socket to the directory server stays open. Every such request leaks one connection, which is trivially repeatable and ends in connection-handler exhaustion on the server.Reproduce: POST a SOAP batch containing a single
<abandonRequest abandonID="1"/>to/DSMLServlet. Expected: a batch response with no entry for the abandon (per DSMLv2). Actual: HTTP 500, and one leaked LDAP connection per request.Fix:
continuewhenresultisnull, and move the connection cleanup into afinally.2. NPE when the request has no
Content-TypeheadermessageFactoryis assigned only inside the header loop, when acontent-typeheader is present and matches SOAP 1.1 or 1.2. A POST without aContent-Typeheader is legal HTTP, and leavesmessageFactoryatnull:Only
SOAPExceptionis caught there, so the NPE escapesdoPost()→ 500.The same field is dereferenced again on the response path, which produces a second, quieter symptom: when an error response was already queued (for example invalid credentials) the parsing block is skipped, and
throws the NPE inside a
catch (Exception e) { e.printStackTrace(); }. The client then receives an empty HTTP 200 instead of the credentials error.Fix: treat a missing or unsupported
Content-Typeas a malformed request and return a propermalformedRequestbatch response (a default message factory for the response path, or an early rejection), rather than dereferencingnull.Both are long-standing and predate the Open Identity Platform fork.