Skip to content

Commit 7231883

Browse files
authored
Merge pull request #53369 from nextcloud/bug/noid/principal-guest_app-not-found
fix: hide guests group when searching for principals
2 parents b40acb3 + 6254354 commit 7231883

File tree

9 files changed

+214
-0
lines changed

9 files changed

+214
-0
lines changed

apps/dav/lib/DAV/GroupPrincipalBackend.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ public function searchPrincipals($prefixPath, array $searchProperties, $test = '
188188
$groups = $this->groupManager->search($value, $searchLimit);
189189

190190
$results[] = array_reduce($groups, function (array $carry, IGroup $group) use ($restrictGroups) {
191+
if ($group->hideFromCollaboration()) {
192+
return $carry;
193+
}
194+
191195
$gid = $group->getGID();
192196
// is sharing restricted to groups only?
193197
if ($restrictGroups !== false) {

apps/testing/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
'OCA\\Testing\\Controller\\LockingController' => $baseDir . '/../lib/Controller/LockingController.php',
1414
'OCA\\Testing\\Controller\\RateLimitTestController' => $baseDir . '/../lib/Controller/RateLimitTestController.php',
1515
'OCA\\Testing\\Conversion\\ConversionProvider' => $baseDir . '/../lib/Conversion/ConversionProvider.php',
16+
'OCA\\Testing\\HiddenGroupBackend' => $baseDir . '/../lib/HiddenGroupBackend.php',
1617
'OCA\\Testing\\Listener\\GetDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/GetDeclarativeSettingsValueListener.php',
1718
'OCA\\Testing\\Listener\\RegisterDeclarativeSettingsListener' => $baseDir . '/../lib/Listener/RegisterDeclarativeSettingsListener.php',
1819
'OCA\\Testing\\Listener\\SetDeclarativeSettingsValueListener' => $baseDir . '/../lib/Listener/SetDeclarativeSettingsValueListener.php',

apps/testing/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ComposerStaticInitTesting
2828
'OCA\\Testing\\Controller\\LockingController' => __DIR__ . '/..' . '/../lib/Controller/LockingController.php',
2929
'OCA\\Testing\\Controller\\RateLimitTestController' => __DIR__ . '/..' . '/../lib/Controller/RateLimitTestController.php',
3030
'OCA\\Testing\\Conversion\\ConversionProvider' => __DIR__ . '/..' . '/../lib/Conversion/ConversionProvider.php',
31+
'OCA\\Testing\\HiddenGroupBackend' => __DIR__ . '/..' . '/../lib/HiddenGroupBackend.php',
3132
'OCA\\Testing\\Listener\\GetDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/GetDeclarativeSettingsValueListener.php',
3233
'OCA\\Testing\\Listener\\RegisterDeclarativeSettingsListener' => __DIR__ . '/..' . '/../lib/Listener/RegisterDeclarativeSettingsListener.php',
3334
'OCA\\Testing\\Listener\\SetDeclarativeSettingsValueListener' => __DIR__ . '/..' . '/../lib/Listener/SetDeclarativeSettingsValueListener.php',

apps/testing/lib/AppInfo/Application.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
use OCA\Testing\AlternativeHomeUserBackend;
1010
use OCA\Testing\Conversion\ConversionProvider;
11+
use OCA\Testing\HiddenGroupBackend;
1112
use OCA\Testing\Listener\GetDeclarativeSettingsValueListener;
1213
use OCA\Testing\Listener\RegisterDeclarativeSettingsListener;
1314
use OCA\Testing\Listener\SetDeclarativeSettingsValueListener;
@@ -26,6 +27,7 @@
2627
use OCP\AppFramework\Bootstrap\IBootContext;
2728
use OCP\AppFramework\Bootstrap\IBootstrap;
2829
use OCP\AppFramework\Bootstrap\IRegistrationContext;
30+
use OCP\IGroupManager;
2931
use OCP\Settings\Events\DeclarativeSettingsGetValueEvent;
3032
use OCP\Settings\Events\DeclarativeSettingsRegisterFormEvent;
3133
use OCP\Settings\Events\DeclarativeSettingsSetValueEvent;
@@ -68,5 +70,8 @@ public function boot(IBootContext $context): void {
6870
$userManager->clearBackends();
6971
$userManager->registerBackend($context->getAppContainer()->get(AlternativeHomeUserBackend::class));
7072
}
73+
74+
$groupManager = $server->get(IGroupManager::class);
75+
$groupManager->addBackend($server->get(HiddenGroupBackend::class));
7176
}
7277
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Testing;
11+
12+
use OCP\Group\Backend\ABackend;
13+
use OCP\Group\Backend\IHideFromCollaborationBackend;
14+
15+
class HiddenGroupBackend extends ABackend implements IHideFromCollaborationBackend {
16+
private string $groupName;
17+
18+
public function __construct(
19+
string $groupName = 'hidden_group',
20+
) {
21+
$this->groupName = $groupName;
22+
}
23+
24+
public function inGroup($uid, $gid): bool {
25+
return false;
26+
}
27+
28+
public function getUserGroups($uid): array {
29+
return [];
30+
}
31+
32+
public function getGroups($search = '', $limit = -1, $offset = 0): array {
33+
return $offset === 0 ? [$this->groupName] : [];
34+
}
35+
36+
public function groupExists($gid): bool {
37+
return $gid === $this->groupName;
38+
}
39+
40+
public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0): array {
41+
return [];
42+
}
43+
44+
public function hideGroup(string $groupId): bool {
45+
return true;
46+
}
47+
}

build/integration/config/behat.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ default:
8080
- CommandLineContext:
8181
baseUrl: http://localhost:8080
8282
ocPath: ../../
83+
- PrincipalPropertySearchContext:
84+
baseUrl: http://localhost:8080
8385
federation:
8486
paths:
8587
- "%paths.base%/../federation_features"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
2+
# SPDX-License-Identifier: AGPL-3.0-or-later
3+
4+
Feature: principal-property-search
5+
Background:
6+
Given user "user0" exists
7+
Given As an "admin"
8+
Given invoking occ with "app:enable --force testing"
9+
10+
Scenario: Find a principal by a given displayname
11+
When searching for a principal matching "user0"
12+
Then The search HTTP status code should be "207"
13+
And The search response should contain "<d:href>/remote.php/dav/principals/users/user0/</d:href>"
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
/**
3+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
4+
* SPDX-License-Identifier: AGPL-3.0-or-later
5+
*/
6+
7+
require __DIR__ . '/../../vendor/autoload.php';
8+
9+
use Behat\Behat\Context\Context;
10+
use GuzzleHttp\BodySummarizer;
11+
use GuzzleHttp\Client;
12+
use GuzzleHttp\HandlerStack;
13+
use GuzzleHttp\Middleware;
14+
use GuzzleHttp\Utils;
15+
use Psr\Http\Message\ResponseInterface;
16+
17+
class PrincipalPropertySearchContext implements Context {
18+
private string $baseUrl;
19+
private Client $client;
20+
private ResponseInterface $response;
21+
22+
public function __construct(string $baseUrl) {
23+
$this->baseUrl = $baseUrl;
24+
25+
// in case of ci deployment we take the server url from the environment
26+
$testServerUrl = getenv('TEST_SERVER_URL');
27+
if ($testServerUrl !== false) {
28+
$this->baseUrl = substr($testServerUrl, 0, -5);
29+
}
30+
}
31+
32+
/** @BeforeScenario */
33+
public function setUpScenario(): void {
34+
$this->client = $this->createGuzzleInstance();
35+
}
36+
37+
/**
38+
* Create a Guzzle client with a higher truncateAt value to read full error responses.
39+
*/
40+
private function createGuzzleInstance(): Client {
41+
$bodySummarizer = new BodySummarizer(2048);
42+
43+
$stack = new HandlerStack(Utils::chooseHandler());
44+
$stack->push(Middleware::httpErrors($bodySummarizer), 'http_errors');
45+
$stack->push(Middleware::redirect(), 'allow_redirects');
46+
$stack->push(Middleware::cookies(), 'cookies');
47+
$stack->push(Middleware::prepareBody(), 'prepare_body');
48+
49+
return new Client(['handler' => $stack]);
50+
}
51+
52+
/**
53+
* @When searching for a principal matching :match
54+
* @param string $match
55+
* @throws \Exception
56+
*/
57+
public function principalPropertySearch(string $match) {
58+
$davUrl = $this->baseUrl . '/remote.php/dav/';
59+
$user = 'admin';
60+
$password = 'admin';
61+
62+
$this->response = $this->client->request(
63+
'REPORT',
64+
$davUrl,
65+
[
66+
'body' => '<x0:principal-property-search xmlns:x0="DAV:" test="anyof">
67+
<x0:property-search>
68+
<x0:prop>
69+
<x0:displayname/>
70+
<x2:email-address xmlns:x2="http://sabredav.org/ns"/>
71+
</x0:prop>
72+
<x0:match>' . $match . '</x0:match>
73+
</x0:property-search>
74+
<x0:prop>
75+
<x0:displayname/>
76+
<x1:calendar-user-type xmlns:x1="urn:ietf:params:xml:ns:caldav"/>
77+
<x1:calendar-user-address-set xmlns:x1="urn:ietf:params:xml:ns:caldav"/>
78+
<x0:principal-URL/>
79+
<x0:alternate-URI-set/>
80+
<x2:email-address xmlns:x2="http://sabredav.org/ns"/>
81+
<x3:language xmlns:x3="http://nextcloud.com/ns"/>
82+
<x1:calendar-home-set xmlns:x1="urn:ietf:params:xml:ns:caldav"/>
83+
<x1:schedule-inbox-URL xmlns:x1="urn:ietf:params:xml:ns:caldav"/>
84+
<x1:schedule-outbox-URL xmlns:x1="urn:ietf:params:xml:ns:caldav"/>
85+
<x1:schedule-default-calendar-URL xmlns:x1="urn:ietf:params:xml:ns:caldav"/>
86+
<x3:resource-type xmlns:x3="http://nextcloud.com/ns"/>
87+
<x3:resource-vehicle-type xmlns:x3="http://nextcloud.com/ns"/>
88+
<x3:resource-vehicle-make xmlns:x3="http://nextcloud.com/ns"/>
89+
<x3:resource-vehicle-model xmlns:x3="http://nextcloud.com/ns"/>
90+
<x3:resource-vehicle-is-electric xmlns:x3="http://nextcloud.com/ns"/>
91+
<x3:resource-vehicle-range xmlns:x3="http://nextcloud.com/ns"/>
92+
<x3:resource-vehicle-seating-capacity xmlns:x3="http://nextcloud.com/ns"/>
93+
<x3:resource-contact-person xmlns:x3="http://nextcloud.com/ns"/>
94+
<x3:resource-contact-person-vcard xmlns:x3="http://nextcloud.com/ns"/>
95+
<x3:room-type xmlns:x3="http://nextcloud.com/ns"/>
96+
<x3:room-seating-capacity xmlns:x3="http://nextcloud.com/ns"/>
97+
<x3:room-building-address xmlns:x3="http://nextcloud.com/ns"/>
98+
<x3:room-building-story xmlns:x3="http://nextcloud.com/ns"/>
99+
<x3:room-building-room-number xmlns:x3="http://nextcloud.com/ns"/>
100+
<x3:room-features xmlns:x3="http://nextcloud.com/ns"/>
101+
</x0:prop>
102+
<x0:apply-to-principal-collection-set/>
103+
</x0:principal-property-search>
104+
',
105+
'auth' => [
106+
$user,
107+
$password,
108+
],
109+
'headers' => [
110+
'Content-Type' => 'application/xml; charset=UTF-8',
111+
'Depth' => '0',
112+
],
113+
]
114+
);
115+
}
116+
117+
/**
118+
* @Then The search HTTP status code should be :code
119+
* @param string $code
120+
* @throws \Exception
121+
*/
122+
public function theHttpStatusCodeShouldBe(string $code): void {
123+
if ((int)$code !== $this->response->getStatusCode()) {
124+
throw new \Exception('Expected ' . (int)$code . ' got ' . $this->response->getStatusCode());
125+
}
126+
}
127+
128+
/**
129+
* @Then The search response should contain :needle
130+
* @param string $needle
131+
* @throws \Exception
132+
*/
133+
public function theResponseShouldContain(string $needle): void {
134+
$body = $this->response->getBody()->getContents();
135+
136+
if (str_contains($body, $needle) === false) {
137+
throw new \Exception('Response does not contain "' . $needle . '"');
138+
}
139+
}
140+
}

build/integration/features/provisioning-v1.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ Feature: provisioning
452452
Then groups returned are
453453
| España |
454454
| admin |
455+
| hidden_group |
455456
| new-group |
456457

457458
Scenario: create a subadmin

0 commit comments

Comments
 (0)