Skip to content

Commit bb3b712

Browse files
authored
Merge pull request #3115 from nextcloud/backport/3096/stable29
[stable29] emit audit log events for changes to groupfolders
2 parents 759e2aa + b18deb0 commit bb3b712

File tree

7 files changed

+90
-52
lines changed

7 files changed

+90
-52
lines changed

β€Žlib/ACL/Rule.php

+24
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
use OCA\GroupFolders\ACL\UserMapping\IUserMapping;
2727
use OCA\GroupFolders\ACL\UserMapping\UserMapping;
28+
use OCP\Constants;
2829
use Sabre\Xml\Reader;
2930
use Sabre\Xml\Writer;
3031
use Sabre\Xml\XmlDeserializable;
@@ -38,6 +39,14 @@ class Rule implements XmlSerializable, XmlDeserializable, \JsonSerializable {
3839
public const MAPPING_ID = '{http://nextcloud.org/ns}acl-mapping-id';
3940
public const MAPPING_DISPLAY_NAME = '{http://nextcloud.org/ns}acl-mapping-display-name';
4041

42+
public const PERMISSIONS_MAP = [
43+
'read' => Constants::PERMISSION_READ,
44+
'write' => Constants::PERMISSION_UPDATE,
45+
'create' => Constants::PERMISSION_CREATE,
46+
'delete' => Constants::PERMISSION_DELETE,
47+
'share' => Constants::PERMISSION_SHARE,
48+
];
49+
4150
private $userMapping;
4251
private $fileId;
4352

@@ -182,4 +191,19 @@ public static function defaultRule(): Rule {
182191
0
183192
);
184193
}
194+
195+
public static function formatRulePermissions(int $mask, int $permissions): string {
196+
$result = [];
197+
foreach (self::PERMISSIONS_MAP as $name => $value) {
198+
if (($mask & $value) === $value) {
199+
$type = ($permissions & $value) === $value ? '+' : '-';
200+
$result[] = $type . $name;
201+
}
202+
}
203+
return implode(', ', $result);
204+
}
205+
206+
public function formatPermissions(): string {
207+
return self::formatRulePermissions($this->mask, $this->permissions);
208+
}
185209
}

β€Žlib/Command/ACL.php

+4-23
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@
3939
use Symfony\Component\Console\Output\OutputInterface;
4040

4141
class ACL extends FolderCommand {
42-
public const PERMISSIONS_MAP = [
43-
'read' => Constants::PERMISSION_READ,
44-
'write' => Constants::PERMISSION_UPDATE,
45-
'create' => Constants::PERMISSION_CREATE,
46-
'delete' => Constants::PERMISSION_DELETE,
47-
'share' => Constants::PERMISSION_SHARE,
48-
];
49-
5042
private RuleManager $ruleManager;
5143
private ACLManagerFactory $aclManagerFactory;
5244
private IUserManager $userManager;
@@ -103,7 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
10395
$path = $input->getArgument('path');
10496
$aclManager = $this->aclManagerFactory->getACLManager($user);
10597
$permissions = $aclManager->getACLPermissionsForPath($jailPath . rtrim('/' . $path, '/'));
106-
$permissionString = $this->formatRulePermissions(Constants::PERMISSION_ALL, $permissions);
98+
$permissionString = Rule::formatRulePermissions(Constants::PERMISSION_ALL, $permissions);
10799
$output->writeln($permissionString);
108100
return 0;
109101
} else {
@@ -177,7 +169,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
177169
return -3;
178170
}
179171
$name = substr($permission, 1);
180-
if (!isset(self::PERMISSIONS_MAP[$name])) {
172+
if (!isset(Rule::PERMISSIONS_MAP[$name])) {
181173
$output->writeln('<error>incorrect format for permissions2 "' . $permission . '"</error>');
182174
return -3;
183175
}
@@ -223,7 +215,7 @@ private function printPermissions(InputInterface $input, OutputInterface $output
223215
return $rule->getUserMapping()->getType() . ': ' . $rule->getUserMapping()->getId();
224216
}, $rulesForPath);
225217
$permissions = array_map(function (Rule $rule) {
226-
return $this->formatRulePermissions($rule->getMask(), $rule->getPermissions());
218+
return $rule->formatPermissions();
227219
}, $rulesForPath);
228220
$formattedPath = substr($path, $jailPathLength);
229221
return [
@@ -244,23 +236,12 @@ private function printPermissions(InputInterface $input, OutputInterface $output
244236
}
245237
}
246238

247-
private function formatRulePermissions(int $mask, int $permissions): string {
248-
$result = [];
249-
foreach (self::PERMISSIONS_MAP as $name => $value) {
250-
if (($mask & $value) === $value) {
251-
$type = ($permissions & $value) === $value ? '+' : '-';
252-
$result[] = $type . $name;
253-
}
254-
}
255-
return implode(', ', $result);
256-
}
257-
258239
private function parsePermissions(array $permissions): array {
259240
$mask = 0;
260241
$result = 0;
261242

262243
foreach ($permissions as $permission) {
263-
$permissionValue = self::PERMISSIONS_MAP[substr($permission, 1)];
244+
$permissionValue = Rule::PERMISSIONS_MAP[substr($permission, 1)];
264245
$mask |= $permissionValue;
265246
if ($permission[0] === '+') {
266247
$result |= $permissionValue;

β€Žlib/Controller/FolderController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public function removeFolder(int $id): DataResponse {
185185
* @RequireGroupFolderAdmin
186186
*/
187187
public function setMountPoint(int $id, string $mountPoint): DataResponse {
188-
$this->manager->setMountPoint($id, trim($mountPoint));
188+
$this->manager->renameFolder($id, trim($mountPoint));
189189
return new DataResponse(['success' => true]);
190190
}
191191

β€Žlib/DAV/ACLPlugin.php

+23-9
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
use OCA\GroupFolders\Folder\FolderManager;
3030
use OCA\GroupFolders\Mount\GroupMountPoint;
3131
use OCP\Constants;
32+
use OCP\EventDispatcher\IEventDispatcher;
3233
use OCP\IUser;
3334
use OCP\IUserSession;
35+
use OCP\Log\Audit\CriticalActionPerformedEvent;
3436
use Sabre\DAV\INode;
3537
use Sabre\DAV\PropFind;
3638
use Sabre\DAV\PropPatch;
@@ -46,19 +48,14 @@ class ACLPlugin extends ServerPlugin {
4648
public const GROUP_FOLDER_ID = '{http://nextcloud.org/ns}group-folder-id';
4749

4850
private ?Server $server = null;
49-
private RuleManager $ruleManager;
50-
private FolderManager $folderManager;
51-
private IUserSession $userSession;
5251
private ?IUser $user = null;
5352

5453
public function __construct(
55-
RuleManager $ruleManager,
56-
IUserSession $userSession,
57-
FolderManager $folderManager
54+
private RuleManager $ruleManager,
55+
private IUserSession $userSession,
56+
private FolderManager $folderManager,
57+
private IEventDispatcher $eventDispatcher,
5858
) {
59-
$this->ruleManager = $ruleManager;
60-
$this->userSession = $userSession;
61-
$this->folderManager = $folderManager;
6259
}
6360

6461
private function isAdmin(string $path): bool {
@@ -211,6 +208,23 @@ public function propPatch(string $path, PropPatch $propPatch): void {
211208
);
212209
}, $rawRules);
213210

211+
$formattedRules = array_map(function (Rule $rule) {
212+
return $rule->getUserMapping()->getType() . ' ' . $rule->getUserMapping()->getDisplayName() . ': ' . $rule->formatPermissions();
213+
}, $rules);
214+
if (count($formattedRules)) {
215+
$formattedRules = implode(', ', $formattedRules);
216+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The advanced permissions for "%s" in groupfolder with id %d was set to "%s"', [
217+
$fileInfo->getInternalPath(),
218+
$mount->getFolderId(),
219+
$formattedRules,
220+
]));
221+
} else {
222+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The advanced permissions for "%s" in groupfolder with id %d was cleared', [
223+
$fileInfo->getInternalPath(),
224+
$mount->getFolderId(),
225+
]));
226+
}
227+
214228
$existingRules = array_reduce(
215229
$this->ruleManager->getAllRulesForPaths($mount->getNumericStorageId(), [$path]),
216230
function (array $rules, array $rulesForPath) {

β€Žlib/Folder/FolderManager.php

+25-13
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@
3232
use OCP\Constants;
3333
use OCP\DB\Exception;
3434
use OCP\DB\QueryBuilder\IQueryBuilder;
35+
use OCP\EventDispatcher\IEventDispatcher;
3536
use OCP\Files\Cache\ICacheEntry;
3637
use OCP\Files\IMimeTypeLoader;
3738
use OCP\Files\IRootFolder;
3839
use OCP\IDBConnection;
3940
use OCP\IGroupManager;
4041
use OCP\IUser;
4142
use OCP\IUserManager;
43+
use OCP\Log\Audit\CriticalActionPerformedEvent;
4244
use OCP\Server;
4345
use Psr\Container\ContainerExceptionInterface;
4446
use Psr\Log\LoggerInterface;
@@ -51,7 +53,8 @@ public function __construct(
5153
private IDBConnection $connection,
5254
private IGroupManager $groupManager,
5355
private IMimeTypeLoader $mimeTypeLoader,
54-
private LoggerInterface $logger
56+
private LoggerInterface $logger,
57+
private IEventDispatcher $eventDispatcher,
5558
) {
5659
}
5760

@@ -674,20 +677,11 @@ public function createFolder(string $mountPoint): int {
674677
'mount_point' => $query->createNamedParameter($mountPoint)
675678
]);
676679
$query->executeStatement();
680+
$id = $query->getLastInsertId();
677681

678-
return $query->getLastInsertId();
679-
}
682+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('A new groupfolder "%s" was created with id %d', [$mountPoint, $id]));
680683

681-
/**
682-
* @throws Exception
683-
*/
684-
public function setMountPoint(int $folderId, string $mountPoint): void {
685-
$query = $this->connection->getQueryBuilder();
686-
687-
$query->update('group_folders')
688-
->set('mount_point', $query->createNamedParameter($mountPoint))
689-
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)));
690-
$query->executeStatement();
684+
return $id;
691685
}
692686

693687
/**
@@ -709,6 +703,8 @@ public function addApplicableGroup(int $folderId, string $groupId): void {
709703
'permissions' => $query->createNamedParameter(Constants::PERMISSION_ALL)
710704
]);
711705
$query->executeStatement();
706+
707+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The group "%s" was given access to the groupfolder with id %d', [$groupId, $folderId]));
712708
}
713709

714710
/**
@@ -730,6 +726,8 @@ public function removeApplicableGroup(int $folderId, string $groupId): void {
730726
)
731727
);
732728
$query->executeStatement();
729+
730+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The group "%s" was revoked access to the groupfolder with id %d', [$groupId, $folderId]));
733731
}
734732

735733

@@ -754,6 +752,8 @@ public function setGroupPermissions(int $folderId, string $groupId, int $permiss
754752
);
755753

756754
$query->executeStatement();
755+
756+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The permissions of group "%s" to the groupfolder with id %d was set to %d', [$groupId, $folderId, $permissions]));
757757
}
758758

759759
/**
@@ -775,6 +775,9 @@ public function setManageACL(int $folderId, string $type, string $id, bool $mana
775775
->andWhere($query->expr()->eq('mapping_id', $query->createNamedParameter($id)));
776776
}
777777
$query->executeStatement();
778+
779+
$action = $manageAcl ? "given" : "revoked";
780+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The %s "%s" was %s acl management rights to the groupfolder with id %d', [$type, $id, $action, $folderId]));
778781
}
779782

780783
/**
@@ -786,6 +789,8 @@ public function removeFolder(int $folderId): void {
786789
$query->delete('group_folders')
787790
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)));
788791
$query->executeStatement();
792+
793+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The groupfolder with id %d was removed', [$folderId]));
789794
}
790795

791796
/**
@@ -798,6 +803,8 @@ public function setFolderQuota(int $folderId, int $quota): void {
798803
->set('quota', $query->createNamedParameter($quota))
799804
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId)));
800805
$query->executeStatement();
806+
807+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The quota for groupfolder with id %d was set to %d bytes', [$folderId, $quota]));
801808
}
802809

803810
/**
@@ -810,6 +817,8 @@ public function renameFolder(int $folderId, string $newMountPoint): void {
810817
->set('mount_point', $query->createNamedParameter($newMountPoint))
811818
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT)));
812819
$query->executeStatement();
820+
821+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('The groupfolder with id %d was renamed to "%s"', [$folderId, $newMountPoint]));
813822
}
814823

815824
/**
@@ -870,6 +879,9 @@ public function setFolderACL(int $folderId, bool $acl): void {
870879
->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId)));
871880
$query->executeStatement();
872881
}
882+
883+
$action = $acl ? "enabled" : "disabled";
884+
$this->eventDispatcher->dispatchTyped(new CriticalActionPerformedEvent('Advanced permissions for the groupfolder with id %d was %s', [$folderId, $action]));
873885
}
874886

875887
/**

β€Žtests/Folder/FolderManagerTest.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
use OCA\GroupFolders\Folder\FolderManager;
2525
use OCP\Constants;
26+
use OCP\EventDispatcher\IEventDispatcher;
2627
use OCP\Files\IMimeTypeLoader;
2728
use OCP\IDBConnection;
2829
use OCP\IGroupManager;
@@ -38,18 +39,21 @@ class FolderManagerTest extends TestCase {
3839
private IGroupManager $groupManager;
3940
private IMimeTypeLoader $mimeLoader;
4041
private LoggerInterface $logger;
42+
private IEventDispatcher $eventDispatcher;
4143

4244
protected function setUp(): void {
4345
parent::setUp();
4446

4547
$this->groupManager = $this->createMock(IGroupManager::class);
4648
$this->mimeLoader = $this->createMock(IMimeTypeLoader::class);
4749
$this->logger = $this->createMock(LoggerInterface::class);
50+
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
4851
$this->manager = new FolderManager(
4952
\OC::$server->getDatabaseConnection(),
5053
$this->groupManager,
5154
$this->mimeLoader,
52-
$this->logger
55+
$this->logger,
56+
$this->eventDispatcher,
5357
);
5458
$this->clean();
5559
}
@@ -101,7 +105,7 @@ public function testSetMountpoint() {
101105
$folderId1 = $this->manager->createFolder('foo');
102106
$this->manager->createFolder('bar');
103107

104-
$this->manager->setMountPoint($folderId1, 'foo2');
108+
$this->manager->renameFolder($folderId1, 'foo2');
105109

106110
$this->assertHasFolders([
107111
['mount_point' => 'foo2', 'groups' => []],
@@ -319,7 +323,7 @@ public function testGetFoldersForUserSimple() {
319323
$db = $this->createMock(IDBConnection::class);
320324
/** @var FolderManager|\PHPUnit_Framework_MockObject_MockObject $manager */
321325
$manager = $this->getMockBuilder(FolderManager::class)
322-
->setConstructorArgs([$db, $this->groupManager, $this->mimeLoader, $this->logger])
326+
->setConstructorArgs([$db, $this->groupManager, $this->mimeLoader, $this->logger, $this->eventDispatcher])
323327
->setMethods(['getFoldersForGroups'])
324328
->getMock();
325329

@@ -342,7 +346,7 @@ public function testGetFoldersForUserMerge() {
342346
$db = $this->createMock(IDBConnection::class);
343347
/** @var FolderManager|\PHPUnit_Framework_MockObject_MockObject $manager */
344348
$manager = $this->getMockBuilder(FolderManager::class)
345-
->setConstructorArgs([$db, $this->groupManager, $this->mimeLoader, $this->logger])
349+
->setConstructorArgs([$db, $this->groupManager, $this->mimeLoader, $this->logger, $this->eventDispatcher])
346350
->setMethods(['getFoldersForGroups'])
347351
->getMock();
348352

@@ -378,7 +382,7 @@ public function testGetFolderPermissionsForUserMerge() {
378382
$db = $this->createMock(IDBConnection::class);
379383
/** @var FolderManager|\PHPUnit_Framework_MockObject_MockObject $manager */
380384
$manager = $this->getMockBuilder(FolderManager::class)
381-
->setConstructorArgs([$db, $this->groupManager, $this->mimeLoader, $this->logger])
385+
->setConstructorArgs([$db, $this->groupManager, $this->mimeLoader, $this->logger, $this->eventDispatcher])
382386
->setMethods(['getFoldersForGroups'])
383387
->getMock();
384388

β€Žtests/stub.phpstub

+4-1
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,9 @@ namespace OC\Files\Storage\Wrapper{
15451545
public function getDirectoryContent($directory) : \Traversable
15461546
{
15471547
}
1548+
public function setOwner(?string $user) : void
1549+
{
1550+
}
15481551
}
15491552

15501553

@@ -1655,4 +1658,4 @@ namespace OCA\DAV\Connector\Sabre\Exception {
16551658
*/
16561659
public function serialize(\Sabre\DAV\Server $server, \DOMElement $errorNode) {}
16571660
}
1658-
}
1661+
}

0 commit comments

Comments
Β (0)