Skip to content

Fixes #29835: make read authorization independent of the fields projection - #30691

Open
sonika-shah wants to merge 1 commit into
open-metadata:mainfrom
sonika-shah:fix/authz-projection-independent-fields
Open

Fixes #29835: make read authorization independent of the fields projection#30691
sonika-shah wants to merge 1 commit into
open-metadata:mainfrom
sonika-shah:fix/authz-projection-independent-fields

Conversation

@sonika-shah

@sonika-shah sonika-shah commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Describe your changes:

Fixes #29835

ResourceContext.resolveEntity() loaded the entity used for policy evaluation with the caller's fields query parameter. Any policy-relevant attribute the caller did not request read as absent, so a conditional Deny rule silently failed open — matchAnyTag returns false when tags were never loaded.

Measured on a table tagged PII.Sensitive with a DENY VIEW_ALL where matchAnyTag('PII.Sensitive') rule, as a non-admin user:

Request Before After
GET /v1/tables/{id} 200 — leaked 403
GET /v1/tables/{id}?fields=tags 403 403
GET /v1/tables/{id}?fields=owners 200 — leaked 403
GET /v1/tables/name/{fqn} 200 — leaked 403
untagged table, no fields 200 200

The authorization entity is now always resolved with the policy-relevant fields (owners, tags, domains, reviewers) rather than the caller-supplied projection. The response load is untouched, so response payloads are byte-identical.

Side effect: removing the projection makes the authorization read cache-eligible again — useRepositoryCache() returned false whenever requestedFields was set, so this path was previously uncached.

Scope

This closes the projection-dependence gap. It does not change column-level tag enforcement: column tags hydrate only when columns and tags are both loaded (TableRepository#setFields), which is unchanged here and tracked separately.

Type of change:

  • Bug fix

High-level design:

N/A — removes a branch, no new components.

Tests:

Use cases covered

  • A tag-based Deny rule is enforced on GET by id and by name regardless of the fields parameter.
  • A projection that excludes tags (fields=owners) does not bypass the rule.
  • An entity without the tag remains viewable — the rule does not over-block.

Unit tests

  • Not applicable — covered by integration tests below.

Backend integration tests

  • Added to openmetadata-integration-tests.
  • File: QueryVisibilityPolicyIT#test_tagDenyPolicy_enforcedWhenFieldsParamOmitted (added to the existing tag-policy IT rather than a new file).

Ingestion integration tests

  • Not applicable.

Playwright (UI) tests

  • Not applicable — no UI changes.

Manual testing performed

  1. Created a table tagged PII.Sensitive, a DENY VIEW_ALL policy conditioned on matchAnyTag, and a non-admin user carrying it.
  2. Confirmed the table was returned without fields, and denied with fields=tags — the reported inconsistency.
  3. Applied the change and confirmed all four request shapes above are denied, and an untagged table still returns 200.

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR is linked to a GitHub issue via Fixes #29835.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests and listed them above.

Greptile Summary

Authorization entity loading is now independent of the caller’s response projection.

  • GET-by-ID and GET-by-name resource contexts no longer receive caller-requested fields.
  • Policy evaluation consistently hydrates supported owners, tags, domains, and reviewers.
  • Repository caching is enabled for non-mutating authorization reads.
  • Integration coverage verifies tag-based deny rules with omitted, inclusive, and exclusive field projections while preserving access to untagged entities.

Confidence Score: 5/5

The PR appears safe to merge and closes the field-projection-dependent authorization gap.

Authorization now loads policy-relevant relationships independently from the response projection, while field-sensitive request caching remains isolated by field and relation keys and the response load remains separate.

Important Files Changed

Filename Overview
openmetadata-service/src/main/java/org/openmetadata/service/security/policyevaluator/ResourceContext.java Decouples authorization hydration from response fields and safely enables repository caching for GET policy resolution.
openmetadata-service/src/main/java/org/openmetadata/service/resources/EntityResource.java Updates GET-by-ID and GET-by-name paths to construct projection-independent authorization contexts.
openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/QueryVisibilityPolicyIT.java Adds end-to-end coverage for tag-based deny enforcement across field projections and untagged controls.

Sequence Diagram

sequenceDiagram
  participant Client
  participant Resource as EntityResource
  participant Auth as Authorizer
  participant Context as ResourceContext
  participant Repo as EntityRepository
  Client->>Resource: "GET entity?fields=<projection>"
  Resource->>Auth: authorize(operation, resource context)
  Auth->>Context: resolve policy entity
  Context->>Repo: load owners/tags/domains/reviewers
  Repo-->>Context: policy-complete entity
  Context-->>Auth: authorization attributes
  Auth-->>Resource: allow or deny
  alt allowed
    Resource->>Repo: load requested response projection
    Repo-->>Client: projected entity
  else denied
    Resource-->>Client: 403 Forbidden
  end
Loading

Reviews (1): Last reviewed commit: "fix(security): make read authorization i..." | Re-trigger Greptile

Context used:

…ection

ResourceContext loaded the entity for policy evaluation using the caller's
`fields` query parameter. A policy attribute that was not requested read as
absent, so a conditional Deny rule silently failed open — GET /v1/tables/{id}
without `fields=tags` returned a table that a matchAnyTag Deny rule should
have blocked, while the same request with `fields=tags` was correctly denied.

Always resolve the authorization entity with the policy-relevant fields
(owners, tags, domains, reviewers) instead of the caller-supplied projection.
The response load is unchanged, so payloads are unaffected. Removing the
projection also makes the authorization read cache-eligible again, since
useRepositoryCache() disabled caching whenever requestedFields was set.

Fixes open-metadata#29835
Copilot AI review requested due to automatic review settings July 30, 2026 09:55
@sonika-shah
sonika-shah requested a review from a team as a code owner July 30, 2026 09:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions github-actions Bot added backend safe to test Add this label to run secure Github workflows on PRs labels Jul 30, 2026
@gitar-bot

gitar-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Makes read authorization independent of the caller's fields projection by resolving policy entities with all required attributes, preventing conditional deny rules from failing open. No issues found.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar | Powered by Gitar — free for open source

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

REST API authorization bypasses tag-based Deny policies when entity metadata is not loaded

2 participants