diff --git a/lib/Controller/ConfigController.php b/lib/Controller/ConfigController.php index e24b209e3..79ae35a8d 100755 --- a/lib/Controller/ConfigController.php +++ b/lib/Controller/ConfigController.php @@ -216,11 +216,21 @@ private function setIntegrationConfig(array $values): array { // creates or replace the app password if (key_exists('setup_app_password', $values) && $values['setup_app_password'] === true) { + $isAppPasswordBeingReplaced = $this->openprojectAPIService->hasAppPassword(); $this->openprojectAPIService->deleteAppPassword(); if (!$this->userManager->userExists(Application::OPEN_PROJECT_ENTITIES_NAME)) { throw new NoUserException('User "' . Application::OPEN_PROJECT_ENTITIES_NAME . '" does not exists to create application password'); } $appPassword = $this->openprojectAPIService->generateAppPasswordTokenForUser(); + if($isAppPasswordBeingReplaced) { + $this->openprojectAPIService->logToAuditFile( + "Application password for user 'OpenProject has been replaced' in application " . Application::APP_ID + ); + } else { + $this->openprojectAPIService->logToAuditFile( + "New application password for user 'OpenProject' has been created in application " . Application::APP_ID + ); + } } $oldOpenProjectOauthUrl = $this->config->getAppValue( @@ -280,6 +290,11 @@ private function setIntegrationConfig(array $values): array { // resetting and keeping the project folder setup should delete the user app password if (key_exists('setup_app_password', $values) && $values['setup_app_password'] === false) { $this->openprojectAPIService->deleteAppPassword(); + if(!$runningFullReset) { + $this->openprojectAPIService->logToAuditFile( + "Project folder setup has been deactivated in application " . Application::APP_ID + ); + } } $this->config->deleteAppValue(Application::APP_ID, 'oPOAuthTokenRevokeStatus'); @@ -337,6 +352,9 @@ private function setIntegrationConfig(array $values): array { // so setting `fresh_project_folder_setup` as true if ($runningFullReset) { $this->config->setAppValue(Application::APP_ID, 'fresh_project_folder_setup', "1"); + $this->openprojectAPIService->logToAuditFile( + "OpenProject Integration admin configuration has been reset in application " . Application::APP_ID, true + ); } elseif (key_exists('setup_app_password', $values) && key_exists('setup_project_folder', $values)) { // for other cases when api has key 'setup_app_password' and 'setup_project_folder' we set it to false // assuming user has either fully set the integration or partially without project folder/app password @@ -366,6 +384,15 @@ private function setIntegrationConfig(array $values): array { public function setAdminConfig(array $values): DataResponse { try { $result = $this->setIntegrationConfig($values); + if(key_exists('openproject_client_id', $values) && + key_exists('openproject_client_secret', $values) && + $values['openproject_client_id'] && + $values['openproject_client_secret'] + ) { + $this->openprojectAPIService->logToAuditFile( + "OpenProject OAuth credential has been set in application " . Application::APP_ID + ); + } return new DataResponse($result); } catch (OpenprojectGroupfolderSetupConflictException $e) { return new DataResponse([ @@ -528,7 +555,11 @@ private function storeUserInfo(): array { * @return DataResponse */ public function autoOauthCreation(): DataResponse { - return new DataResponse($this->recreateOauthClientInformation()); + $result = $this->recreateOauthClientInformation(); + $this->openprojectAPIService->logToAuditFile( + "Nextcloud OAuth credential has been set on application " . Application::APP_ID + ); + return new DataResponse($result); } private function deleteOauthClient(): void { diff --git a/lib/Controller/OpenProjectAPIController.php b/lib/Controller/OpenProjectAPIController.php index 1c9b46226..67c2d83ab 100644 --- a/lib/Controller/OpenProjectAPIController.php +++ b/lib/Controller/OpenProjectAPIController.php @@ -547,6 +547,9 @@ public function isValidOpenProjectInstance(string $url): DataResponse { ); return new DataResponse(['result' => 'invalid']); } + $oldOpenProjectOauthUrl = $this->config->getAppValue( + Application::APP_ID, 'openproject_instance_url', '' + ); try { $response = $this->openprojectAPIService->rawRequest( '', $url, '', [], 'GET', @@ -585,6 +588,10 @@ public function isValidOpenProjectInstance(string $url): DataResponse { $decodedBody['_type'] === 'Root' && $decodedBody['instanceName'] !== '' ) { + // sending admin audit log if admin has changed or added the openproject host url + $this->openprojectAPIService->logToAuditFile( + "OpenProject host url has been set to '$url' in application " . Application::APP_ID + ); return new DataResponse(['result' => true]); } } catch (ClientException $e) { @@ -598,6 +605,10 @@ public function isValidOpenProjectInstance(string $url): DataResponse { $decodedBody['_type'] === 'Error' && $decodedBody['errorIdentifier'] !== '' ) { + // sending admin audit log if admin has changed or added the openproject host url + $this->openprojectAPIService->logToAuditFile( + "OpenProject host url has been set to '$url' in application " . Application::APP_ID + ); return new DataResponse(['result' => true]); } $this->logger->error( diff --git a/lib/Service/OpenProjectAPIService.php b/lib/Service/OpenProjectAPIService.php index 64dfc0f5d..71c0a5056 100644 --- a/lib/Service/OpenProjectAPIService.php +++ b/lib/Service/OpenProjectAPIService.php @@ -47,12 +47,17 @@ use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IL10N; +use OCP\ILogger; use OCP\IURLGenerator; use OCP\IUserManager; use OCP\PreConditionNotMetException; use OCP\Security\ISecureRandom; use OCP\Server; +use phpDocumentor\Reflection\Types\This; use Psr\Log\LoggerInterface; +use OCA\AdminAudit\AuditLogger; +use OCP\Log\ILogFactory; + define('CACHE_TTL', 3600); @@ -115,6 +120,7 @@ class OpenProjectAPIService { */ private ISubAdmin $subAdminManager; private IDBConnection $db; + private ILogFactory $logFactory; /** @@ -125,6 +131,8 @@ class OpenProjectAPIService { private IProvider $tokenProvider; private ISecureRandom $random; private IEventDispatcher $eventDispatcher; + private AuditLogger $auditLogger; + public function __construct( string $appName, IAvatarManager $avatarManager, @@ -142,7 +150,8 @@ public function __construct( ISecureRandom $random, IEventDispatcher $eventDispatcher, ISubAdmin $subAdminManager, - IDBConnection $db + IDBConnection $db, + ILogFactory $logFactory, ) { $this->appName = $appName; $this->avatarManager = $avatarManager; @@ -161,6 +170,7 @@ public function __construct( $this->random = $random; $this->eventDispatcher = $eventDispatcher; $this->db = $db; + $this->logFactory = $logFactory; } /** @@ -1070,6 +1080,33 @@ class_exists('\OCA\GroupFolders\Folder\FolderManager') && ); } + /** + * @param $auditLogMessage + * @return void + */ + public function logToAuditFile($auditLogMessage): void { + if($this->isAdminAuditConfigSetCorrectly()) { + $this->auditLogger = new AuditLogger($this->logFactory, $this->config); + $this->auditLogger->info($auditLogMessage, + ['app' => 'admin_audit'] + ); + } + } + + public function isAdminAuditConfigSetCorrectly(): bool { + $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN); + $configAuditFile = $this->config->getSystemValue('logfile_audit', ILogger::WARN); + $logCondition = $this->config->getSystemValue('log.condition', []); + // All the above config should be satisfied in order for admin audit log for the integration application + // if any of the config is failed to be set then we are not able to send the admin audit logging in the audit.log file + return ( + $this->appManager->isInstalled('admin_audit') && + $configAuditFile === $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/audit.log' && + (isset($logCondition["apps"]) && in_array('admin_audit', $logCondition["apps"])) && + $logLevel >= 1 + ); + } + public function isTermsOfServiceAppEnabled(): bool { return ( class_exists('\OCA\TermsOfService\Db\Entities\Signatory') && @@ -1081,6 +1118,8 @@ class_exists('\OCA\TermsOfService\Db\Mapper\TermsMapper') && ); } + + /** * @return array */ @@ -1245,6 +1284,7 @@ public function hasAppPassword(): bool { $tokens = $this->tokenProvider->getTokenByUser(Application::OPEN_PROJECT_ENTITIES_NAME); foreach ($tokens as $token) { if ($token->getName() === Application::OPEN_PROJECT_ENTITIES_NAME) { + $this->logger->info('Application password for user "OpenProject" has been deleted.', ['app' => $this->appName]); return true; } }