shashank created CAMEL-25509:
--------------------------------
Summary: camel-ldif - "changetype: modrdn" ignores newsuperior,
and "changetype: moddn" without newsuperior moves the entry to the root
Key: CAMEL-25509
URL: https://issues.apache.org/jira/browse/CAMEL-25509
Project: Camel
Issue Type: Bug
Reporter: shashank
RFC 2849 defines {{modrdn}} and {{moddn}} as the same change type
({{change-moddn = ("modrdn" / "moddn") SEP "newrdn:" ... "deleteoldrdn:" ...
[SEP "newsuperior:" ...]}}): the entry gets the new RDN, and moves under the
new superior only when {{newsuperior}} is given (RFC 4511 4.9).
{{LdifProducer.processLdifEntry}} (lines 161-172 at main c578a42a776d) treats
them as two different operations:
{code:java}
} else if (ldifEntry.isChangeModDn()) {
conn.moveAndRename(ldifEntry.getDn(), new Dn(ldifEntry.getNewRdn(),
ldifEntry.getNewSuperior()), ...);
} else if (ldifEntry.isChangeModRdn()) {
conn.rename(ldifEntry.getDn(), new Rdn(ldifEntry.getNewRdn()), ...);
}
{code}
* A {{modrdn}} record with {{newsuperior}} renames the entry in place: it is
not moved, and the result for the record is still {{success}}.
* A {{moddn}} record without {{newsuperior}} (a plain rename, valid per RFC
2849) builds {{new Dn(newRdn, null)}}, which is the one-RDN DN {{uid=b}}, so
the request moves the entry directly under the root and the server rejects it.
The Apache LDAP API's {{LdifReader}} keeps the two keywords apart
({{ChangeType.ModRdn}}/{{ModDn}}) and reads {{newsuperior}} for both.
h3. Reproduction
New {{LdifModDnTest}}, with a stub {{LdapConnection}} (a
{{java.lang.reflect.Proxy}}) that records the DN each rename/move gives the
entry, so no LDAP server is needed. On main:
{noformat}
modRdnWithNewSuperiorMovesTheEntry: expected: <uid=b,ou=new,dc=example,dc=org
deleteOldRdn=true> but was: <uid=b,ou=old,dc=example,dc=org deleteOldRdn=true>
modDnWithoutNewSuperiorKeepsTheParent: expected:
<uid=b,ou=old,dc=example,dc=org deleteOldRdn=true> but was: <uid=b
deleteOldRdn=true>
{noformat}
The controls ({{moddn}} with {{newsuperior}}, {{modrdn}} without it, as in
{{LdifRouteIT}}) pass.
h3. Proposed fix
One branch for both change types: {{moveAndRename(dn, new Dn(newRdn,
newSuperior), deleteOldRdn)}} when {{newsuperior}} is given, {{rename(dn, new
Rdn(newRdn), deleteOldRdn)}} otherwise. The requests for the two cases that
worked are unchanged; a short upgrade guide note for 4.23 describes the two
changed cases. camel-ldif unit tests with the fix: 5, 0 failures
({{LdifRouteIT}} needs the OpenLDAP container and was not run; its modDn/modRdn
cases send the same requests as before).
Found with a Lean 4 model of the dispatch (DNs as lists of RDNs, the effect of
rename and moveAndRename on the entry's DN): "the new DN is newrdn under
newsuperior if given, else under the current parent, for both keywords" fails
for the two records above, and is proved to fail for every {{modrdn}} with a
{{newsuperior}} other than the current parent and every {{moddn}} without
{{newsuperior}} of an entry not directly under the root. The fix is proved
correct for all records, and to send exactly main's request in the two cases
main got right. Then confirmed with the real producer and LDAP API as above.
Affected: main, camel-4.18.x, camel-4.14.x (same code, GitHub contents API).
The component was added in 2017 (CAMEL-11778).
Duplicate check (2026-10-09): JIRA text "ldif" (9 hits: component creation, URL
opt-in CAMEL-24297, upgrades), "modrdn" (none); GitHub pull requests "ldif
modrdn", "ldif newsuperior", "LdifProducer": none (only the CVE pin #25622).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)