Merge pull request #43 from nextcloud/stable9-pr

[stable9] Backport auditing app
This commit is contained in:
Lukas Reschke 2016-06-10 18:13:53 +02:00 committed by GitHub
commit 7d92165b99
14 changed files with 959 additions and 0 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@
!/apps/user_ldap
!/apps/provisioning_api
!/apps/systemtags
!/apps/admin_audit
!/apps/updatenotification
/apps/files_external/3rdparty/irodsphp/PHPUnitTest
/apps/files_external/3rdparty/irodsphp/web

View File

@ -0,0 +1,27 @@
<?php
/**
* @author Lukas Reschke <lukas@statuscode.ch>
*
* @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/>.
*
*/
$logger = \OC::$server->getLogger();
$userSession = \OC::$server->getUserSession();
$groupManager = \OC::$server->getGroupManager();
$auditLogger = new \OCA\Admin_Audit\AuditLogger($logger, $userSession, $groupManager);
$auditLogger->registerHooks();

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<info>
<id>admin_audit</id>
<name>Auditing / Logging</name>
<description>Provides logging abilities for Nextcloud such as logging file
accesses or otherwise sensitive actions.
</description>
<licence>AGPL</licence>
<author>Nextcloud</author>
<version>1.0.0</version>
<dependencies>
<owncloud min-version="9.0" max-version="9.1" />
</dependencies>
<types>
<logging/>
</types>
<default_enable/>
</info>

View File

@ -0,0 +1,76 @@
<?php
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @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\Admin_Audit\Actions;
use OCP\ILogger;
class Action {
/** @var ILogger */
private $logger;
/**
* @param ILogger $logger
*/
public function __construct(ILogger $logger) {
$this->logger = $logger;
}
/**
* Log a single action with a log level of info
*
* @param string $text
* @param array $params
* @param array $elements
*/
public function log($text,
array $params,
array $elements) {
foreach($elements as $element) {
if(!isset($params[$element])) {
$this->logger->critical(
sprintf(
'$params["'.$element.'"] was missing. Transferred value: %s',
print_r($params, true)
)
);
return;
}
}
$replaceArray = [];
foreach($elements as $element) {
if($params[$element] instanceof \DateTime) {
$params[$element] = $params[$element]->format('Y-m-d H:i:s');
}
$replaceArray[] = $params[$element];
}
$this->logger->info(
vsprintf(
$text,
$replaceArray
),
[
'app' => 'admin_audit'
]
);
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @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\Admin_Audit\Actions;
/**
* Class Auth logs all auth related actions
*
* @package OCA\Admin_Audit\Actions
*/
class Auth extends Action {
public function loginAttempt(array $params) {
$this->log(
'Login attempt: "%s"',
$params,
[
'uid',
]
);
}
public function loginSuccessful(array $params) {
$this->log(
'Login successful: "%s"',
$params,
[
'uid',
]
);
}
public function logout(array $params) {
$this->log(
'Logout occurred',
[],
[]
);
}
}

View File

@ -0,0 +1,135 @@
<?php
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @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\Admin_Audit\Actions;
/**
* Class Files logs the actions to files
*
* @package OCA\Admin_Audit\Actions
*/
class Files extends Action {
/**
* Logs file read actions
*
* @param array $params
*/
public function read(array $params) {
$this->log(
'File accessed: "%s"',
$params,
[
'path',
]
);
}
/**
* Logs rename actions of files
*
* @param array $params
*/
public function rename(array $params) {
$this->log(
'File renamed: "%s" to "%s"',
$params,
[
'oldpath',
'newpath',
]
);
}
/**
* Logs creation of files
*
* @param array $params
*/
public function create(array $params) {
$this->log(
'File created: "%s"',
$params,
[
'path',
]
);
}
/**
* Logs copying of files
*
* @param array $params
*/
public function copy(array $params) {
$this->log(
'File copied: "%s" to "%s"',
$params,
[
'oldpath',
'newpath',
]
);
}
/**
* Logs writing of files
*
* @param array $params
*/
public function write(array $params) {
$this->log(
'File written to: "%s"',
$params,
[
'path',
]
);
}
/**
* Logs update of files
*
* @param array $params
*/
public function update(array $params) {
$this->log(
'File updated: "%s"',
$params,
[
'path',
]
);
}
/**
* Logs deletions of files
*
* @param array $params
*/
public function delete(array $params) {
$this->log(
'File deleted: "%s"',
$params,
[
'path',
]
);
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @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\Admin_Audit\Actions;
use OCA\Admin_Audit\Actions\Action;
use OCP\IGroup;
use OCP\IUser;
/**
* Class GroupManagement logs all group manager related events
*
* @package OCA\Admin_Audit
*/
class GroupManagement extends Action {
/**
* log add user to group event
*
* @param IGroup $group
* @param IUser $user
*/
public function addUser(IGroup $group, IUser $user) {
$this->log('User "%s" added to group "%s"',
[
'group' => $group->getGID(),
'user' => $user->getUID()
],
[
'user', 'group'
]
);
}
/**
* log remove user from group event
*
* @param IGroup $group
* @param IUser $user
*/
public function removeUser(IGroup $group, IUser $user) {
$this->log('User "%s" removed from group "%s"',
[
'group' => $group->getGID(),
'user' => $user->getUID()
],
[
'user', 'group'
]
);
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @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\Admin_Audit\Actions;
use OCP\Share;
/**
* Class Sharing logs the sharing actions
*
* @package OCA\Admin_Audit\Actions
*/
class Sharing extends Action {
/**
* Logs sharing of data
*
* @param array $params
*/
public function shared(array $params) {
if($params['shareType'] === Share::SHARE_TYPE_LINK) {
$this->log(
'The %s "%s" with ID "%s" has been shared via link with permissions "%s" (Share ID: %s)',
$params,
[
'itemType',
'itemTarget',
'itemSource',
'permissions',
'id',
]
);
} elseif($params['shareType'] === Share::SHARE_TYPE_USER) {
$this->log(
'The %s "%s" with ID "%s" has been shared to the user "%s" with permissions "%s" (Share ID: %s)',
$params,
[
'itemType',
'itemTarget',
'itemSource',
'shareWith',
'permissions',
'id',
]
);
} elseif($params['shareType'] === Share::SHARE_TYPE_GROUP) {
$this->log(
'The %s "%s" with ID "%s" has been shared to the group "%s" with permissions "%s" (Share ID: %s)',
$params,
[
'itemType',
'itemTarget',
'itemSource',
'shareWith',
'permissions',
'id',
]
);
}
}
/**
* Logs unsharing of data
*
* @param array $params
*/
public function unshare(array $params) {
if($params['shareType'] === Share::SHARE_TYPE_LINK) {
$this->log(
'The %s "%s" with ID "%s" has been unshared (Share ID: %s)',
$params,
[
'itemType',
'fileTarget',
'itemSource',
'id',
]
);
} elseif($params['shareType'] === Share::SHARE_TYPE_USER) {
$this->log(
'The %s "%s" with ID "%s" has been unshared from the user "%s" (Share ID: %s)',
$params,
[
'itemType',
'fileTarget',
'itemSource',
'shareWith',
'id',
]
);
} elseif($params['shareType'] === Share::SHARE_TYPE_GROUP) {
$this->log(
'The %s "%s" with ID "%s" has been unshared from the group "%s" (Share ID: %s)',
$params,
[
'itemType',
'fileTarget',
'itemSource',
'shareWith',
'id',
]
);
}
}
/**
* Logs the updating of permission changes for shares
*
* @param array $params
*/
public function updatePermissions(array $params) {
$this->log(
'The permissions of the shared %s "%s" with ID "%s" have been changed to "%s"',
$params,
[
'itemType',
'path',
'itemSource',
'permissions',
]
);
}
/**
* Logs the password changes for a share
*
* @param array $params
*/
public function updatePassword(array $params) {
$this->log(
'The password of the publicly shared %s "%s" with ID "%s" has been changed',
$params,
[
'itemType',
'token',
'itemSource',
]
);
}
/**
* Logs the expiration date changes for a share
*
* @param array $params
*/
public function updateExpirationDate(array $params) {
$this->log(
'The expiration date of the publicly shared %s with ID "%s" has been changed to "%s"',
$params,
[
'itemType',
'itemSource',
'date',
]
);
}
/**
* Logs access of shared files
*
* @param array $params
*/
public function shareAccessed(array $params) {
$this->log(
'The shared %s with the token "%s" by "%s" has been accessed.',
$params,
[
'itemType',
'token',
'uidOwner',
]
);
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @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\Admin_Audit\Actions;
use OCP\ILogger;
use OCP\IUserSession;
class Trashbin extends Action {
/** @var IUserSession */
private $userSession;
/**
* Trashbin constructor.
*
* @param ILogger $logger
* @param IUserSession $userSession
*/
public function __construct(ILogger $logger, IUserSession $userSession) {
parent::__construct($logger);
$this->userSession = $userSession;
}
public function delete($params) {
$this->log('File "%s" deleted from trash bin by "%s"',
[
'path' => $params['path'],
'user' => $this->userSession->getUser()->getUID()
],
[
'path', 'user'
]
);
}
public function restore($params) {
$this->log('File "%s" restored from trash bin by "%s"',
[
'path' => $params['filePath'],
'user' => $this->userSession->getUser()->getUID()
],
[
'path', 'user'
]
);
}
}

View File

@ -0,0 +1,78 @@
<?php
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @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\Admin_Audit\Actions;
use OCP\IUser;
/**
* Class UserManagement logs all user management related actions.
*
* @package OCA\Admin_Audit\Actions
*/
class UserManagement extends Action {
/**
* Log creation of users
*
* @param array $params
*/
public function create(array $params) {
$this->log(
'User created: "%s"',
$params,
[
'uid',
]
);
}
/**
* Log deletion of users
*
* @param array $params
*/
public function delete(array $params) {
$this->log(
'User deleted: "%s"',
$params,
[
'uid',
]
);
}
/**
* Logs changing of the user scope
*
* @param IUser $user
*/
public function setPassword(IUser $user) {
if($user->getBackendClassName() === 'Database') {
$this->log(
'Password of user "%s" has been changed',
[
'user' => $user->getUID(),
],
[
'user',
]
);
}
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* @copyright Bjoern Schiessle <bjoern@schiessle.org>
*
* @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\Admin_Audit\Actions;
class Versions extends Action {
public function rollback($params) {
$this->log('Version "%s" of "%s" was restored.',
[
'version' => $params['revision'],
'path' => $params['path']
],
['version', 'path']
);
}
public function delete($params) {
$this->log('Version "%s" was deleted.',
['path' => $params['path']],
['path']
);
}
}

View File

@ -0,0 +1,186 @@
<?php
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
* @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\Admin_Audit;
use OC\Files\Filesystem;
use OCA\Admin_Audit\Actions\Auth;
use OCA\Admin_Audit\Actions\Files;
use OCA\Admin_Audit\Actions\GroupManagement;
use OCA\Admin_Audit\Actions\Sharing;
use OCA\Admin_Audit\Actions\Trashbin;
use OCA\Admin_Audit\Actions\UserManagement;
use OCA\Admin_Audit\Actions\Versions;
use OCP\IGroupManager;
use OCP\ILogger;
use OCP\IUserSession;
use OCP\Util;
class AuditLogger {
/** @var ILogger */
private $logger;
/** @var IUserSession */
private $userSession;
/** @var IGroupManager */
private $groupManager;
/**
* AuditLogger constructor.
*
* @param ILogger $logger
* @param IUserSession $userSession
* @param IGroupManager $groupManager
*/
public function __construct(ILogger $logger,
IUserSession $userSession,
IGroupManager $groupManager) {
$this->logger = $logger;
$this->userSession = $userSession;
$this->groupManager = $groupManager;
}
/**
* register hooks in order to log them
*/
public function registerHooks() {
$this->userManagementHooks();
$this->groupHooks();
$this->sharingHooks();
$this->authHooks();
$this->fileHooks();
$this->trashbinHooks();
$this->versionsHooks();
}
/**
* connect to user management hooks
*/
private function userManagementHooks() {
$userActions = new UserManagement($this->logger);
Util::connectHook('OC_User', 'post_createUser', $userActions, 'create');
Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete');
$this->userSession->listen('\OC\User', 'postSetPassword', [$userActions, 'setPassword']);
}
private function groupHooks() {
$groupActions = new GroupManagement($this->logger);
$this->groupManager->listen('\OC\Group', 'postRemoveUser', [$groupActions, 'removeUser']);
$this->groupManager->listen('\OC\Group', 'postAddUser', [$groupActions, 'addUser']);
}
/**
* connect to sharing events
*/
private function sharingHooks() {
$shareActions = new Sharing($this->logger);
Util::connectHook('OCP\Share', 'post_shared', $shareActions, 'shared');
Util::connectHook('OCP\Share', 'post_unshare', $shareActions, 'unshare');
Util::connectHook('OCP\Share', 'post_update_permissions', $shareActions, 'updatePermissions');
Util::connectHook('OCP\Share', 'post_update_password', $shareActions, 'updatePassword');
Util::connectHook('OCP\Share', 'post_set_expiration_date', $shareActions, 'updateExpirationDate');
Util::connectHook('OCP\Share', 'share_link_access', $shareActions, 'shareAccessed');
}
/**
* connect to authentication event and related actions
*/
private function authHooks() {
$authActions = new Auth($this->logger);
Util::connectHook('OC_User', 'pre_login', $authActions, 'loginAttempt');
Util::connectHook('OC_User', 'post_login', $authActions, 'loginSuccessful');
Util::connectHook('OC_User', 'logout', $authActions, 'logout');
}
/**
* connect to file hooks
*/
private function fileHooks() {
$fileActions = new Files($this->logger);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_post_rename,
$fileActions,
'rename'
);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_post_create,
$fileActions,
'create'
);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_post_copy,
$fileActions,
'copy'
);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_post_write,
$fileActions,
'write'
);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_post_update,
$fileActions,
'update'
);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_read,
$fileActions,
'read'
);
Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_delete,
$fileActions,
'delete'
);
}
public function versionsHooks() {
$versionsActions = new Versions($this->logger);
Util::connectHook('\OCP\Versions', 'rollback', $versionsActions, 'rollback');
Util::connectHook('\OCP\Versions', 'delete',$versionsActions, 'delete');
}
/**
* connect to trash bin hooks
*/
private function trashbinHooks() {
$trashActions = new Trashbin($this->logger, $this->userSession);
Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete');
Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore');
}
}

View File

@ -64,6 +64,11 @@ OC.Log = {
timeTd.text(formatDate(entry.time * 1000));
}
row.append(timeTd);
var userTd = $('<td/>');
userTd.text(entry.user);
row.append(userTd);
$('#log').append(row);
}
OC.Log.loaded += entries.length;

View File

@ -519,6 +519,7 @@ if ($_['cronErrors']) {
p($entry->time);
}?>
</td>
<td><?php isset($entry->user) ? p($entry->user) : p('--') ?></td>
</tr>
<?php endforeach;?>
</table>