Skip to content

fix(rbac): NC-32 IResult lacks fetchAllAssociative() → RBAC fail-closes every internal read#2035

Merged
rubenvdlinde merged 1 commit into
developmentfrom
fix/nc32-iresult-fetchallassociative-rbac-failclose
Jul 22, 2026
Merged

fix(rbac): NC-32 IResult lacks fetchAllAssociative() → RBAC fail-closes every internal read#2035
rubenvdlinde merged 1 commit into
developmentfrom
fix/nc32-iresult-fetchallassociative-rbac-failclose

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Problem

On Nextcloud 32, OC\DB\ResultAdapter (what IQueryBuilder::executeQuery() returns) does not expose Doctrine's fetchAllAssociative() — calling it throws Call to undefined method.

RegisterMapper::getAllRegisterIdsWithSchema() used it, and that method runs inside PermissionHandler's authorization resolver (getRegisterForSchema()). Its catch re-throws as AuthorizationUnresolvableException, which fail-closes the action.

Net effect on NC 32: every RBAC-checked read via ObjectService::find() is denied even for admin — dashboard widgets (403), the status-transition engine (available-transitions → current status never resolves), and single-object reads. The list path still works (it uses findMultipleOptimized, no per-row resolver), which masks the root cause: the register lists data but every detail/aggregate read 403s.

Fix

Iterate fetch() instead of fetchAllAssociative(), matching the pattern already applied in MarkerLookupTrait. Two sites:

  • lib/Db/RegisterMapper.phpgetAllRegisterIdsWithSchema() (the RBAC-critical one)
  • lib/Controller/SettingsController.php — a diagnostic query (same NC-32 bug)

DbalObjectSourceProvider's fetchAllAssociative() calls are intentionally left — those run against an external raw \Doctrine\DBAL\Query\QueryBuilder whose Result does expose the method.

Verification

Reproduced + fixed on a live NC-32 instance (procest + OpenRegister). Before: available-transitions returned current: [] and loadCase failed / Unable to resolve register for schema N; procest dashboard widgets 403. After: current: {statusId, statusName} resolves and the widgets return 200. Surfaced while running procest's live-NC Playwright e2e suite against NC 32.

🤖 Generated with Claude Code

…ses every internal read

RegisterMapper::getAllRegisterIdsWithSchema() and SettingsController's diagnostic
query called Doctrine's fetchAllAssociative() on Nextcloud's IResult
(OC\DB\ResultAdapter), which does not expose that method on every supported
server — it is absent on NC 32 and throws 'Call to undefined method'.

getAllRegisterIdsWithSchema() runs inside PermissionHandler's authorization
resolver (getRegisterForSchema); its catch re-throws as
AuthorizationUnresolvableException and FAIL-CLOSES the action. The net effect on
NC 32: every RBAC-checked read via ObjectService::find() — dashboard widgets, the
status-transition engine (available-transitions → current status never resolves),
single-object reads — is denied even for admin, while the list path (which uses
findMultipleOptimized, no per-row resolver) still works, masking the cause.

Iterate fetch() instead, matching the fix already applied in MarkerLookupTrait.
Verified on a live NC-32 instance: available-transitions now resolves the status
name and procest dashboard widgets return 200 instead of 403.

DbalObjectSourceProvider's fetchAllAssociative() calls are left as-is — those run
against an external raw \Doctrine\DBAL\Query\QueryBuilder whose Result does
expose the method.
@rubenvdlinde
rubenvdlinde merged commit f4bb3f0 into development Jul 22, 2026
@rubenvdlinde
rubenvdlinde deleted the fix/nc32-iresult-fetchallassociative-rbac-failclose branch July 22, 2026 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant