group_restrictions not enforced in getPrincipalsByPrefix/getPrincipalByPath: restricted rooms stay visible in Calendar's "Show rooms" dialog
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
⚠️ This issue respects the following points: ⚠️
- This is a bug, not a question or a configuration issue.
- This issue is not already reported on GitHub (I've searched it).
Bug description
group_restrictions on a calendar room or resource are enforced in some of AbstractPrincipalBackend's read paths but not in others. As a result a restricted room stays visible to users outside the allowed group in Nextcloud Calendar's "Show rooms" dialog, while the attendee type-ahead correctly hides it.
isAllowedToAccessResource() is called from searchPrincipals() and findByUri(), but not from getPrincipalsByPrefix() or getPrincipalByPath() — those two do not even select the group_restrictions column:
| Method | Selects group_restrictions |
Calls isAllowedToAccessResource() |
|---|---|---|
getPrincipalsByPrefix() (L70) |
no | no |
getPrincipalByPath() (L121) |
no | no |
searchPrincipals() (L204) |
yes | yes |
findByUri() (L400) |
yes | yes |
Calendar fills the "Show rooms" dialog via fetchRoomAndResourcePrincipals(), which does a PROPFIND on dav/principals/calendar-rooms/ — i.e. straight through getPrincipalsByPrefix().
Only the room's name, email and metadata leak; booking is still rejected server-side. But room names and locations can reveal organisational structure, which is exactly what the restriction is meant to prevent.
Steps to reproduce
- Have a room backend providing at least one room (any app implementing
IRoomBackend). - Give that room a
group_restrictionsvalue, e.g.["test"], and let the hourlyUpdateCalendarResourcesRoomsBackgroundJobwrite it tooc_calendar_rooms. - Log in as a user who is not in that group.
- Create an event in Calendar → Resources → Show rooms.
Expected behaviour
The restricted room is not listed, consistent with the attendee type-ahead.
Actual behaviour
The room is listed with its name, email and metadata.
Measured directly against the backend on a live NC 34 instance, with two test accounts differing only in group membership:
user groups searchPrincipals getPrincipalsByPrefix
roomtest-in [test] 1 1
roomtest-uit [] 0 1 <-- should be 0
Setting the restriction back to [] makes both users see the room again through both paths, which confirms the restriction itself is stored and evaluated correctly — one of the two read paths simply skips the check.
Note for whoever picks this up
AbstractPrincipalBackendTestCase::testGetPrincipalsByPrefix() currently asserts that all six fixtures are returned, including res5 (["foo", "bar"]) and res6 (["group1", "bar"]), and it does not mock a user session. So the present behaviour is pinned by a test — fixing this means deciding that the test encodes a bug rather than an intent, which felt like a call for a maintainer rather than something to settle in a drive-by PR.
There is also a question I could not answer from the outside: searchPrincipals() and findByUri() both bail out when there is no session (return [] / return null), but getPrincipalsByPrefix() has no such guard, and the backend is used both by the principal collection and by CalendarRoot in RootCollection.php. If some path reaches it without a session, adding a filter there would hide every room instead of the restricted ones — a worse regression than the bug.
Happy to prepare a PR once you indicate the preferred direction (filter in the backend vs. filter in the Calendar dialog).
Nextcloud Server version
34
Operating system
Other
PHP engine version
PHP 8.4
Web server
Apache (supported)
Database engine version
PostgreSQL
Is this bug present after an update or on a fresh install?
Updated to a major version (ex. 32.0.9 to 33.0.4)
Are you using the Nextcloud Server Encryption module?
Encryption is Disabled
Are you using an external user-backend, if yes which one?
- LDAP/ Active Directory
- SSO - SAML
- Other
Server configuration detail
Calendar app 6.5.4. Room provided by a third-party IRoomBackend implementation; the same code path applies to any room backend.
Nextcloud Signing status
No response
Nextcloud Logs
No response
Additional info
Related: the same dialog also renders the literal string undefined inside busy blocks — that one is a Calendar-side issue and is being fixed separately in nextcloud/calendar#8780.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with getPrincipalsByPrefix() and getPrincipalByPath() in AbstractPrincipalBackend, then compare their session handling with searchPrincipals() and findByUri(). Run AbstractPrincipalBackendTestCase::testGetPrincipalsByPrefix(), which currently expects all six fixtures, and inspect CalendarRoot in RootCollection.php for callers without a session. Done means restricted rooms are absent for unauthorized users without hiding unrestricted rooms or breaking session-less callers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- authorization, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100