Skip to content

DbalObjectSourceProvider silently returns empty when the shared Source's organisation differs from the caller's active org (SaaS mode) #2089

Description

@rubenvdlinde

Summary

Follow-up to #2084 / PR #2088. That PR fixed the reported orX() zero-args defect in MultiTenancyTrait::applyActiveOrgFilter(), but live-verification on the shared dev instance showed dbal-source (query-backed) schemas — e.g. spectr-live's v-app-market, apps (register 2479, backed by Source spectr intelligence-db, uuid beb5b7d0-19bd-42b6-a7c4-9d10cc840a31) — still return total: 0 with {"saasMode":true,"adminOverride":true}, even after that fix.

Root cause

DbalObjectSourceProvider::resolveSource() (lib/Service/ObjectSource/DbalObjectSourceProvider.php) loads the backing Source entity via:

$matches = $this->sourceMapper->findAll(filters: ['uuid' => $sourceId]);
$source  = ($matches[0] ?? null);

SourceMapper uses MultiTenancyTrait, and findAll() applies applyOrganisationFilter(..., allowNullOrg: false) to this query, same as any tenant-owned row. The spectr intelligence-db Source row has its own organisation (286a9152-4b09-4714-9115-fabbbad342d0) which differs from the querying admin's active organisation (9db9eae6-5049-47cd-a434-a68568cf3a01).

Under normal config, adminOverride bypasses this and everything works — that's exactly why the current workaround ({"saasMode":false,"adminOverride":true}) masks the problem. But saasMode: true unconditionally disables admin override (MultiTenancyTrait::isAdminOverrideEnabled()), so the Source row gets excluded by the org filter, findAll() returns [], resolveSource() returns null, resolveContext() logs only a warning ([ObjectSource:dbal-source] no source resolved for schema ...) and returns null, and every downstream find/findAll/count/aggregate on that schema silently returns empty — no exception ever surfaces to the caller. Confirmed live via nextcloud.log.

Why this matters

A Source (external DB connection config) is shared infrastructure, not tenant-owned data — it's the provider multiple dbal-backed schemas connect through, not an object that itself belongs to one tenant's data set. Scoping its own lookup by the querying user's active organisation means any dbal-backed schema becomes invisible to every user whose active org doesn't happen to match the Source's organisation column, independent of whatever RBAC the target schema itself declares.

Suggested fix direction (needs a design decision, not a mechanical patch)

One of:

  • Exempt Source entities from organisation-scoped filtering when resolved internally by DbalObjectSourceProvider (they're infrastructure config, gate on RBAC/admin-only elsewhere), or
  • Treat Source.organisation as informational/ownership metadata only, and let the schema's own authorization/RBAC (already enforced via MagicOrganizationHandler/applyOrganisationFilter on the resulting objects) be the actual access boundary, or
  • Give Source records allowNullOrg: true semantics plus an explicit cross-org-visible flag for shared connections.

Repro

occ config:app:set openregister multitenancy --value='{"saasMode":true,"adminOverride":true}'
curl -u admin:admin 'http://localhost:8080/apps/openregister/api/objects/spectr-live/v-app-market?_limit=3'
# {"results":[],"total":0,...}
# nextcloud.log: [ObjectSource:dbal-source] no source resolved for schema v-app-market
occ config:app:set openregister multitenancy --value='{"saasMode":false,"adminOverride":true}'

Current instance state

Workaround {"saasMode":false,"adminOverride":true} remains in place on the shared dev instance and MUST stay until this is resolved — flipping saasMode back to true empties all dbal-source schemas again (confirmed, unrelated to #2084's fix which is already merged).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions