Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ACCESS_ISSUE event for checking issue access #830

Merged
merged 10 commits into from
May 6, 2020
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Upgrading to 3.8.x versions requires that you upgrade to latest 3.5.x version fi
- Catch and log fatal errors if XhguiProfile fails to initialize, #822
- Migrate `SPHINX_SEARCHD_HOST` constant to `setup.php`, #824
- Add Pimple based service container, #826
- Add `ACCESS_ISSUE` event for checking issue access, #830

[3.8.11]: https://github.com/eventum/eventum/compare/v3.8.10...master

Expand Down
36 changes: 36 additions & 0 deletions db/migrations/20200505135053_register_legacy_extensions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/*
* This file is part of the Eventum (Issue Tracking System) package.
*
* @copyright (c) Eventum Team
* @license GNU General Public License, version 2 or later (GPL-2+)
*
* For the full copyright and license information,
* please see the COPYING and AUTHORS files
* that were distributed with this source code.
*/

use Eventum\Db\AbstractMigration;
use Eventum\Extension\Legacy;
use Eventum\Extension\RegisterExtension;

class RegisterLegacyExtensions extends AbstractMigration
{
private const EXTENSIONS = [
Legacy\CustomerLegacyExtension::class,
Legacy\WorkflowLegacyExtension::class,
];

public function up(): void
{
$register = new RegisterExtension();
$register->register(...self::EXTENSIONS);
}

public function down(): void
{
$register = new RegisterExtension();
$register->unregister(...self::EXTENSIONS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/*
* This file is part of the Eventum (Issue Tracking System) package.
*
* @copyright (c) Eventum Team
* @license GNU General Public License, version 2 or later (GPL-2+)
*
* For the full copyright and license information,
* please see the COPYING and AUTHORS files
* that were distributed with this source code.
*/

use Eventum\Db\AbstractMigration;
use Eventum\Extension\AuditTrailExtension;
use Eventum\Extension\RegisterExtension;
use Eventum\ServiceContainer;

class EventumRegisterAuditTrailExtension extends AbstractMigration
{
private const EXTENSION = AuditTrailExtension::class;

public function up(): void
{
$enabled = ServiceContainer::getConfig()['audit_trail'] === 'enabled';
if (!$enabled) {
return;
}

$register = new RegisterExtension();
$register->register(self::EXTENSION);
}

public function down(): void
{
$register = new RegisterExtension();
$register->unregister(self::EXTENSION);
}
}
67 changes: 1 addition & 66 deletions lib/eventum/class.access.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,10 @@ public static function canAccessIssue($issue_id, $usr_id, $log = true)
$return = true;
}

$workflow = Workflow::canAccessIssue($prj_id, $issue_id, $usr_id);
if ($workflow !== null) {
$return = $workflow;
}
$return = Workflow::canAccessIssue($prj_id, $issue_id, $usr_id, $return, !$log);

$access[$issue_id . '-' . $usr_id] = $return;

if ($log) {
self::log($return, $issue_id, $usr_id);
}

return $return;
}

Expand Down Expand Up @@ -658,62 +651,4 @@ public static function getListingSQL($prj_id)

return $sql;
}

/**
* @param int $issue_id
* @param int $usr_id
*/
public static function log($return, $issue_id, $usr_id, $item = null, $item_id = null)
{
if (Setup::get()->get('audit_trail') !== 'enabled') {
return $return;
}

if (is_null($item) && is_null($item_id) && isset($_SERVER['REQUEST_URI'])) {
list($item, $item_id) = self::extractInfoFromURL($_SERVER['REQUEST_URI']);
}
$sql = 'INSERT INTO
`issue_access_log`
SET
alg_iss_id = ?,
alg_usr_id = ?,
alg_created = ?,
alg_ip_address = ?,
alg_failed = ?,
alg_item = ?,
alg_item_id = ?,
alg_url = ?';
$params = [
$issue_id,
$usr_id,
Date_Helper::getCurrentDateGMT(),
$_SERVER['REMOTE_ADDR'] ?? null,
(int) !$return,
$item,
$item_id,
$_SERVER['REQUEST_URI'] ?? null,
];
try {
DB_Helper::getInstance()->query($sql, $params);
} catch (DatabaseException $e) {
// do nothing besides log it
}

return $return;
}

private static function extractInfoFromURL($url)
{
if (preg_match("/view_note\.php\?id=(?P<item_id>\d+)/", $url, $matches)) {
return ['note', $matches[1]];
} elseif (preg_match("/view_email\.php\?ema_id=\d+&id=(?P<item_id>\d+)/", $url, $matches)) {
return ['email', $matches[1]];
} elseif (preg_match("/download\.php\?cat=attachment&id=(?P<item_id>\d+)/", $url, $matches)) {
return ['file', $matches[1]];
} elseif (preg_match("/update\.php/", $url, $matches)) {
return ['update', null];
}

return [null, null];
}
}
24 changes: 14 additions & 10 deletions lib/eventum/class.workflow.php
Original file line number Diff line number Diff line change
Expand Up @@ -974,20 +974,24 @@ public static function getAccessLevels($prj_id)
}

/**
* Performs additional checks on if a user can access an issue.
* Returns true if a user can access an issue.
*
* @param $prj_id
* @param $issue_id
* @param $usr_id
* @return mixed null to use default rules, true or false otherwise
* @deprecated since 3.8.11 use ACCESS_ISSUE event
*/
public static function canAccessIssue($prj_id, $issue_id, $usr_id)
public static function canAccessIssue(int $prj_id, int $issue_id, int $usr_id, bool $return, bool $internal): bool
{
if (!$backend = self::getBackend($prj_id)) {
return null;
}
$arguments = [
'prj_id' => $prj_id,
'issue_id' => $issue_id,
'usr_id' => $usr_id,
// if it's internal call. i.e called from canViewInternalNotes
'internal' => $internal,
];
$event = new ResultableEvent(null, $arguments);
$event->setResult($return);
EventManager::dispatch(SystemEvents::ACCESS_ISSUE, $event);

return $backend->canAccessIssue($prj_id, $issue_id, $usr_id);
return $event->getResult();
}

/**
Expand Down
3 changes: 3 additions & 0 deletions lib/eventum/workflow/class.abstract_workflow_backend.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
/**
* Abstract Class that all workflow backends should extend. This is so any new
* workflow methods added in future releases will not break current backends.
*
* @deprecated use Extension events instead
*/
abstract class Abstract_Workflow_Backend
{
Expand Down Expand Up @@ -609,6 +611,7 @@ public function getAccessLevels($prj_id)
* @param $issue_id
* @param $usr_id
* @return mixed null to use default rules, true or false otherwise
* @deprecated since 3.8.11 use ACCESS_ISSUE event
*/
public function canAccessIssue($prj_id, $issue_id, $usr_id)
{
Expand Down
10 changes: 9 additions & 1 deletion src/Controller/Manage/GeneralController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
namespace Eventum\Controller\Manage;

use Eventum\Controller\Helper\MessagesHelper;
use Eventum\Extension\AuditTrailExtension;
use Eventum\Extension\RegisterExtension;
use Project;
use Setup;
use User;
Expand Down Expand Up @@ -44,7 +46,7 @@ protected function configure(): void
*/
protected function defaultAction(): void
{
if ($this->cat == 'update') {
if ($this->cat === 'update') {
$this->updateAction();
}
}
Expand Down Expand Up @@ -81,6 +83,12 @@ private function updateAction(): void
'audit_trail' => $post->get('audit_trail'),
];
$res = Setup::save($setup);

// audit trail is an extension, enable disable extension
$enabled = $setup['audit_trail'] === 'enabled';
$register = new RegisterExtension();
$register->enable(AuditTrailExtension::class, $enabled);

$this->tpl->assign('result', $res);

$setupFile = Setup::getSetupFile();
Expand Down
6 changes: 6 additions & 0 deletions src/Event/SystemEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ final class SystemEvents
*/
public const ISSUE_LINK_FILTERS = 'issue.link.filters';

/**
* @since 3.8.11
* @see Workflow::canAccessIssue()
*/
public const ACCESS_ISSUE = 'access.issue';

/**
* @since 3.5.0
* @see Workflow::handleNewNote()
Expand Down
103 changes: 103 additions & 0 deletions src/Extension/AuditTrailExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

/*
* This file is part of the Eventum (Issue Tracking System) package.
*
* @copyright (c) Eventum Team
* @license GNU General Public License, version 2 or later (GPL-2+)
*
* For the full copyright and license information,
* please see the COPYING and AUTHORS files
* that were distributed with this source code.
*/

namespace Eventum\Extension;

use Date_Helper;
use DB_Helper;
use Eventum\Db\DatabaseException;
use Eventum\Event\ResultableEvent;
use Eventum\Event\SystemEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AuditTrailExtension implements Provider\SubscriberProvider, EventSubscriberInterface
{
public function getSubscribers(): array
{
return [
self::class,
];
}

public static function getSubscribedEvents(): array
{
return [
/** @see AuditTrailExtension::canAccessIssue */
// This should be with lowest priority to log final result
SystemEvents::ACCESS_ISSUE => ['canAccessIssue', PHP_INT_MIN],
];
}

/**
* @see Workflow::canAccessIssue
*/
public function canAccessIssue(ResultableEvent $event): void
{
if (!$event['internal']) {
$this->log($event->getResult(), $event['issue_id'], $event['usr_id'], $_SERVER['REQUEST_URI'] ?? '');
}
}

private function log(bool $return, int $issue_id, int $usr_id, string $url): void
{
[$item, $item_id] = $this->extractInfoFromURL($url);

$sql = 'INSERT INTO
`issue_access_log`
SET
alg_iss_id = ?,
alg_usr_id = ?,
alg_created = ?,
alg_ip_address = ?,
alg_failed = ?,
alg_item = ?,
alg_item_id = ?,
alg_url = ?';
$params = [
$issue_id,
$usr_id,
Date_Helper::getCurrentDateGMT(),
$_SERVER['REMOTE_ADDR'] ?? null,
(int)!$return,
$item,
$item_id,
$url,
];
try {
DB_Helper::getInstance()->query($sql, $params);
} catch (DatabaseException $e) {
// do nothing besides log it
}
}

private function extractInfoFromURL(string $url)
{
if (preg_match("/view_note\.php\?id=(?P<item_id>\d+)/", $url, $matches)) {
return ['note', $matches[1]];
}

if (preg_match("/view_email\.php\?ema_id=\d+&id=(?P<item_id>\d+)/", $url, $matches)) {
return ['email', $matches[1]];
}

if (preg_match("/download\.php\?cat=attachment&id=(?P<item_id>\d+)/", $url, $matches)) {
return ['file', $matches[1]];
}

if (preg_match("/update\.php/", $url, $matches)) {
return ['update', null];
}

return [null, null];
}
}
28 changes: 28 additions & 0 deletions src/Extension/Legacy/CustomerLegacyExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/*
* This file is part of the Eventum (Issue Tracking System) package.
*
* @copyright (c) Eventum Team
* @license GNU General Public License, version 2 or later (GPL-2+)
*
* For the full copyright and license information,
* please see the COPYING and AUTHORS files
* that were distributed with this source code.
*/

namespace Eventum\Extension\Legacy;

use Eventum\Extension\Provider;

/**
* Extension that adds integration of legacy Customer classes to Extension events
*/
class CustomerLegacyExtension implements Provider\SubscriberProvider
{
public function getSubscribers(): array
{
return [
];
}
}