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/groups with an empty search string and limit=20. The backend (OC\Group\Database::getGroups()) orders results ORDER 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 match displayname ILIKE %search% too, so search-by-name works) - the result is unusable: Provisioning_API\Controller\GroupsController::getGroups() (the controller behind cloud/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: calls searchGroup('') on mount, hitting cloud/groups?search=&limit=20.
apps/provisioning_api/lib/Controller/GroupsController.php::getGroups(): returns array_map(fn($group) => $group->getGID(), $groups) - no display name.
lib/private/Group/Database.php::getGroups(): ORDER BY gid ASC; the WHERE clause does correctly search both gid and displayname.
#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
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
IGroupManager::createGroup($opaqueId)+setDisplayName($friendlyName)), with enough other groups sorting alphabetically before that gid to push it past the first 20 results.pluginname_1234), not its display name.Expected behavior
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