use principaluri instead of userid, allowing to add delegates for rooms and things

Signed-off-by: Georg Ehrke <developer@georgehrke.com>

!fixup add owner_id and proxy_id as db index, since we use it for querying

Signed-off-by: Georg Ehrke <developer@georgehrke.com>

!fixup don't add ACL for each individual proxy, just use calendar-proxy groups

Signed-off-by: Georg Ehrke <developer@georgehrke.com>

!fixup allow delegation of resources / rooms

Signed-off-by: Georg Ehrke <developer@georgehrke.com>

!fixup fix addIndex call in migration

Signed-off-by: Georg Ehrke <developer@georgehrke.com>

!fixup fix remaining constructor calls of Principal

Signed-off-by: Georg Ehrke <developer@georgehrke.com>

!fixup minor fixes and unit tests

Signed-off-by: Georg Ehrke <developer@georgehrke.com>
This commit is contained in:
Georg Ehrke 2019-08-14 13:38:11 +02:00
parent 3d86537dc9
commit 63d584afb5
No known key found for this signature in database
GPG Key ID: 9D98FD9380A1CB43
21 changed files with 650 additions and 228 deletions

View File

@ -46,8 +46,8 @@ $principalBackend = new Principal(
\OC::$server->getGroupManager(), \OC::$server->getGroupManager(),
\OC::$server->getShareManager(), \OC::$server->getShareManager(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getConfig(),
\OC::$server->getAppManager(), \OC::$server->getAppManager(),
\OC::$server->query(\OCA\DAV\CalDAV\Proxy\ProxyMapper::class),
'principals/' 'principals/'
); );
$db = \OC::$server->getDatabaseConnection(); $db = \OC::$server->getDatabaseConnection();

View File

@ -47,8 +47,8 @@ $principalBackend = new Principal(
\OC::$server->getGroupManager(), \OC::$server->getGroupManager(),
\OC::$server->getShareManager(), \OC::$server->getShareManager(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getConfig(),
\OC::$server->getAppManager(), \OC::$server->getAppManager(),
\OC::$server->query(\OCA\DAV\CalDAV\Proxy\ProxyMapper::class),
'principals/' 'principals/'
); );
$db = \OC::$server->getDatabaseConnection(); $db = \OC::$server->getDatabaseConnection();

View File

@ -196,6 +196,7 @@ return array(
'OCA\\DAV\\SystemTag\\SystemTagsObjectMappingCollection' => $baseDir . '/../lib/SystemTag/SystemTagsObjectMappingCollection.php', 'OCA\\DAV\\SystemTag\\SystemTagsObjectMappingCollection' => $baseDir . '/../lib/SystemTag/SystemTagsObjectMappingCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsObjectTypeCollection' => $baseDir . '/../lib/SystemTag/SystemTagsObjectTypeCollection.php', 'OCA\\DAV\\SystemTag\\SystemTagsObjectTypeCollection' => $baseDir . '/../lib/SystemTag/SystemTagsObjectTypeCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsRelationsCollection' => $baseDir . '/../lib/SystemTag/SystemTagsRelationsCollection.php', 'OCA\\DAV\\SystemTag\\SystemTagsRelationsCollection' => $baseDir . '/../lib/SystemTag/SystemTagsRelationsCollection.php',
'OCA\\DAV\\Traits\\PrincipalProxyTrait' => $baseDir . '/../lib/Traits/PrincipalProxyTrait.php',
'OCA\\DAV\\Upload\\AssemblyStream' => $baseDir . '/../lib/Upload/AssemblyStream.php', 'OCA\\DAV\\Upload\\AssemblyStream' => $baseDir . '/../lib/Upload/AssemblyStream.php',
'OCA\\DAV\\Upload\\ChunkingPlugin' => $baseDir . '/../lib/Upload/ChunkingPlugin.php', 'OCA\\DAV\\Upload\\ChunkingPlugin' => $baseDir . '/../lib/Upload/ChunkingPlugin.php',
'OCA\\DAV\\Upload\\CleanupService' => $baseDir . '/../lib/Upload/CleanupService.php', 'OCA\\DAV\\Upload\\CleanupService' => $baseDir . '/../lib/Upload/CleanupService.php',

View File

@ -211,6 +211,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\SystemTag\\SystemTagsObjectMappingCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsObjectMappingCollection.php', 'OCA\\DAV\\SystemTag\\SystemTagsObjectMappingCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsObjectMappingCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsObjectTypeCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsObjectTypeCollection.php', 'OCA\\DAV\\SystemTag\\SystemTagsObjectTypeCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsObjectTypeCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsRelationsCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsRelationsCollection.php', 'OCA\\DAV\\SystemTag\\SystemTagsRelationsCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsRelationsCollection.php',
'OCA\\DAV\\Traits\\PrincipalProxyTrait' => __DIR__ . '/..' . '/../lib/Traits/PrincipalProxyTrait.php',
'OCA\\DAV\\Upload\\AssemblyStream' => __DIR__ . '/..' . '/../lib/Upload/AssemblyStream.php', 'OCA\\DAV\\Upload\\AssemblyStream' => __DIR__ . '/..' . '/../lib/Upload/AssemblyStream.php',
'OCA\\DAV\\Upload\\ChunkingPlugin' => __DIR__ . '/..' . '/../lib/Upload/ChunkingPlugin.php', 'OCA\\DAV\\Upload\\ChunkingPlugin' => __DIR__ . '/..' . '/../lib/Upload/ChunkingPlugin.php',
'OCA\\DAV\\Upload\\CleanupService' => __DIR__ . '/..' . '/../lib/Upload/CleanupService.php', 'OCA\\DAV\\Upload\\CleanupService' => __DIR__ . '/..' . '/../lib/Upload/CleanupService.php',

View File

@ -47,9 +47,14 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
/** @var IConfig */ /** @var IConfig */
private $config; private $config;
/** @var ProxyMapper */ /**
private $proxyMapper; * Calendar constructor.
*
* @param BackendInterface $caldavBackend
* @param $calendarInfo
* @param IL10N $l10n
* @param IConfig $config
*/
public function __construct(BackendInterface $caldavBackend, $calendarInfo, IL10N $l10n, IConfig $config) { public function __construct(BackendInterface $caldavBackend, $calendarInfo, IL10N $l10n, IConfig $config) {
parent::__construct($caldavBackend, $calendarInfo); parent::__construct($caldavBackend, $calendarInfo);
@ -62,9 +67,6 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
} }
$this->config = $config; $this->config = $config;
// TODO: proper DI
$this->proxyMapper = \OC::$server->query(ProxyMapper::class);
} }
/** /**
@ -126,29 +128,60 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
return $this->calendarInfo['principaluri']; return $this->calendarInfo['principaluri'];
} }
/**
* @return array
*/
public function getACL() { public function getACL() {
$acl = [ $acl = [
[ [
'privilege' => '{DAV:}read', 'privilege' => '{DAV:}read',
'principal' => $this->getOwner(), 'principal' => $this->getOwner(),
'protected' => true, 'protected' => true,
]]; ],
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner() . '/calendar-proxy-write',
'protected' => true,
],
[
'privilege' => '{DAV:}read',
'principal' => $this->getOwner() . '/calendar-proxy-read',
'protected' => true,
],
];
if ($this->getName() !== BirthdayService::BIRTHDAY_CALENDAR_URI) { if ($this->getName() !== BirthdayService::BIRTHDAY_CALENDAR_URI) {
$acl[] = [ $acl[] = [
'privilege' => '{DAV:}write', 'privilege' => '{DAV:}write',
'principal' => $this->getOwner(), 'principal' => $this->getOwner(),
'protected' => true, 'protected' => true,
]; ];
$acl[] = [
'privilege' => '{DAV:}write',
'principal' => $this->getOwner() . '/calendar-proxy-write',
'protected' => true,
];
} else { } else {
$acl[] = [ $acl[] = [
'privilege' => '{DAV:}write-properties', 'privilege' => '{DAV:}write-properties',
'principal' => $this->getOwner(), 'principal' => $this->getOwner(),
'protected' => true, 'protected' => true,
]; ];
$acl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => $this->getOwner() . '/calendar-proxy-write',
'protected' => true,
];
} }
$acl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => $this->getOwner() . '/calendar-proxy-read',
'protected' => true,
];
if (!$this->isShared()) { if (!$this->isShared()) {
return $this->addProxies($acl); return $acl;
} }
if ($this->getOwner() !== parent::getOwner()) { if ($this->getOwner() !== parent::getOwner()) {
@ -180,38 +213,16 @@ class Calendar extends \Sabre\CalDAV\Calendar implements IShareable {
} }
$acl = $this->caldavBackend->applyShareAcl($this->getResourceId(), $acl); $acl = $this->caldavBackend->applyShareAcl($this->getResourceId(), $acl);
$allowedPrincipals = [$this->getOwner(), parent::getOwner(), 'principals/system/public']; $allowedPrincipals = [
$acl = array_filter($acl, function($rule) use ($allowedPrincipals) { $this->getOwner(),
$this->getOwner(). '/calendar-proxy-read',
$this->getOwner(). '/calendar-proxy-write',
parent::getOwner(),
'principals/system/public'
];
return array_filter($acl, function($rule) use ($allowedPrincipals) {
return \in_array($rule['principal'], $allowedPrincipals, true); return \in_array($rule['principal'], $allowedPrincipals, true);
}); });
$acl = $this->addProxies($acl);
return $acl;
}
public function addProxies(array $acl): array {
list($prefix, $name) = \Sabre\Uri\split($this->getOwner());
$proxies = $this->proxyMapper->getProxiesOf($name);
foreach ($proxies as $proxy) {
if ($proxy->getPermissions() & ProxyMapper::PERMISSION_READ) {
$acl[] = [
'privilege' => '{DAV:}read',
'principal' => 'principals/users/' . $proxy->getProxyId(),
'protected' => true,
];
}
if ($proxy->getPermissions() & ProxyMapper::PERMISSION_WRITE) {
$acl[] = [
'privilege' => '{DAV:}write',
'principal' => 'principals/users/' . $proxy->getProxyId(),
'protected' => true,
];
}
}
return $acl;
} }
public function getChildACL() { public function getChildACL() {

View File

@ -27,17 +27,27 @@ namespace OCA\DAV\CalDAV\Proxy;
use OCP\AppFramework\Db\QBMapper; use OCP\AppFramework\Db\QBMapper;
use OCP\IDBConnection; use OCP\IDBConnection;
/**
* Class ProxyMapper
*
* @package OCA\DAV\CalDAV\Proxy
*/
class ProxyMapper extends QBMapper { class ProxyMapper extends QBMapper {
const PERMISSION_READ = 1; const PERMISSION_READ = 1;
const PERMISSION_WRITE = 2; const PERMISSION_WRITE = 2;
/**
* ProxyMapper constructor.
*
* @param IDBConnection $db
*/
public function __construct(IDBConnection $db) { public function __construct(IDBConnection $db) {
parent::__construct($db, 'dav_cal_proxy', Proxy::class); parent::__construct($db, 'dav_cal_proxy', Proxy::class);
} }
/** /**
* @param string $proxyId The userId that can act as a proxy for the resulting calendars * @param string $proxyId The principal uri that can act as a proxy for the resulting calendars
* *
* @return Proxy[] * @return Proxy[]
*/ */
@ -52,7 +62,7 @@ class ProxyMapper extends QBMapper {
} }
/** /**
* @param string $ownerId The userId that has the resulting proxies for their calendars * @param string $ownerId The principal uri that has the resulting proxies for their calendars
* *
* @return Proxy[] * @return Proxy[]
*/ */

View File

@ -22,6 +22,8 @@
*/ */
namespace OCA\DAV\CalDAV\ResourceBooking; namespace OCA\DAV\CalDAV\ResourceBooking;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCA\DAV\Traits\PrincipalProxyTrait;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\IGroupManager; use OCP\IGroupManager;
use OCP\ILogger; use OCP\ILogger;
@ -44,6 +46,9 @@ abstract class AbstractPrincipalBackend implements BackendInterface {
/** @var ILogger */ /** @var ILogger */
private $logger; private $logger;
/** @var ProxyMapper */
private $proxyMapper;
/** @var string */ /** @var string */
private $principalPrefix; private $principalPrefix;
@ -72,6 +77,7 @@ abstract class AbstractPrincipalBackend implements BackendInterface {
IUserSession $userSession, IUserSession $userSession,
IGroupManager $groupManager, IGroupManager $groupManager,
ILogger $logger, ILogger $logger,
ProxyMapper $proxyMapper,
string $principalPrefix, string $principalPrefix,
string $dbPrefix, string $dbPrefix,
string $cuType) { string $cuType) {
@ -79,6 +85,7 @@ abstract class AbstractPrincipalBackend implements BackendInterface {
$this->userSession = $userSession; $this->userSession = $userSession;
$this->groupManager = $groupManager; $this->groupManager = $groupManager;
$this->logger = $logger; $this->logger = $logger;
$this->proxyMapper = $proxyMapper;
$this->principalPrefix = $principalPrefix; $this->principalPrefix = $principalPrefix;
$this->dbTableName = 'calendar_' . $dbPrefix . 's'; $this->dbTableName = 'calendar_' . $dbPrefix . 's';
$this->dbMetaDataTableName = $this->dbTableName . '_md'; $this->dbMetaDataTableName = $this->dbTableName . '_md';
@ -86,6 +93,8 @@ abstract class AbstractPrincipalBackend implements BackendInterface {
$this->cuType = $cuType; $this->cuType = $cuType;
} }
use PrincipalProxyTrait;
/** /**
* Returns a list of principals based on a prefix. * Returns a list of principals based on a prefix.
* *
@ -215,39 +224,6 @@ abstract class AbstractPrincipalBackend implements BackendInterface {
return $this->rowToPrincipal($row, $metadata); return $this->rowToPrincipal($row, $metadata);
} }
/**
* Returns the list of members for a group-principal
*
* @param string $principal
* @return string[]
*/
public function getGroupMemberSet($principal) {
return [];
}
/**
* Returns the list of groups a principal is a member of
*
* @param string $principal
* @return array
*/
public function getGroupMembership($principal) {
return [];
}
/**
* Updates the list of group members for a group principal.
*
* The principals should be passed as a list of uri's.
*
* @param string $principal
* @param string[] $members
* @throws Exception
*/
public function setGroupMemberSet($principal, array $members) {
throw new Exception('Setting members of the group is not supported yet');
}
/** /**
* @param string $path * @param string $path
* @param PropPatch $propPatch * @param PropPatch $propPatch

View File

@ -22,24 +22,34 @@
*/ */
namespace OCA\DAV\CalDAV\ResourceBooking; namespace OCA\DAV\CalDAV\ResourceBooking;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\IGroupManager; use OCP\IGroupManager;
use OCP\ILogger; use OCP\ILogger;
use OCP\IUserSession; use OCP\IUserSession;
/**
* Class ResourcePrincipalBackend
*
* @package OCA\DAV\CalDAV\ResourceBooking
*/
class ResourcePrincipalBackend extends AbstractPrincipalBackend { class ResourcePrincipalBackend extends AbstractPrincipalBackend {
/** /**
* ResourcePrincipalBackend constructor.
*
* @param IDBConnection $dbConnection * @param IDBConnection $dbConnection
* @param IUserSession $userSession * @param IUserSession $userSession
* @param IGroupManager $groupManager * @param IGroupManager $groupManager
* @param ILogger $logger * @param ILogger $logger
* @param ProxyMapper $proxyMapper
*/ */
public function __construct(IDBConnection $dbConnection, public function __construct(IDBConnection $dbConnection,
IUserSession $userSession, IUserSession $userSession,
IGroupManager $groupManager, IGroupManager $groupManager,
ILogger $logger) { ILogger $logger,
ProxyMapper $proxyMapper) {
parent::__construct($dbConnection, $userSession, $groupManager, $logger, parent::__construct($dbConnection, $userSession, $groupManager, $logger,
'principals/calendar-resources', 'resource', 'RESOURCE'); $proxyMapper, 'principals/calendar-resources', 'resource', 'RESOURCE');
} }
} }

View File

@ -22,24 +22,34 @@
*/ */
namespace OCA\DAV\CalDAV\ResourceBooking; namespace OCA\DAV\CalDAV\ResourceBooking;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\IGroupManager; use OCP\IGroupManager;
use OCP\ILogger; use OCP\ILogger;
use OCP\IUserSession; use OCP\IUserSession;
/**
* Class RoomPrincipalBackend
*
* @package OCA\DAV\CalDAV\ResourceBooking
*/
class RoomPrincipalBackend extends AbstractPrincipalBackend { class RoomPrincipalBackend extends AbstractPrincipalBackend {
/** /**
* RoomPrincipalBackend constructor.
*
* @param IDBConnection $dbConnection * @param IDBConnection $dbConnection
* @param IUserSession $userSession * @param IUserSession $userSession
* @param IGroupManager $groupManager * @param IGroupManager $groupManager
* @param ILogger $logger * @param ILogger $logger
* @param ProxyMapper $proxyMapper
*/ */
public function __construct(IDBConnection $dbConnection, public function __construct(IDBConnection $dbConnection,
IUserSession $userSession, IUserSession $userSession,
IGroupManager $groupManager, IGroupManager $groupManager,
ILogger $logger) { ILogger $logger,
ProxyMapper $proxyMapper) {
parent::__construct($dbConnection, $userSession, $groupManager, $logger, parent::__construct($dbConnection, $userSession, $groupManager, $logger,
'principals/calendar-rooms', 'room', 'ROOM'); $proxyMapper, 'principals/calendar-rooms', 'room', 'ROOM');
} }
} }

View File

@ -24,6 +24,7 @@
namespace OCA\DAV\Command; namespace OCA\DAV\Command;
use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\Connector\Sabre\Principal;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\IGroupManager; use OCP\IGroupManager;
@ -78,8 +79,8 @@ class CreateCalendar extends Command {
$this->groupManager, $this->groupManager,
\OC::$server->getShareManager(), \OC::$server->getShareManager(),
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getConfig(), \OC::$server->getAppManager(),
\OC::$server->getAppManager() \OC::$server->query(ProxyMapper::class)
); );
$random = \OC::$server->getSecureRandom(); $random = \OC::$server->getSecureRandom();
$logger = \OC::$server->getLogger(); $logger = \OC::$server->getLogger();

View File

@ -37,6 +37,7 @@ namespace OCA\DAV\Connector\Sabre;
use OCA\Circles\Exceptions\CircleDoesNotExistException; use OCA\Circles\Exceptions\CircleDoesNotExistException;
use OCA\DAV\CalDAV\Proxy\Proxy; use OCA\DAV\CalDAV\Proxy\Proxy;
use OCA\DAV\CalDAV\Proxy\ProxyMapper; use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCA\DAV\Traits\PrincipalProxyTrait;
use OCP\App\IAppManager; use OCP\App\IAppManager;
use OCP\AppFramework\QueryException; use OCP\AppFramework\QueryException;
use OCP\IGroup; use OCP\IGroup;
@ -74,9 +75,21 @@ class Principal implements BackendInterface {
/** @var bool */ /** @var bool */
private $hasCircles; private $hasCircles;
/** @var ProxyMapper */ /** @var ProxyMapper */
private $proxyMapper; private $proxyMapper;
/**
* Principal constructor.
*
* @param IUserManager $userManager
* @param IGroupManager $groupManager
* @param IShareManager $shareManager
* @param IUserSession $userSession
* @param IAppManager $appManager
* @param ProxyMapper $proxyMapper
* @param string $principalPrefix
*/
public function __construct(IUserManager $userManager, public function __construct(IUserManager $userManager,
IGroupManager $groupManager, IGroupManager $groupManager,
IShareManager $shareManager, IShareManager $shareManager,
@ -94,6 +107,10 @@ class Principal implements BackendInterface {
$this->proxyMapper = $proxyMapper; $this->proxyMapper = $proxyMapper;
} }
use PrincipalProxyTrait {
getGroupMembership as protected traitGetGroupMembership;
}
/** /**
* Returns a list of principals based on a prefix. * Returns a list of principals based on a prefix.
* *
@ -161,23 +178,6 @@ class Principal implements BackendInterface {
return null; return null;
} }
/**
* Returns the list of members for a group-principal
*
* @param string $principal
* @return string[]
* @throws Exception
*/
public function getGroupMemberSet($principal) {
// TODO: for now the group principal has only one member, the user itself
$principal = $this->getPrincipalByPath($principal);
if (!$principal) {
throw new Exception('Principal not found');
}
return [$principal['uri']];
}
/** /**
* Returns the list of groups a principal is a member of * Returns the list of groups a principal is a member of
* *
@ -189,99 +189,30 @@ class Principal implements BackendInterface {
public function getGroupMembership($principal, $needGroups = false) { public function getGroupMembership($principal, $needGroups = false) {
list($prefix, $name) = \Sabre\Uri\split($principal); list($prefix, $name) = \Sabre\Uri\split($principal);
if ($prefix === $this->principalPrefix) { if ($prefix !== $this->principalPrefix) {
$user = $this->userManager->get($name); return [];
if (!$user) {
throw new Exception('Principal not found');
}
if ($this->hasGroups || $needGroups) {
$groups = $this->groupManager->getUserGroups($user);
$groups = array_map(function($group) {
/** @var IGroup $group */
return 'principals/groups/' . urlencode($group->getGID());
}, $groups);
$proxies = $this->proxyMapper->getProxiesFor($user->getUID());
foreach ($proxies as $proxy) {
if ($proxy->getPermissions() & ProxyMapper::PERMISSION_READ) {
$groups[] = 'principals/users/' . $proxy->getOwnerId() . '/calendar-proxy-read';
}
if ($proxy->getPermissions() & ProxyMapper::PERMISSION_WRITE) {
$groups[] = 'principals/users/' . $proxy->getOwnerId() . '/calendar-proxy-write';
}
}
return $groups;
}
}
return [];
}
/**
* Updates the list of group members for a group principal.
*
* The principals should be passed as a list of uri's.
*
* @param string $principal
* @param string[] $members
* @throws Exception
*/
public function setGroupMemberSet($principal, array $members) {
list($prefix, $target) = \Sabre\Uri\split($principal);
if ($target !== 'calendar-proxy-write' && $target !== 'calendar-proxy-read') {
throw new Exception('Setting members of the group is not supported yet');
} }
$permission = ProxyMapper::PERMISSION_READ; $user = $this->userManager->get($name);
if ($target === 'calendar-proxy-write') { if (!$user) {
$permission |= ProxyMapper::PERMISSION_WRITE; throw new Exception('Principal not found');
} }
list($prefix, $owner) = \Sabre\Uri\split($prefix); $groups = [];
$proxies = $this->proxyMapper->getProxiesOf($owner);
foreach ($members as $member) { if ($this->hasGroups || $needGroups) {
list($prefix, $name) = \Sabre\Uri\split($member); $userGroups = $this->groupManager->getUserGroups($user);
foreach($userGroups as $userGroup) {
if ($prefix !== $this->principalPrefix) { $groups[] = 'principals/groups/' . urlencode($userGroup->getGID());
throw new Exception('Invalid member group prefix: ' . $prefix);
}
$user = $this->userManager->get($name);
if ($user === null) {
throw new Exception('Invalid member: ' . $name);
}
$found = false;
foreach ($proxies as $proxy) {
if ($proxy->getProxyId() === $user->getUID()) {
$found = true;
$proxy->setPermissions($proxy->getPermissions() | $permission);
$this->proxyMapper->update($proxy);
$proxies = array_filter($proxies, function(Proxy $p) use ($proxy) {
return $p->getId() !== $proxy->getId();
});
break;
}
}
if ($found === false) {
$proxy = new Proxy();
$proxy->setOwnerId($owner);
$proxy->setProxyId($user->getUID());
$proxy->setPermissions($permission);
$this->proxyMapper->insert($proxy);
} }
} }
// Delete all remaining proxies $groups = array_unique(array_merge(
foreach ($proxies as $proxy) { $groups,
$this->proxyMapper->delete($proxy); $this->traitGetGroupMembership($principal, $needGroups)
} ));
return $groups;
} }
/** /**
@ -552,5 +483,4 @@ class Principal implements BackendInterface {
return []; return [];
} }
} }

View File

@ -47,6 +47,8 @@ class Version1011Date20190806104428 extends SimpleMigrationStep {
$table->setPrimaryKey(['id']); $table->setPrimaryKey(['id']);
$table->addUniqueIndex(['owner_id', 'proxy_id', 'permissions'], 'dav_cal_proxy_uidx'); $table->addUniqueIndex(['owner_id', 'proxy_id', 'permissions'], 'dav_cal_proxy_uidx');
$table->addIndex(['owner_id'], 'dav_cal_proxy_ioid');
$table->addIndex(['proxy_id'], 'dav_cal_proxy_ipid');
return $schema; return $schema;
} }

View File

@ -54,17 +54,19 @@ class RootCollection extends SimpleCollection {
$shareManager = \OC::$server->getShareManager(); $shareManager = \OC::$server->getShareManager();
$db = \OC::$server->getDatabaseConnection(); $db = \OC::$server->getDatabaseConnection();
$dispatcher = \OC::$server->getEventDispatcher(); $dispatcher = \OC::$server->getEventDispatcher();
$proxyMapper = \OC::$server->query(ProxyMapper::class);
$userPrincipalBackend = new Principal( $userPrincipalBackend = new Principal(
$userManager, $userManager,
$groupManager, $groupManager,
$shareManager, $shareManager,
\OC::$server->getUserSession(), \OC::$server->getUserSession(),
\OC::$server->getAppManager(), \OC::$server->getAppManager(),
\OC::$server->query(ProxyMapper::class) $proxyMapper
); );
$groupPrincipalBackend = new GroupPrincipalBackend($groupManager, $userSession, $shareManager, $l10n); $groupPrincipalBackend = new GroupPrincipalBackend($groupManager, $userSession, $shareManager, $l10n);
$calendarResourcePrincipalBackend = new ResourcePrincipalBackend($db, $userSession, $groupManager, $logger); $calendarResourcePrincipalBackend = new ResourcePrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper);
$calendarRoomPrincipalBackend = new RoomPrincipalBackend($db, $userSession, $groupManager, $logger); $calendarRoomPrincipalBackend = new RoomPrincipalBackend($db, $userSession, $groupManager, $logger, $proxyMapper);
// as soon as debug mode is enabled we allow listing of principals // as soon as debug mode is enabled we allow listing of principals
$disableListing = !$config->getSystemValue('debug', false); $disableListing = !$config->getSystemValue('debug', false);

View File

@ -0,0 +1,223 @@
<?php
/**
* @copyright 2019, Georg Ehrke <oc.list@georgehrke.com>
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\Traits;
use OCA\DAV\CalDAV\Proxy\Proxy;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use Sabre\DAV\Exception;
/**
* Trait PrincipalTrait
*
* @package OCA\DAV\Traits
*/
trait PrincipalProxyTrait {
/**
* Returns the list of members for a group-principal
*
* @param string $principal
* @return string[]
* @throws Exception
*/
public function getGroupMemberSet($principal) {
$members = [];
if ($this->isProxyPrincipal($principal)) {
$realPrincipal = $this->getPrincipalUriFromProxyPrincipal($principal);
$principalArray = $this->getPrincipalByPath($realPrincipal);
if (!$principalArray) {
throw new Exception('Principal not found');
}
$proxies = $this->proxyMapper->getProxiesOf($principalArray['uri']);
foreach ($proxies as $proxy) {
if ($this->isReadProxyPrincipal($principal) && $proxy->getPermissions() === ProxyMapper::PERMISSION_READ) {
$members[] = $proxy->getProxyId();
}
if ($this->isWriteProxyPrincipal($principal) && $proxy->getPermissions() === (ProxyMapper::PERMISSION_READ | ProxyMapper::PERMISSION_WRITE)) {
$members[] = $proxy->getProxyId();
}
}
}
return $members;
}
/**
* Returns the list of groups a principal is a member of
*
* @param string $principal
* @param bool $needGroups
* @return array
* @throws Exception
*/
public function getGroupMembership($principal, $needGroups = false) {
list($prefix, $name) = \Sabre\Uri\split($principal);
if ($prefix !== $this->principalPrefix) {
return [];
}
$principalArray = $this->getPrincipalByPath($principal);
if (!$principalArray) {
throw new Exception('Principal not found');
}
$groups = [];
$proxies = $this->proxyMapper->getProxiesFor($principal);
foreach ($proxies as $proxy) {
if ($proxy->getPermissions() === ProxyMapper::PERMISSION_READ) {
$groups[] = $proxy->getOwnerId() . '/calendar-proxy-read';
}
if ($proxy->getPermissions() === (ProxyMapper::PERMISSION_READ | ProxyMapper::PERMISSION_WRITE)) {
$groups[] = $proxy->getOwnerId() . '/calendar-proxy-write';
}
}
return $groups;
}
/**
* Updates the list of group members for a group principal.
*
* The principals should be passed as a list of uri's.
*
* @param string $principal
* @param string[] $members
* @throws Exception
*/
public function setGroupMemberSet($principal, array $members) {
list($principalUri, $target) = \Sabre\Uri\split($principal);
if ($target !== 'calendar-proxy-write' && $target !== 'calendar-proxy-read') {
throw new Exception('Setting members of the group is not supported yet');
}
$masterPrincipalArray = $this->getPrincipalByPath($principalUri);
if (!$masterPrincipalArray) {
throw new Exception('Principal not found');
}
$permission = ProxyMapper::PERMISSION_READ;
if ($target === 'calendar-proxy-write') {
$permission |= ProxyMapper::PERMISSION_WRITE;
}
list($prefix, $owner) = \Sabre\Uri\split($principalUri);
$proxies = $this->proxyMapper->getProxiesOf($principalUri);
foreach ($members as $member) {
list($prefix, $name) = \Sabre\Uri\split($member);
if ($prefix !== $this->principalPrefix) {
throw new Exception('Invalid member group prefix: ' . $prefix);
}
$principalArray = $this->getPrincipalByPath($member);
if (!$principalArray) {
throw new Exception('Principal not found');
}
$found = false;
foreach ($proxies as $proxy) {
if ($proxy->getProxyId() === $member) {
$found = true;
$proxy->setPermissions($proxy->getPermissions() | $permission);
$this->proxyMapper->update($proxy);
$proxies = array_filter($proxies, function(Proxy $p) use ($proxy) {
return $p->getId() !== $proxy->getId();
});
break;
}
}
if ($found === false) {
$proxy = new Proxy();
$proxy->setOwnerId($principalUri);
$proxy->setProxyId($member);
$proxy->setPermissions($permission);
$this->proxyMapper->insert($proxy);
}
}
// Delete all remaining proxies
foreach ($proxies as $proxy) {
// Write and Read Proxies have individual requests,
// so only delete proxies of this permission
if ($proxy->getPermissions() === $permission) {
$this->proxyMapper->delete($proxy);
}
}
}
/**
* @param string $principalUri
* @return bool
*/
private function isProxyPrincipal(string $principalUri):bool {
list($realPrincipalUri, $proxy) = \Sabre\Uri\split($principalUri);
list($prefix, $userId) = \Sabre\Uri\split($realPrincipalUri);
if (!isset($prefix) || !isset($userId)) {
return false;
}
if ($prefix !== $this->principalPrefix) {
return false;
}
return $proxy === 'calendar-proxy-read'
|| $proxy === 'calendar-proxy-write';
}
/**
* @param string $principalUri
* @return bool
*/
private function isReadProxyPrincipal(string $principalUri):bool {
list(, $proxy) = \Sabre\Uri\split($principalUri);
return $proxy === 'calendar-proxy-read';
}
/**
* @param string $principalUri
* @return bool
*/
private function isWriteProxyPrincipal(string $principalUri):bool {
list(, $proxy) = \Sabre\Uri\split($principalUri);
return $proxy === 'calendar-proxy-write';
}
/**
* @param string $principalUri
* @return string
*/
private function getPrincipalUriFromProxyPrincipal(string $principalUri):string {
list($realPrincipalUri, ) = \Sabre\Uri\split($principalUri);
return $realPrincipalUri;
}
}

View File

@ -26,6 +26,7 @@
namespace OCA\DAV\Tests\unit\CalDAV; namespace OCA\DAV\Tests\unit\CalDAV;
use OCA\DAV\CalDAV\CalDavBackend; use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\Connector\Sabre\Principal;
use OCP\App\IAppManager; use OCP\App\IAppManager;
use OCP\IConfig; use OCP\IConfig;
@ -83,8 +84,8 @@ abstract class AbstractCalDavBackend extends TestCase {
$this->groupManager, $this->groupManager,
$this->createMock(ShareManager::class), $this->createMock(ShareManager::class),
$this->createMock(IUserSession::class), $this->createMock(IUserSession::class),
$this->createMock(IConfig::class),
$this->createMock(IAppManager::class), $this->createMock(IAppManager::class),
$this->createMock(ProxyMapper::class),
]) ])
->setMethods(['getPrincipalByPath', 'getGroupMembership']) ->setMethods(['getPrincipalByPath', 'getGroupMembership'])
->getMock(); ->getMock();

View File

@ -213,21 +213,44 @@ class CalendarTest extends TestCase {
'principal' => $hasOwnerSet ? 'user1' : 'user2', 'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true 'protected' => true
], [ ], [
'privilege' => '{DAV:}write', 'privilege' => '{DAV:}read',
'principal' => $hasOwnerSet ? 'user1' : 'user2', 'principal' => ($hasOwnerSet ? 'user1' : 'user2') . '/calendar-proxy-write',
'protected' => true 'protected' => true,
], [
'privilege' => '{DAV:}read',
'principal' => ($hasOwnerSet ? 'user1' : 'user2') . '/calendar-proxy-read',
'protected' => true,
]]; ]];
if ($uri === BirthdayService::BIRTHDAY_CALENDAR_URI) { if ($uri === BirthdayService::BIRTHDAY_CALENDAR_URI) {
$expectedAcl = [[ $expectedAcl[] = [
'privilege' => '{DAV:}read',
'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true
], [
'privilege' => '{DAV:}write-properties', 'privilege' => '{DAV:}write-properties',
'principal' => $hasOwnerSet ? 'user1' : 'user2', 'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true 'protected' => true
]]; ];
$expectedAcl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => ($hasOwnerSet ? 'user1' : 'user2') . '/calendar-proxy-write',
'protected' => true
];
} else {
$expectedAcl[] = [
'privilege' => '{DAV:}write',
'principal' => $hasOwnerSet ? 'user1' : 'user2',
'protected' => true
];
$expectedAcl[] = [
'privilege' => '{DAV:}write',
'principal' => ($hasOwnerSet ? 'user1' : 'user2') . '/calendar-proxy-write',
'protected' => true
];
} }
$expectedAcl[] = [
'privilege' => '{DAV:}write-properties',
'principal' => ($hasOwnerSet ? 'user1' : 'user2') . '/calendar-proxy-read',
'protected' => true
];
if ($hasOwnerSet) { if ($hasOwnerSet) {
$expectedAcl[] = [ $expectedAcl[] = [
'privilege' => '{DAV:}read', 'privilege' => '{DAV:}read',

View File

@ -21,6 +21,8 @@
*/ */
namespace OCA\DAV\Tests\unit\CalDAV\ResourceBooking; namespace OCA\DAV\Tests\unit\CalDAV\ResourceBooking;
use OCA\DAV\CalDAV\Proxy\Proxy;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IGroupManager; use OCP\IGroupManager;
use OCP\ILogger; use OCP\ILogger;
@ -43,6 +45,9 @@ abstract class AbstractPrincipalBackendTest extends TestCase {
/** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */ /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
protected $logger; protected $logger;
/** @var ProxyMapper|\PHPUnit_Framework_MockObject_MockObject */
protected $proxyMapper;
/** @var string */ /** @var string */
protected $mainDbTable; protected $mainDbTable;
@ -64,6 +69,7 @@ abstract class AbstractPrincipalBackendTest extends TestCase {
$this->userSession = $this->createMock(IUserSession::class); $this->userSession = $this->createMock(IUserSession::class);
$this->groupManager = $this->createMock(IGroupManager::class); $this->groupManager = $this->createMock(IGroupManager::class);
$this->logger = $this->createMock(ILogger::class); $this->logger = $this->createMock(ILogger::class);
$this->proxyMapper = $this->createMock(ProxyMapper::class);
} }
protected function tearDown() { protected function tearDown() {
@ -152,21 +158,113 @@ abstract class AbstractPrincipalBackendTest extends TestCase {
} }
public function testGetGroupMemberSet() { public function testGetGroupMemberSet() {
$actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/foo-bar'); $actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/backend1-res1');
$this->assertEquals([], $actual); $this->assertEquals([], $actual);
} }
public function testGetGroupMemberSetProxyRead() {
$proxy1 = new Proxy();
$proxy1->setProxyId('proxyId1');
$proxy1->setPermissions(1);
$proxy2 = new Proxy();
$proxy2->setProxyId('proxyId2');
$proxy2->setPermissions(3);
$proxy3 = new Proxy();
$proxy3->setProxyId('proxyId3');
$proxy3->setPermissions(3);
$this->proxyMapper->expects($this->once())
->method('getProxiesOf')
->with($this->principalPrefix . '/backend1-res1')
->willReturn([$proxy1, $proxy2, $proxy3]);
$actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/backend1-res1/calendar-proxy-read');
$this->assertEquals(['proxyId1'], $actual);
}
public function testGetGroupMemberSetProxyWrite() {
$proxy1 = new Proxy();
$proxy1->setProxyId('proxyId1');
$proxy1->setPermissions(1);
$proxy2 = new Proxy();
$proxy2->setProxyId('proxyId2');
$proxy2->setPermissions(3);
$proxy3 = new Proxy();
$proxy3->setProxyId('proxyId3');
$proxy3->setPermissions(3);
$this->proxyMapper->expects($this->once())
->method('getProxiesOf')
->with($this->principalPrefix . '/backend1-res1')
->willReturn([$proxy1, $proxy2, $proxy3]);
$actual = $this->principalBackend->getGroupMemberSet($this->principalPrefix . '/backend1-res1/calendar-proxy-write');
$this->assertEquals(['proxyId2', 'proxyId3'], $actual);
}
public function testGetGroupMembership() { public function testGetGroupMembership() {
$actual = $this->principalBackend->getGroupMembership($this->principalPrefix . '/foo-bar'); $proxy1 = new Proxy();
$this->assertEquals([], $actual); $proxy1->setOwnerId('proxyId1');
$proxy1->setPermissions(1);
$proxy2 = new Proxy();
$proxy2->setOwnerId('proxyId2');
$proxy2->setPermissions(3);
$this->proxyMapper->expects($this->once())
->method('getProxiesFor')
->with($this->principalPrefix . '/backend1-res1')
->willReturn([$proxy1, $proxy2]);
$actual = $this->principalBackend->getGroupMembership($this->principalPrefix . '/backend1-res1');
$this->assertEquals(['proxyId1/calendar-proxy-read', 'proxyId2/calendar-proxy-write'], $actual);
} }
/**
* @expectedException \Sabre\DAV\Exception
* @expectedExceptionMessage Setting members of the group is not supported yet
*/
public function testSetGroupMemberSet() { public function testSetGroupMemberSet() {
$this->principalBackend->setGroupMemberSet($this->principalPrefix . '/foo-bar', ['foo', 'bar']); $this->proxyMapper->expects($this->at(0))
->method('getProxiesOf')
->with($this->principalPrefix . '/backend1-res1')
->willReturn([]);
$this->proxyMapper->expects($this->at(1))
->method('insert')
->with($this->callback(function($proxy) {
/** @var Proxy $proxy */
if ($proxy->getOwnerId() !== $this->principalPrefix . '/backend1-res1') {
return false;
}
if ($proxy->getProxyId() !== $this->principalPrefix . '/backend1-res2') {
return false;
}
if ($proxy->getPermissions() !== 3) {
return false;
}
return true;
}));
$this->proxyMapper->expects($this->at(2))
->method('insert')
->with($this->callback(function($proxy) {
/** @var Proxy $proxy */
if ($proxy->getOwnerId() !== $this->principalPrefix . '/backend1-res1') {
return false;
}
if ($proxy->getProxyId() !== $this->principalPrefix . '/backend2-res3') {
return false;
}
if ($proxy->getPermissions() !== 3) {
return false;
}
return true;
}));
$this->principalBackend->setGroupMemberSet($this->principalPrefix . '/backend1-res1/calendar-proxy-write', [$this->principalPrefix . '/backend1-res2', $this->principalPrefix . '/backend2-res3']);
} }
public function testUpdatePrincipal() { public function testUpdatePrincipal() {

View File

@ -28,7 +28,7 @@ Class ResourcePrincipalBackendTest extends AbstractPrincipalBackendTest {
parent::setUp(); parent::setUp();
$this->principalBackend = new ResourcePrincipalBackend(self::$realDatabase, $this->principalBackend = new ResourcePrincipalBackend(self::$realDatabase,
$this->userSession, $this->groupManager, $this->logger); $this->userSession, $this->groupManager, $this->logger, $this->proxyMapper);
$this->mainDbTable = 'calendar_resources'; $this->mainDbTable = 'calendar_resources';
$this->metadataDbTable = 'calendar_resources_md'; $this->metadataDbTable = 'calendar_resources_md';

View File

@ -28,7 +28,7 @@ Class RoomPrincipalBackendTest extends AbstractPrincipalBackendTest {
parent::setUp(); parent::setUp();
$this->principalBackend = new RoomPrincipalBackend(self::$realDatabase, $this->principalBackend = new RoomPrincipalBackend(self::$realDatabase,
$this->userSession, $this->groupManager, $this->logger); $this->userSession, $this->groupManager, $this->logger, $this->proxyMapper);
$this->mainDbTable = 'calendar_rooms'; $this->mainDbTable = 'calendar_rooms';
$this->metadataDbTable = 'calendar_rooms_md'; $this->metadataDbTable = 'calendar_rooms_md';

View File

@ -32,6 +32,7 @@
namespace OCA\DAV\Tests\unit\CardDAV; namespace OCA\DAV\Tests\unit\CardDAV;
use InvalidArgumentException; use InvalidArgumentException;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCA\DAV\CardDAV\AddressBook; use OCA\DAV\CardDAV\AddressBook;
use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\Connector\Sabre\Principal; use OCA\DAV\Connector\Sabre\Principal;
@ -131,8 +132,8 @@ class CardDavBackendTest extends TestCase {
$this->groupManager, $this->groupManager,
$this->createMock(ShareManager::class), $this->createMock(ShareManager::class),
$this->createMock(IUserSession::class), $this->createMock(IUserSession::class),
$this->createMock(IConfig::class),
$this->createMock(IAppManager::class), $this->createMock(IAppManager::class),
$this->createMock(ProxyMapper::class),
]) ])
->setMethods(['getPrincipalByPath', 'getGroupMembership']) ->setMethods(['getPrincipalByPath', 'getGroupMembership'])
->getMock(); ->getMock();

View File

@ -29,6 +29,8 @@
namespace OCA\DAV\Tests\unit\Connector\Sabre; namespace OCA\DAV\Tests\unit\Connector\Sabre;
use OC\User\User; use OC\User\User;
use OCA\DAV\CalDAV\Proxy\Proxy;
use OCA\DAV\CalDAV\Proxy\ProxyMapper;
use OCP\App\IAppManager; use OCP\App\IAppManager;
use OCP\IConfig; use OCP\IConfig;
use OCP\IGroup; use OCP\IGroup;
@ -57,27 +59,27 @@ class PrincipalTest extends TestCase {
/** @var IUserSession | \PHPUnit_Framework_MockObject_MockObject */ /** @var IUserSession | \PHPUnit_Framework_MockObject_MockObject */
private $userSession; private $userSession;
/** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */
private $config;
/** @var IAppManager | \PHPUnit_Framework_MockObject_MockObject */ /** @var IAppManager | \PHPUnit_Framework_MockObject_MockObject */
private $appManager; private $appManager;
/** @var ProxyMapper | \PHPUnit_Framework_MockObject_MockObject */
private $proxyMapper;
public function setUp() { public function setUp() {
$this->userManager = $this->createMock(IUserManager::class); $this->userManager = $this->createMock(IUserManager::class);
$this->groupManager = $this->createMock(IGroupManager::class); $this->groupManager = $this->createMock(IGroupManager::class);
$this->shareManager = $this->createMock(IManager::class); $this->shareManager = $this->createMock(IManager::class);
$this->userSession = $this->createMock(IUserSession::class); $this->userSession = $this->createMock(IUserSession::class);
$this->config = $this->createMock(IConfig::class);
$this->appManager = $this->createMock(IAppManager::class); $this->appManager = $this->createMock(IAppManager::class);
$this->proxyMapper = $this->createMock(ProxyMapper::class);
$this->connector = new \OCA\DAV\Connector\Sabre\Principal( $this->connector = new \OCA\DAV\Connector\Sabre\Principal(
$this->userManager, $this->userManager,
$this->groupManager, $this->groupManager,
$this->shareManager, $this->shareManager,
$this->userSession, $this->userSession,
$this->config, $this->appManager,
$this->appManager $this->proxyMapper
); );
parent::setUp(); parent::setUp();
} }
@ -203,19 +205,8 @@ class PrincipalTest extends TestCase {
} }
public function testGetGroupMemberSet() { public function testGetGroupMemberSet() {
$fooUser = $this->createMock(User::class);
$fooUser
->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('foo'));
$this->userManager
->expects($this->once())
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
$response = $this->connector->getGroupMemberSet('principals/users/foo'); $response = $this->connector->getGroupMemberSet('principals/users/foo');
$this->assertSame(['principals/users/foo'], $response); $this->assertSame([], $response);
} }
/** /**
@ -229,7 +220,71 @@ class PrincipalTest extends TestCase {
->with('foo') ->with('foo')
->will($this->returnValue(null)); ->will($this->returnValue(null));
$this->connector->getGroupMemberSet('principals/users/foo'); $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read');
}
public function testGetGroupMemberSetProxyRead() {
$fooUser = $this->createMock(User::class);
$fooUser
->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('foo'));
$this->userManager
->expects($this->once())
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
$proxy1 = new Proxy();
$proxy1->setProxyId('proxyId1');
$proxy1->setPermissions(1);
$proxy2 = new Proxy();
$proxy2->setProxyId('proxyId2');
$proxy2->setPermissions(3);
$proxy3 = new Proxy();
$proxy3->setProxyId('proxyId3');
$proxy3->setPermissions(3);
$this->proxyMapper->expects($this->once())
->method('getProxiesOf')
->with('principals/users/foo')
->willReturn([$proxy1, $proxy2, $proxy3]);
$this->assertEquals(['proxyId1'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read'));
}
public function testGetGroupMemberSetProxyWrite() {
$fooUser = $this->createMock(User::class);
$fooUser
->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('foo'));
$this->userManager
->expects($this->once())
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
$proxy1 = new Proxy();
$proxy1->setProxyId('proxyId1');
$proxy1->setPermissions(1);
$proxy2 = new Proxy();
$proxy2->setProxyId('proxyId2');
$proxy2->setPermissions(3);
$proxy3 = new Proxy();
$proxy3->setProxyId('proxyId3');
$proxy3->setPermissions(3);
$this->proxyMapper->expects($this->once())
->method('getProxiesOf')
->with('principals/users/foo')
->willReturn([$proxy1, $proxy2, $proxy3]);
$this->assertEquals(['proxyId2', 'proxyId3'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-write'));
} }
public function testGetGroupMembership() { public function testGetGroupMembership() {
@ -243,7 +298,7 @@ class PrincipalTest extends TestCase {
->method('getGID') ->method('getGID')
->willReturn('foo/bar'); ->willReturn('foo/bar');
$this->userManager $this->userManager
->expects($this->once()) ->expects($this->exactly(2))
->method('get') ->method('get')
->with('foo') ->with('foo')
->willReturn($fooUser); ->willReturn($fooUser);
@ -256,9 +311,24 @@ class PrincipalTest extends TestCase {
$group2, $group2,
]); ]);
$proxy1 = new Proxy();
$proxy1->setOwnerId('proxyId1');
$proxy1->setPermissions(1);
$proxy2 = new Proxy();
$proxy2->setOwnerId('proxyId2');
$proxy2->setPermissions(3);
$this->proxyMapper->expects($this->once())
->method('getProxiesFor')
->with('principals/users/foo')
->willReturn([$proxy1, $proxy2]);
$expectedResponse = [ $expectedResponse = [
'principals/groups/group1', 'principals/groups/group1',
'principals/groups/foo%2Fbar', 'principals/groups/foo%2Fbar',
'proxyId1/calendar-proxy-read',
'proxyId2/calendar-proxy-write',
]; ];
$response = $this->connector->getGroupMembership('principals/users/foo'); $response = $this->connector->getGroupMembership('principals/users/foo');
$this->assertSame($expectedResponse, $response); $this->assertSame($expectedResponse, $response);
@ -286,6 +356,58 @@ class PrincipalTest extends TestCase {
$this->connector->setGroupMemberSet('principals/users/foo', ['foo']); $this->connector->setGroupMemberSet('principals/users/foo', ['foo']);
} }
public function testSetGroupMembershipProxy() {
$fooUser = $this->createMock(User::class);
$fooUser
->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('foo'));
$barUser = $this->createMock(User::class);
$barUser
->expects($this->exactly(1))
->method('getUID')
->will($this->returnValue('bar'));
$this->userManager
->expects($this->at(0))
->method('get')
->with('foo')
->will($this->returnValue($fooUser));
$this->userManager
->expects($this->at(1))
->method('get')
->with('bar')
->will($this->returnValue($barUser));
$this->proxyMapper->expects($this->at(0))
->method('getProxiesOf')
->with('principals/users/foo')
->willReturn([]);
$this->proxyMapper->expects($this->at(1))
->method('insert')
->with($this->callback(function($proxy) {
/** @var Proxy $proxy */
if ($proxy->getOwnerId() !== 'principals/users/foo') {
return false;
}
if ($proxy->getProxyId() !== 'principals/users/bar') {
return false;
}
if ($proxy->getPermissions() !== 3) {
return false;
}
return true;
}));
$this->connector->setGroupMemberSet('principals/users/foo/calendar-proxy-write', ['principals/users/bar']);
}
public function testUpdatePrincipal() { public function testUpdatePrincipal() {
$this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch(array()))); $this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch(array())));
} }