Skip to content

Commit e9c95a0

Browse files
Merge pull request #61293 from nextcloud/fix/federation-settings-calendar
fix(caldav): respect federation settings
2 parents ede0284 + 6280efc commit e9c95a0

6 files changed

Lines changed: 218 additions & 5 deletions

File tree

apps/dav/lib/CalDAV/Federation/CalendarFederationConfig.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,36 @@
99

1010
namespace OCA\DAV\CalDAV\Federation;
1111

12-
use OCP\AppFramework\Services\IAppConfig;
12+
use OCP\IAppConfig;
1313

1414
class CalendarFederationConfig {
1515
public function __construct(
1616
private readonly IAppConfig $appConfig,
17+
private \OCP\GlobalScale\IConfig $gsConfig,
1718
) {
1819
}
1920

2021
public function isFederationEnabled(): bool {
21-
return $this->appConfig->getAppValueBool('enableCalendarFederation', true);
22+
return $this->appConfig->getValueBool('dav', 'enableCalendarFederation', true);
23+
}
24+
25+
/**
26+
* Check if users are allowed to create federated shares
27+
*/
28+
public function isOutgoingServer2serverShareEnabled(): bool {
29+
if ($this->gsConfig->onlyInternalFederation()) {
30+
return false;
31+
}
32+
return $this->appConfig->getValueBool('files_sharing', 'outgoing_server2server_share_enabled', true);
33+
}
34+
35+
/**
36+
* Check if users are allowed to receive federated shares
37+
*/
38+
public function isIncomingServer2serverShareEnabled(): bool {
39+
if ($this->gsConfig->onlyInternalFederation()) {
40+
return false;
41+
}
42+
return $this->appConfig->getValueBool('files_sharing', 'incoming_server2server_share_enabled', true);
2243
}
2344
}

apps/dav/lib/CalDAV/Federation/CalendarFederationProvider.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ public function shareReceived(ICloudFederationShare $share): string {
5555
);
5656
}
5757

58+
if (!$this->calendarFederationConfig->isIncomingServer2serverShareEnabled()) {
59+
$this->logger->debug('Received a federated calendar share which is not allowed on this instance');
60+
throw new ProviderCouldNotAddShareException(
61+
'Instance does not support receiving federated calendar shares',
62+
'',
63+
Http::STATUS_SERVICE_UNAVAILABLE,
64+
);
65+
}
66+
5867
if (!in_array($share->getShareType(), $this->getSupportedShareTypes(), true)) {
5968
$this->logger->debug('Received a federation invite for invalid share type');
6069
throw new ProviderCouldNotAddShareException(

apps/dav/lib/CalDAV/Federation/FederationSharingService.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public function __construct(
3434
private readonly LoggerInterface $logger,
3535
private readonly ISecureRandom $random,
3636
private readonly SharingMapper $sharingMapper,
37+
private readonly CalendarFederationConfig $config,
3738
) {
3839
}
3940

@@ -70,6 +71,14 @@ private function decodeRemoteUserPrincipal(string $principal): ?string {
7071
public function shareWith(IShareable $shareable, string $principal, int $access): void {
7172
$baseError = 'Failed to create federated calendar share: ';
7273

74+
if (!$this->config->isOutgoingServer2serverShareEnabled()) {
75+
$this->logger->error('cannot share with remote user because federated sharing is disabled on this instance', [
76+
'shareable' => $shareable->getName(),
77+
'encodedShareWith' => $principal,
78+
]);
79+
return;
80+
}
81+
7382
// 1. Validate share data
7483
$shareWith = $this->decodeRemoteUserPrincipal($principal);
7584
if ($shareWith === null) {

apps/dav/tests/unit/CalDAV/Federation/CalendarFederationConfigTest.php

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
namespace OCA\DAV\Tests\unit\CalDAV\Federation;
1111

1212
use OCA\DAV\CalDAV\Federation\CalendarFederationConfig;
13-
use OCP\AppFramework\Services\IAppConfig;
13+
use OCP\GlobalScale\IConfig;
14+
use OCP\IAppConfig;
1415
use PHPUnit\Framework\Attributes\DataProvider;
1516
use PHPUnit\Framework\MockObject\MockObject;
1617
use Test\TestCase;
@@ -19,14 +20,17 @@ class CalendarFederationConfigTest extends TestCase {
1920
private CalendarFederationConfig $config;
2021

2122
private IAppConfig&MockObject $appConfig;
23+
private IConfig&MockObject $gsConfig;
2224

2325
protected function setUp(): void {
2426
parent::setUp();
2527

2628
$this->appConfig = $this->createMock(IAppConfig::class);
29+
$this->gsConfig = $this->createMock(IConfig::class);
2730

2831
$this->config = new CalendarFederationConfig(
2932
$this->appConfig,
33+
$this->gsConfig,
3034
);
3135
}
3236

@@ -40,10 +44,74 @@ public static function provideIsFederationEnabledData(): array {
4044
#[DataProvider(methodName: 'provideIsFederationEnabledData')]
4145
public function testIsFederationEnabled(bool $configValue): void {
4246
$this->appConfig->expects(self::once())
43-
->method('getAppValueBool')
44-
->with('enableCalendarFederation', true)
47+
->method('getValueBool')
48+
->with('dav', 'enableCalendarFederation', true)
4549
->willReturn($configValue);
4650

4751
$this->assertEquals($configValue, $this->config->isFederationEnabled());
4852
}
53+
54+
public static function provideIsOutgoingServer2serverShareEnabledData(): array {
55+
return [
56+
[false, false, false],
57+
[false, true, true],
58+
[true, false, false],
59+
[true, false, false],
60+
];
61+
}
62+
63+
#[DataProvider(methodName: 'provideIsOutgoingServer2serverShareEnabledData')]
64+
public function testIsOutgoingServer2serverShareEnabled(
65+
bool $globalScaleEnabled,
66+
bool $expected,
67+
bool $configValue,
68+
): void {
69+
$this->gsConfig->expects(self::once())
70+
->method('onlyInternalFederation')
71+
->willReturn($globalScaleEnabled);
72+
73+
if (!$globalScaleEnabled) {
74+
$this->appConfig->expects(self::once())
75+
->method('getValueBool')
76+
->with('files_sharing', 'outgoing_server2server_share_enabled', true)
77+
->willReturn($configValue);
78+
} else {
79+
$this->appConfig->expects(self::never())
80+
->method('getValueBool');
81+
}
82+
83+
$this->assertEquals($expected, $this->config->isOutgoingServer2serverShareEnabled());
84+
}
85+
86+
public static function provideIsIncomingServer2serverShareEnabledData(): array {
87+
return [
88+
[false, false, false],
89+
[false, true, true],
90+
[true, false, false],
91+
[true, false, true],
92+
];
93+
}
94+
95+
#[DataProvider(methodName: 'provideIsIncomingServer2serverShareEnabledData')]
96+
public function testIsIncomingServer2serverShareEnabled(
97+
bool $globalScaleEnabled,
98+
bool $expected,
99+
bool $configValue,
100+
): void {
101+
$this->gsConfig->expects(self::once())
102+
->method('onlyInternalFederation')
103+
->willReturn($globalScaleEnabled);
104+
105+
if (!$globalScaleEnabled) {
106+
$this->appConfig->expects(self::once())
107+
->method('getValueBool')
108+
->with('files_sharing', 'incoming_server2server_share_enabled', true)
109+
->willReturn($configValue);
110+
} else {
111+
$this->appConfig->expects(self::never())
112+
->method('getValueBool');
113+
}
114+
115+
$this->assertEquals($expected, $this->config->isIncomingServer2serverShareEnabled());
116+
}
49117
}

apps/dav/tests/unit/CalDAV/Federation/CalendarFederationProviderTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ public function testShareReceived(): void {
9191
->method('isFederationEnabled')
9292
->willReturn(true);
9393

94+
$this->calendarFederationConfig->expects(self::once())
95+
->method('isIncomingServer2serverShareEnabled')
96+
->willReturn(true);
97+
9498
$this->federatedCalendarMapper->expects(self::once())
9599
->method('findByUri')
96100
->with(
@@ -150,6 +154,10 @@ public function testShareReceivedWithExistingCalendar(): void {
150154
->method('isFederationEnabled')
151155
->willReturn(true);
152156

157+
$this->calendarFederationConfig->expects(self::once())
158+
->method('isIncomingServer2serverShareEnabled')
159+
->willReturn(true);
160+
153161
$existingCalendar = new FederatedCalendarEntity();
154162
$existingCalendar->setId(10);
155163
$existingCalendar->setPrincipaluri('principals/users/sharee1');
@@ -204,6 +212,10 @@ public function testShareReceivedWithInvalidProtocolVersion(): void {
204212
->method('isFederationEnabled')
205213
->willReturn(true);
206214

215+
$this->calendarFederationConfig->expects(self::once())
216+
->method('isIncomingServer2serverShareEnabled')
217+
->willReturn(true);
218+
207219
$this->federatedCalendarMapper->expects(self::never())
208220
->method('insert');
209221
$this->jobList->expects(self::never())
@@ -232,6 +244,10 @@ public function testShareReceivedWithoutProtocolVersion(): void {
232244
->method('isFederationEnabled')
233245
->willReturn(true);
234246

247+
$this->calendarFederationConfig->expects(self::once())
248+
->method('isIncomingServer2serverShareEnabled')
249+
->willReturn(true);
250+
235251
$this->federatedCalendarMapper->expects(self::never())
236252
->method('insert');
237253
$this->jobList->expects(self::never())
@@ -261,6 +277,30 @@ public function testShareReceivedWithDisabledConfig(): void {
261277
$this->calendarFederationProvider->shareReceived($share);
262278
}
263279

280+
public function testShareReceivedWithIncomingServer2serverShareDisabled(): void {
281+
$share = $this->createMock(ICloudFederationShare::class);
282+
$share->method('getShareType')
283+
->willReturn('user');
284+
285+
$this->calendarFederationConfig->expects(self::once())
286+
->method('isFederationEnabled')
287+
->willReturn(true);
288+
289+
$this->calendarFederationConfig->expects(self::once())
290+
->method('isIncomingServer2serverShareEnabled')
291+
->willReturn(false);
292+
293+
$this->federatedCalendarMapper->expects(self::never())
294+
->method('insert');
295+
$this->jobList->expects(self::never())
296+
->method('add');
297+
298+
$this->expectException(ProviderCouldNotAddShareException::class);
299+
$this->expectExceptionMessage('Instance does not support receiving federated calendar shares');
300+
$this->expectExceptionCode(503);
301+
$this->calendarFederationProvider->shareReceived($share);
302+
}
303+
264304
public function testShareReceivedWithUnsupportedShareType(): void {
265305
$share = $this->createMock(ICloudFederationShare::class);
266306
$share->method('getShareType')
@@ -270,6 +310,10 @@ public function testShareReceivedWithUnsupportedShareType(): void {
270310
->method('isFederationEnabled')
271311
->willReturn(true);
272312

313+
$this->calendarFederationConfig->expects(self::once())
314+
->method('isIncomingServer2serverShareEnabled')
315+
->willReturn(true);
316+
273317
$this->federatedCalendarMapper->expects(self::never())
274318
->method('insert');
275319
$this->jobList->expects(self::never())
@@ -322,6 +366,10 @@ public function testShareReceivedWithIncompleteProtocolData(array $protocol): vo
322366
->method('isFederationEnabled')
323367
->willReturn(true);
324368

369+
$this->calendarFederationConfig->expects(self::once())
370+
->method('isIncomingServer2serverShareEnabled')
371+
->willReturn(true);
372+
325373
$this->federatedCalendarMapper->expects(self::never())
326374
->method('insert');
327375
$this->jobList->expects(self::never())
@@ -359,6 +407,10 @@ public function testShareReceivedWithReadWriteAccess(): void {
359407
->method('isFederationEnabled')
360408
->willReturn(true);
361409

410+
$this->calendarFederationConfig->expects(self::once())
411+
->method('isIncomingServer2serverShareEnabled')
412+
->willReturn(true);
413+
362414
$this->federatedCalendarMapper->expects(self::once())
363415
->method('findByUri')
364416
->with(
@@ -418,6 +470,10 @@ public function testShareReceivedWithUnsupportedAccess(): void {
418470
->method('isFederationEnabled')
419471
->willReturn(true);
420472

473+
$this->calendarFederationConfig->expects(self::once())
474+
->method('isIncomingServer2serverShareEnabled')
475+
->willReturn(true);
476+
421477
$this->federatedCalendarMapper->expects(self::never())
422478
->method('insert');
423479
$this->jobList->expects(self::never())

0 commit comments

Comments
 (0)