From 1b126eb4004f931f0c2e041320f4c28f737bf4e4 Mon Sep 17 00:00:00 2001 From: Hamza Date: Fri, 13 Mar 2026 17:47:09 +0100 Subject: [PATCH 1/2] fix: add ACLs for calender delegation Signed-off-by: Hamza --- .../composer/composer/autoload_classmap.php | 2 + .../dav/composer/composer/autoload_static.php | 2 + apps/dav/lib/CalDAV/Principal/ProxyRead.php | 23 +++++++++++ apps/dav/lib/CalDAV/Principal/ProxyWrite.php | 23 +++++++++++ apps/dav/lib/CalDAV/Principal/User.php | 40 +++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 apps/dav/lib/CalDAV/Principal/ProxyRead.php create mode 100644 apps/dav/lib/CalDAV/Principal/ProxyWrite.php diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php index 13a7716920f99..9ab04c8ae8053 100644 --- a/apps/dav/composer/composer/autoload_classmap.php +++ b/apps/dav/composer/composer/autoload_classmap.php @@ -96,6 +96,8 @@ 'OCA\\DAV\\CalDAV\\Outbox' => $baseDir . '/../lib/CalDAV/Outbox.php', 'OCA\\DAV\\CalDAV\\Plugin' => $baseDir . '/../lib/CalDAV/Plugin.php', 'OCA\\DAV\\CalDAV\\Principal\\Collection' => $baseDir . '/../lib/CalDAV/Principal/Collection.php', + 'OCA\\DAV\\CalDAV\\Principal\\ProxyRead' => $baseDir . '/../lib/CalDAV/Principal/ProxyRead.php', + 'OCA\\DAV\\CalDAV\\Principal\\ProxyWrite' => $baseDir . '/../lib/CalDAV/Principal/ProxyWrite.php', 'OCA\\DAV\\CalDAV\\Principal\\User' => $baseDir . '/../lib/CalDAV/Principal/User.php', 'OCA\\DAV\\CalDAV\\Proxy\\Proxy' => $baseDir . '/../lib/CalDAV/Proxy/Proxy.php', 'OCA\\DAV\\CalDAV\\Proxy\\ProxyMapper' => $baseDir . '/../lib/CalDAV/Proxy/ProxyMapper.php', diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php index d51024d7adde0..8f09f754b3cd0 100644 --- a/apps/dav/composer/composer/autoload_static.php +++ b/apps/dav/composer/composer/autoload_static.php @@ -111,6 +111,8 @@ class ComposerStaticInitDAV 'OCA\\DAV\\CalDAV\\Outbox' => __DIR__ . '/..' . '/../lib/CalDAV/Outbox.php', 'OCA\\DAV\\CalDAV\\Plugin' => __DIR__ . '/..' . '/../lib/CalDAV/Plugin.php', 'OCA\\DAV\\CalDAV\\Principal\\Collection' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/Collection.php', + 'OCA\\DAV\\CalDAV\\Principal\\ProxyRead' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/ProxyRead.php', + 'OCA\\DAV\\CalDAV\\Principal\\ProxyWrite' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/ProxyWrite.php', 'OCA\\DAV\\CalDAV\\Principal\\User' => __DIR__ . '/..' . '/../lib/CalDAV/Principal/User.php', 'OCA\\DAV\\CalDAV\\Proxy\\Proxy' => __DIR__ . '/..' . '/../lib/CalDAV/Proxy/Proxy.php', 'OCA\\DAV\\CalDAV\\Proxy\\ProxyMapper' => __DIR__ . '/..' . '/../lib/CalDAV/Proxy/ProxyMapper.php', diff --git a/apps/dav/lib/CalDAV/Principal/ProxyRead.php b/apps/dav/lib/CalDAV/Principal/ProxyRead.php new file mode 100644 index 0000000000000..80349464a22a3 --- /dev/null +++ b/apps/dav/lib/CalDAV/Principal/ProxyRead.php @@ -0,0 +1,23 @@ +principalInfo['uri']; + } +} diff --git a/apps/dav/lib/CalDAV/Principal/ProxyWrite.php b/apps/dav/lib/CalDAV/Principal/ProxyWrite.php new file mode 100644 index 0000000000000..0d9d2dd9947f2 --- /dev/null +++ b/apps/dav/lib/CalDAV/Principal/ProxyWrite.php @@ -0,0 +1,23 @@ +principalInfo['uri']; + } +} diff --git a/apps/dav/lib/CalDAV/Principal/User.php b/apps/dav/lib/CalDAV/Principal/User.php index c7b84e6ce4c7f..f81ffbfbdf139 100644 --- a/apps/dav/lib/CalDAV/Principal/User.php +++ b/apps/dav/lib/CalDAV/Principal/User.php @@ -36,4 +36,44 @@ public function getACL() { ]; return $acl; } + + /** + * Returns a specific child node, referenced by its name. + * + * @param string $name + * + * @return \Sabre\DAV\INode + */ + public function getChild($name) { + $principal = $this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name); + if (!$principal) { + throw new \Sabre\DAV\Exception\NotFound("Node with name $name was not found"); + } + if ($name === 'calendar-proxy-read') { + return new ProxyRead($this->principalBackend, $this->principalProperties); + } + + if ($name === 'calendar-proxy-write') { + return new ProxyWrite($this->principalBackend, $this->principalProperties); + } + + throw new \Sabre\DAV\Exception\NotFound("Node with name $name was not found"); + } + + /** + * Returns an array with all the child nodes. + * + * @return \Sabre\DAV\INode[] + */ + public function getChildren() { + $r = []; + if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) { + $r[] = new ProxyRead($this->principalBackend, $this->principalProperties); + } + if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-write')) { + $r[] = new ProxyWrite($this->principalBackend, $this->principalProperties); + } + + return $r; + } } From d9426a2b2201090e3f39787e9a45fcb9af3089b5 Mon Sep 17 00:00:00 2001 From: Hamza Date: Fri, 17 Apr 2026 14:16:06 +0200 Subject: [PATCH 2/2] test(integration): write integration tests for calendar delegation Signed-off-by: Hamza --- .../dav_features/caldav-delegation.feature | 9 +++++- .../features/bootstrap/CalDavContext.php | 32 +++++++++++-------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/build/integration/dav_features/caldav-delegation.feature b/build/integration/dav_features/caldav-delegation.feature index d4cc781f320e6..33cd928db7f98 100644 --- a/build/integration/dav_features/caldav-delegation.feature +++ b/build/integration/dav_features/caldav-delegation.feature @@ -20,4 +20,11 @@ Feature: calendar delegation When "admin" updates property "{DAV:}group-member-set" to href "/remote.php/dav/principals/users/user0" of principal "users/admin/calendar-proxy-write" on the endpoint "/remote.php/dav/principals/" Then The CalDAV response should be multi status And The CalDAV response should contain an href "/remote.php/dav/principals/users/admin/calendar-proxy-write" - And The CalDAV response should contain a property "{DAV:}group-member-set" \ No newline at end of file + And The CalDAV response should contain a property "{DAV:}group-member-set" + + Scenario: Admin cannot grant User1 access to User0's calendar account + Given user "admin" exists + And user "user0" exists + And user "user1" exists + When "admin" updates property "{DAV:}group-member-set" to href "/remote.php/dav/principals/users/user1" of principal "users/user0/calendar-proxy-write" on the endpoint "/remote.php/dav/principals/" + Then The CalDAV HTTP status code should be "404" \ No newline at end of file diff --git a/build/integration/features/bootstrap/CalDavContext.php b/build/integration/features/bootstrap/CalDavContext.php index 22951b3e454d2..3d99040075162 100644 --- a/build/integration/features/bootstrap/CalDavContext.php +++ b/build/integration/features/bootstrap/CalDavContext.php @@ -408,19 +408,23 @@ public function updatesHrefPropertyOfPrincipal( $xml = new \Sabre\Xml\Service(); $body = $xml->write('{DAV:}propertyupdate', $propPatch, '/'); - $this->response = $this->client->request( - 'PROPPATCH', - $davUrl, - [ - 'headers' => [ - 'Content-Type' => 'application/xml; charset=UTF-8', - ], - 'body' => $body, - 'auth' => [ - $user, - $password, - ], - ] - ); + try { + $this->response = $this->client->request( + 'PROPPATCH', + $davUrl, + [ + 'headers' => [ + 'Content-Type' => 'application/xml; charset=UTF-8', + ], + 'body' => $body, + 'auth' => [ + $user, + $password, + ], + ] + ); + } catch (\GuzzleHttp\Exception\ClientException $e) { + $this->response = $e->getResponse(); + } } }