[Bug]: "Limit to groups" picker (2FA enforcement) can never show some groups, and shows raw group ID instead of display name
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
Bug description
Settings > Administration > Security > "Two-Factor Authentication" > "Limit to groups" (the "Enforced groups"/"Excluded groups" pickers) uses a group picker (apps/settings/src/components/AdminTwoFactor.vue) with two related problems:
-
On page load, before typing anything, it calls
GET /ocs/v2.php/cloud/groupswith an empty search string andlimit=20. The backend (OC\Group\Database::getGroups()) orders resultsORDER BY gid ASC- the raw internal group ID, not the display name. If 20+ groups exist whose gid sorts alphabetically before the group you're looking for, that group can never appear in the unfiltered dropdown, no matter how far you scroll - the request only ever returns the first 20 rows by gid. This is especially visible for groups created by an app/plugin with a non-human-readable gid prefix (e.g.pluginname_1234), since those gids cluster together and can easily fall entirely outside the first 20 results once an installation has more than a couple dozen groups total. -
Even when a group IS found - e.g. by typing part of its display name into the search box (
OC\Group\Database::getGroups($search)does correctly matchdisplayname ILIKE %search%too, so search-by-name works) - the result is unusable:Provisioning_API\Controller\GroupsController::getGroups()(the controller behindcloud/groups) returns only$group->getGID()for each match, never the display name. So a group with a friendly display name but an opaque gid shows up in the dropdown as that opaque gid, not its name - there's no way to visually confirm you found the right one.
Both were verified against the actual source and a real deployment, not deployment-specific quirks.
Steps to reproduce
- Have more than ~20 total Nextcloud groups, including at least one whose gid differs from its display name (e.g. created via an app using
IGroupManager::createGroup($opaqueId)+setDisplayName($friendlyName)), with enough other groups sorting alphabetically before that gid to push it past the first 20 results. - Go to Settings > Administration > Security.
- Enable "Enforce two-factor authentication".
- Open the "Enforced groups" (or "Excluded groups") dropdown without typing anything.
- The group with the opaque gid never appears, no matter how far you scroll - only the first 20 alphabetical-by-gid results are ever loaded.
- Type a substring of that group's actual display name into the search box.
- The group is now found and can be selected - but it displays as its raw internal ID (e.g.
pluginname_1234), not its display name.
Expected behavior
- The initial (empty-search) group list shouldn't systematically exclude entire classes of groups just because of alphabetical gid ordering + a small fixed cap - e.g. order by display name instead, or drop the artificial 20-item cap for the initial load.
- Dropdown entries should show the group's display name (already available via
cloud/groups/details), not the raw gid.
Where this comes from
apps/settings/src/components/AdminTwoFactor.vue: callssearchGroup('')on mount, hittingcloud/groups?search=&limit=20.apps/provisioning_api/lib/Controller/GroupsController.php::getGroups(): returnsarray_map(fn($group) => $group->getGID(), $groups)- no display name.lib/private/Group/Database.php::getGroups():ORDER BY gid ASC; theWHEREclause does correctly search bothgidanddisplayname.
#46634 looked related at first glance but is a different, already-fixed bug (the app-permissions group picker losing its checked state on reload) - not this cutoff/display-name problem, so I don't believe this is a duplicate.
Installation method
Community Docker image
Nextcloud Server version
33
Operating system
Linux
PHP engine version
PHP 8.3
Web server
Apache (supported)
Database engine version
MariaDB
Is this bug present after an update or on a fresh install?
Unknown - this looks like a long-standing logic issue rather than a recent regression, but I haven't bisected further back than 33.
Are you using the Nextcloud Server Encryption module?
Encryption is Disabled
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
Read apps/settings/src/components/AdminTwoFactor.vue, provisioning_api/lib/Controller/GroupsController.php, and lib/private/Group/Database.php, starting with the empty-search request and the group response mapping. Trace both picker loading paths and verify that groups beyond the initial limit can be found and that entries expose display names rather than only GIDs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, php
- Domain
- authentication, backend, frontend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100