Skip to content

Commit d44418c

Browse files
committed
Allow restricting reports by name & author
1 parent 971c7e9 commit d44418c

File tree

6 files changed

+97
-6
lines changed

6 files changed

+97
-6
lines changed

application/controllers/ReportController.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ public function init()
3535

3636
$report = Model\Report::on($this->getDb())
3737
->with(['timeframe'])
38-
->filter(Filter::equal('id', $reportId))
39-
->first();
38+
->filter(Filter::equal('id', $reportId));
4039

40+
$this->applyRestrictions($report);
41+
42+
$report = $report->first();
4143
if ($report === null) {
4244
$this->httpNotFound($this->translate('Report not found'));
4345
}

application/controllers/ReportsController.php

+6-4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public function indexAction()
4343
$reports = Report::on($this->getDb())
4444
->withColumns(['report.timeframe.name']);
4545

46+
$this->applyRestrictions($reports);
47+
4648
$sortControl = $this->createSortControl(
4749
$reports,
4850
[
@@ -64,16 +66,16 @@ public function indexAction()
6466
Html::tag('td', null, $report->timeframe->name),
6567
Html::tag('td', null, $report->ctime->format('Y-m-d H:i')),
6668
Html::tag('td', null, $report->mtime->format('Y-m-d H:i')),
67-
Html::tag('td', ['class' => 'icon-col'], [
68-
new Link(
69+
! $this->hasPermission('reporting/reports')
70+
? null
71+
: Html::tag('td', ['class' => 'icon-col'], new Link(
6972
new Icon('edit'),
7073
Url::fromPath('reporting/report/edit', ['id' => $report->id]),
7174
[
7275
'data-icinga-modal' => true,
7376
'data-no-icinga-ajax' => true
7477
]
75-
)
76-
])
78+
))
7779
]);
7880
}
7981

configuration.php

+5
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@
5050
'reporting/timeframes',
5151
$this->translate('Allow managing timeframes')
5252
);
53+
54+
$this->provideRestriction(
55+
'reporting/filter/reports',
56+
$this->translate('Restrict access to the reports that match the provided filter')
57+
);
5358
}

doc/03-Configuration.md

+13
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,16 @@ reporting/reports | Reports (create, edit, delete)
3131
reporting/schedules | Schedules (create, edit, delete)
3232
reporting/templates | Templates (create, edit, delete)
3333
reporting/timeframes | Timeframes (create, edit, delete)
34+
35+
## Restrictions
36+
37+
Icinga Reporting currently provides a single restriction that can be used to limit users to a specific set of reports,
38+
while having the `reporting/reports` permission.
39+
40+
> **Note:**
41+
>
42+
> Filters from multiple roles will expand the available access.
43+
44+
| Name | Description |
45+
|--------------------------|---------------------------------------------------------------|
46+
| reporting/filter/reports | Restrict access to the reports that match the provided filter |

library/Reporting/Common/Auth.php

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/* Icinga Reporting | (c) 2023 Icinga GmbH | GPLv2 */
4+
5+
namespace Icinga\Module\Reporting\Common;
6+
7+
use Icinga\Authentication\Auth as IcingaAuth;
8+
use Icinga\Exception\ConfigurationError;
9+
use ipl\Orm\Query;
10+
use ipl\Stdlib\Filter;
11+
use ipl\Web\Filter\QueryString;
12+
13+
trait Auth
14+
{
15+
/**
16+
* Apply restrictions of this module
17+
*
18+
* @param Query $query
19+
*/
20+
protected function applyRestrictions(Query $query): void
21+
{
22+
$auth = IcingaAuth::getInstance();
23+
$restrictions = $auth->getRestrictions('reporting/filter/reports');
24+
25+
$queryFilter = Filter::any();
26+
// Don't filter out reports created by the current user!
27+
$queryFilter->add(Filter::equal('author', $auth->getUser()->getUsername()));
28+
29+
foreach ($restrictions as $restriction) {
30+
$queryFilter->add($this->parseRestriction($restriction, 'reporting/filter/reports'));
31+
}
32+
33+
$query->filter($queryFilter);
34+
}
35+
36+
/**
37+
* Parse the query string of the given restriction
38+
*
39+
* @param string $queryString
40+
* @param string $restriction
41+
*
42+
* @return Filter\Rule
43+
*/
44+
protected function parseRestriction(string $queryString, string $restriction): Filter\Rule
45+
{
46+
return QueryString::fromString($queryString)
47+
->on(
48+
QueryString::ON_CONDITION,
49+
function (Filter\Condition $condition) use ($restriction, $queryString) {
50+
$allowedColumns = ['report.name', 'report.author'];
51+
if (in_array($condition->getColumn(), $allowedColumns, true)) {
52+
return;
53+
}
54+
55+
throw new ConfigurationError(
56+
t(
57+
'Cannot apply restriction %s using the filter %s.'
58+
. ' You can only use the following columns: %s'
59+
),
60+
$restriction,
61+
$queryString,
62+
implode(', ', $allowedColumns)
63+
);
64+
}
65+
)->parse();
66+
}
67+
}

library/Reporting/Web/Controller.php

+2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
namespace Icinga\Module\Reporting\Web;
66

7+
use Icinga\Module\Reporting\Common\Auth;
78
use ipl\Web\Compat\CompatController;
89

910
class Controller extends CompatController
1011
{
12+
use Auth;
1113
}

0 commit comments

Comments
 (0)