From 18fd136fa155befe4e43f294c5629c178d5e6414 Mon Sep 17 00:00:00 2001
From: Valera V Harseko <vharseko@3a-systems.ru>
Date: Wed, 21 Oct 2026 08:52:49 +0000
Subject: [PATCH] GHSA-jr68-5c58-j463 DSMLv2 gateway changes XML data binding of other applications in the same JVM
---
opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java | 55 ++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java b/opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java
index 15fefeb..e2b6d47 100644
--- a/opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java
+++ b/opendj-dsml-servlet/src/main/java/org/opends/dsml/protocol/DSMLServlet.java
@@ -125,6 +125,11 @@
private static final String TRUSTALLCERTS = "ldap.trustall";
private static final String USEHTTPAUTHZID = "ldap.authzidtypeisid";
private static final String EXOPSTRINGPREFIX = "ldap.exop.string.";
+ /**
+ * JAXB RI system property mapping xsd:anyURI to java.net.URI instead of
+ * java.lang.String. See the caveats in {@link #init(ServletConfig)}.
+ */
+ private static final String MAP_ANYURI_TO_URI = "mapAnyUriToUri";
private static final String DEREF_ANYURI = "ldap.dsml.dereference.anyuri";
private static final String DEREF_ANYURI_SCHEMES = "ldap.dsml.dereference.anyuri.schemes";
private static final String DEREF_ANYURI_MAXSIZE = "ldap.dsml.dereference.anyuri.maxsize";
@@ -225,11 +230,6 @@
}
}
- // Materialise anyURI values as java.net.URI so that, when dereferencing
- // is explicitly enabled, they can be fetched. Dereferencing itself is
- // gated and hardened in ByteStringUtility (disabled by default).
- System.setProperty("mapAnyUriToUri", "true");
-
// Server-side dereferencing of anyURI values is disabled by default
// (SSRF / local-file / unbounded-read hardening, GHSA-68r5-9hpg-7qw9).
// Enable it explicitly, and optionally tune the scheme allowlist and the
@@ -238,6 +238,27 @@
ByteStringUtility.setDereferenceUri(derefAnyUri);
if (derefAnyUri)
{
+ // Materialise anyURI values as java.net.URI, otherwise they are bound
+ // to String and are stored verbatim rather than dereferenced. This is
+ // only done when dereferencing is wanted, because the property comes
+ // with four caveats (GHSA-jr68-5c58-j463):
+ // - it is JVM-global rather than per-JAXBContext, so it also changes
+ // the anyURI binding of every other application initialising JAXB in
+ // this JVM afterwards;
+ // - the JAXB RI tests it for presence, not for its value, so setting
+ // it to "false" would enable the mapping just as well;
+ // - it is read once, by the static initialiser of the JAXB runtime, so
+ // it has no effect if JAXB has already been initialised, and only the
+ // JAXB RI honours it at all - EclipseLink MOXy ignores it, which is
+ // why the gateway must ship exactly one Jakarta XML Binding provider
+ // (pinned by JaxbProviderTestCase);
+ // - the URI binding narrows the accepted values: a lexical form which
+ // is a valid xsd:anyURI but not a valid java.net.URI is turned into a
+ // null by the runtime, and is then reported to the client as an
+ // unresolvableURI error rather than being silently dropped (see
+ // ByteStringUtility.convertRequiredValue).
+ System.setProperty(MAP_ANYURI_TO_URI, "true");
+
String schemes = stringValue(config, DEREF_ANYURI_SCHEMES);
if (schemes != null && !schemes.trim().isEmpty())
{
@@ -345,8 +366,19 @@
}
/**
- * Check if using the proxy authz control will work, by using it to read
- * the Root DSE.
+ * Pre-flight probe telling whether the proxy authz control is usable, by
+ * sending it along with a Root DSE read.
+ * <p>
+ * This is a fail-fast diagnostic, not an access decision: the control it
+ * returns is attached to every operation of the batch request, and the
+ * server evaluates it independently on each of them. That evaluation
+ * requires the authenticated identity to hold the {@code proxied-auth}
+ * privilege, the authorization ID to resolve to a usable entry, and an ACI
+ * granting the authenticated identity the {@code proxy} right over that
+ * entry; ordinary per-entry ACI evaluation then applies to the entries the
+ * operation touches. The probe runs the very same checks - the Root DSE is
+ * served by a local backend - so it only turns an authorization failure that
+ * would happen on the first operation into an error reported up front.
*
* @param connection The authenticated LDAP connection used to check.
* @param authorizationID The authorization ID, in the format
@@ -862,7 +894,9 @@
*
* @return a JAXBElement that contains an ErrorResponse
*/
- private JAXBElement<ErrorResponse> createXMLParsingErrorResponse(
+ // Package-private rather than private so that DSMLXmlParsingTestCase can
+ // exercise the fallback parser on the payloads SAAJ rejects.
+ JAXBElement<ErrorResponse> createXMLParsingErrorResponse(
InputStream is,
ObjectFactory objFactory,
BatchResponse batchResponse,
@@ -1186,7 +1220,10 @@
* @throws ParserConfigurationException if we cannot obtain a parser.
* @throws SAXException if we cannot obtain a parser.
*/
- private XMLReader createSafeXMLReader()
+ // Package-private rather than private so that DSMLXmlParsingTestCase can
+ // assert that the hardening features really did take effect: safeSetFeature
+ // logs and continues when a feature is unsupported by the parser in use.
+ XMLReader createSafeXMLReader()
throws ParserConfigurationException, SAXException
{
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
--
Gitblit v1.10.0