Skip to content

fix(acl): correctly evaluate multi-match JSONPath labels#13527

Open
shreemaan-abhishek wants to merge 1 commit into
apache:masterfrom
shreemaan-abhishek:backport/acl-multi-match
Open

fix(acl): correctly evaluate multi-match JSONPath labels#13527
shreemaan-abhishek wants to merge 1 commit into
apache:masterfrom
shreemaan-abhishek:backport/acl-multi-match

Conversation

@shreemaan-abhishek

Copy link
Copy Markdown
Contributor

Description

The acl plugin extracts the external-user label value from ctx.external_user using a JSONPath expression (external_user_label_field). It did so with single-value jp.value(), which returns only the first match of the JSONPath query.

For external users that belong to multiple organizations/teams, a JSONPath such as $.orgs..team or $..name matches several values, but only the first one was evaluated. This caused two problems:

  • ACL bypass / missed deny: a denied label that lives in a second or later match was never inspected, so a request that should have been rejected could pass.
  • Possible crash: when a later (or the only) match is itself a table, that table could be passed to the segmented_text string parser, where re_split cannot operate on a table value.

This change reads all matches with jp.query():

  • 0 or 1 match: behavior is unchanged (the original jp.value() semantics are preserved, including letting the json/segmented_text parser reject a single table value).
  • 2 or more matches: the configured parser is applied to each matched value individually and the parsed sub-values are merged before allow/deny matching. A type guard ensures a table sub-value is routed through the type-aware path instead of the string parser.

This is an internal correctness fix. There is no schema or option change and no change to documented behavior, so the plugin docs are unchanged.

Tests

  • Updated t/plugin/acl.t TEST 32: a multi-match JSONPath whose values include a packed allowed label ("cloud|infra") is now correctly honored (200 instead of 403).
  • Added two tests: one configures a multi-match JSONPath with a segmented_text parser where a denied label (infra) is packed inside a parsed value ("infra,qa"), confirming the denied label is now caught (403).

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change (no doc change needed; internal fix)
  • I have verified that the code is correctly formatted (luacheck passes)

The ACL plugin read the external_user label field with single-value
jp.value(), which returns only the FIRST JSONPath match. For external
users that belong to multiple orgs/teams, the allow/deny matching then
ran against an incomplete label set: a denied label packed into a later
match could be missed (ACL bypass), and a matched value that is a table
could be handed to the string parser and crash re_split.

Use jp.query() to collect ALL matches. With 0 or 1 match the original
jp.value() semantics are preserved. With 2 or more matches, the
configured parser is applied to each matched value individually and the
parsed sub-values are merged before allow/deny matching, with a type
guard so a table sub-value is not passed to the string parser.
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant