filter: handle multi-component substring filters - #7
Open
navibodybuilder wants to merge 1 commit into
Open
Conversation
RFC 4511 4.5.1.7 allows a SubstringFilter to carry at most one `initial`
(first), any number of `any`, and at most one `final` (last). Three
functions assumed there is exactly one component:
DecompileFilter emitted only Children[1].Children[0] and discarded
the rest, so a wire filter "(cn=svc-*-prod)"
decompiled to "(cn=svc-*)" -- a strictly BROADER
filter.
CompileFilter special-cased only "x*", "*x" and "*x*". A pattern
with an interior '*' ("a*b*c") matched none of them
and fell through to `default`, where it was encoded
as an equality match whose value contained a literal
'*'. No entry has a literal '*' in its value, so
those filters silently matched nothing.
ServerApplyFilter tested only Children[1].Children[0], so a
multi-component assertion was satisfied by its first
component alone: "(cn=svc-*-prod)" matched
"svc-door-dev".
The three interact, so they are fixed together. The decompile defect masks
the compile defect: a multi-component pattern is already truncated to one
component before CompileFilter sees it. Correcting either one alone turns a
superset result into an EMPTY one, which for a directory sync is the more
damaging failure -- an empty read is what makes a sync deprovision every
entry it did not receive.
Note that a compile/decompile round trip does not reproduce any of this,
because CompileFilter did not produce a wire-shaped substring packet
either. TestSubstringFilterWireFormat builds the packets the way a client
puts them on the wire, one child per component.
Tests: three multi-component patterns added to the existing round-trip
table, plus TestSubstringFilterWireFormat and
TestServerApplyFilterSubstrings. All three fail against the current code
(8 failures) and pass with this change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC 4511 §4.5.1.7 allows a
SubstringFilterto carry at most oneinitial(first), any number of
any, and at most onefinal(last). Three functions infilter.goassume there is exactly one component, and they interact, so thisfixes them together.
What breaks today
DecompileFilterChildren[1].Children[0](cn=svc-*-prod)decompiles to(cn=svc-*)— a strictly broader filterCompileFilterx*,*x,*x**(a*b*c) is encoded as an equality match holding a literal*, which matches no entryServerApplyFilterChildren[1].Children[0](cn=svc-*-prod)matchessvc-door-devThe practical impact depends on which one you hit first. A server that decompiles
an incoming request (to log it, route it, or hand it to a backend as a string)
silently answers a different, broader question than the client asked. A caller
that compiles a multi-component pattern gets no results at all.
Why they must be fixed together
The decompile defect masks the compile defect: a multi-component pattern is
already truncated to a single component before
CompileFiltersees it. Fixingeither one alone converts a superset result into an empty one — which, for a
directory sync, is the more damaging failure, because an empty read is what makes
a sync deprovision every entry it did not receive.
A note for reviewers
A compile → decompile round trip does not reproduce any of this, because
CompileFilterdid not produce a wire-shaped substring packet either. That iswhy the round-trip table in
filter_test.gonever caught it.TestSubstringFilterWireFormatbuilds the packets the way a client actually putsthem on the wire — one child per component — which is what
ldapsearch, ActiveDirectory and JNDI all send.
Tests
testFiltersround-triptable.
TestSubstringFilterWireFormat— decompiles wire-shaped packets.TestServerApplyFilterSubstrings— matching, including thatinitialandfinalmay not consume the same characters ((cn=prod*prod)matchesprod-prodbut notprod).All existing tests continue to pass. Against the current code the new tests
produce 8 failures:
(
TestConnect,TestSearch,TestSearchWithPagingandTestMultiGoroutineSearchdial the live public serverldap.itd.umich.eduandfail wherever outbound 389 is closed. They are unrelated to this change and fail
the same way without it.)
Backwards compatibility
Single-component filters —
(cn=x*),(cn=*x),(cn=*x*),(cn=*)— areunchanged in both encoding and matching. A condition of only asterisks (
**)still encodes a single empty
any, preserving the previous match-everythingbehaviour rather than emitting an empty substrings sequence, which RFC 4511
forbids.