Skip to content

Commit 5e982da

Browse files
authored
Merge commit from fork
* Auth: Add method `assertColumnRestrictions` * ObjectSuggestions: Do not suggest protected variables `assertColumnRestrictions` does not allow to use them anymore, hence we should not suggest them in searches as well to not to let the user run into an error by accepting a suggestion. Though, when fetching values as well, we still have to obfuscate, otherwise protected vars won't show up in details anymore. * Introduce Icinga\Module\Icingadb\Common\Model Must be used as base for all models, to ensure column restrictions are asserted on filters. * Utilize `Icinga\Module\Icingadb\Common\Model` where applicable
1 parent cb98b04 commit 5e982da

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+200
-64
lines changed

library/Icingadb/Common/Auth.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Icinga\Authentication\Auth as IcingaAuth;
88
use Icinga\Exception\ConfigurationError;
99
use Icinga\Module\Icingadb\Authentication\ObjectAuthorization;
10+
use Icinga\Security\SecurityException;
1011
use Icinga\Util\StringHelper;
1112
use ipl\Orm\Compat\FilterProcessor;
1213
use ipl\Orm\Model;
@@ -109,6 +110,75 @@ public function isMatchedOn(string $queryString, Model $object): bool
109110
return ObjectAuthorization::matchesOn($queryString, $object);
110111
}
111112

113+
/**
114+
* Assert that the given filter does not contain any column restrictions
115+
*
116+
* @param Filter\Rule $filter The filter to check
117+
*
118+
* @return void
119+
*
120+
* @throws SecurityException
121+
*/
122+
public function assertColumnRestrictions(Filter\Rule $filter): void
123+
{
124+
if ($this->getAuth()->getUser() === null || $this->getAuth()->getUser()->isUnrestricted()) {
125+
return;
126+
}
127+
128+
$forbiddenVars = Filter::all();
129+
$protectedVars = Filter::any();
130+
$hiddenVars = Filter::any();
131+
foreach ($this->getAuth()->getUser()->getRoles() as $role) {
132+
if (($restriction = $role->getRestrictions('icingadb/denylist/variables'))) {
133+
$denied = Filter::none();
134+
$hiddenVars->add($denied);
135+
foreach (explode(',', $restriction) as $value) {
136+
$denied->add(Filter::like('name', trim($value))->ignoreCase());
137+
}
138+
}
139+
140+
if (($restriction = $role->getRestrictions('icingadb/protect/variables'))) {
141+
$protected = Filter::none();
142+
$protectedVars->add($protected);
143+
foreach (explode(',', $restriction) as $value) {
144+
$protected->add(Filter::like('name', trim($value))->ignoreCase());
145+
}
146+
}
147+
}
148+
149+
if (! $hiddenVars->isEmpty()) {
150+
$forbiddenVars->add($hiddenVars);
151+
}
152+
153+
if (! $protectedVars->isEmpty()) {
154+
$forbiddenVars->add($protectedVars);
155+
}
156+
157+
if ($forbiddenVars->isEmpty()) {
158+
return;
159+
}
160+
161+
$checkVars = static function (Filter\Rule $filter) use ($forbiddenVars, &$checkVars) {
162+
if ($filter instanceof Filter\Chain) {
163+
foreach ($filter as $rule) {
164+
$checkVars($rule);
165+
}
166+
} elseif (
167+
! $filter->metaData()->get('_isRestriction', false)
168+
&& preg_match('/^(?:host|service)\.vars\.(.*)/i', $filter->getColumn(), $matches)
169+
) {
170+
if (! Filter::match($forbiddenVars, ['name' => $matches[1]])) {
171+
throw new SecurityException(
172+
'The variable "%s" is not allowed to be queried.',
173+
$matches[1]
174+
);
175+
}
176+
}
177+
};
178+
179+
$checkVars($filter);
180+
}
181+
112182
/**
113183
* Apply Icinga DB Web's restrictions depending on what is queried
114184
*
@@ -333,9 +403,13 @@ function (Filter\Condition $condition) use (
333403
foreach ($allowedColumns as $column) {
334404
if (is_callable($column)) {
335405
if ($column($condition->getColumn())) {
406+
$condition->metaData()->set('_isRestriction', true);
407+
336408
return;
337409
}
338410
} elseif ($column === $condition->getColumn()) {
411+
$condition->metaData()->set('_isRestriction', true);
412+
339413
return;
340414
}
341415
}

library/Icingadb/Common/Model.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/* Icinga DB Web | (c) 2025 Icinga GmbH | GPLv2 */
4+
5+
namespace Icinga\Module\Icingadb\Common;
6+
7+
use ipl\Orm\Query;
8+
use ipl\Sql\Connection;
9+
10+
abstract class Model extends \ipl\Orm\Model
11+
{
12+
public static function on(Connection $db)
13+
{
14+
$query = parent::on($db);
15+
16+
return $query->on(
17+
Query::ON_SELECT_ASSEMBLED,
18+
function () use ($query) {
19+
$auth = new class () {
20+
use Auth;
21+
};
22+
23+
$auth->assertColumnRestrictions($query->getFilter());
24+
}
25+
);
26+
}
27+
}

library/Icingadb/Model/AcknowledgementHistory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
namespace Icinga\Module\Icingadb\Model;
66

77
use DateTime;
8+
use Icinga\Module\Icingadb\Common\Model;
89
use ipl\Orm\Behavior\BoolCast;
910
use ipl\Orm\Behavior\Binary;
1011
use ipl\Orm\Behavior\MillisecondTimestamp;
1112
use ipl\Orm\Behaviors;
12-
use ipl\Orm\Model;
1313
use ipl\Orm\Relations;
1414

1515
/**

library/Icingadb/Model/ActionUrl.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
namespace Icinga\Module\Icingadb\Model;
66

7+
use Icinga\Module\Icingadb\Common\Model;
78
use Icinga\Module\Icingadb\Model\Behavior\ActionAndNoteUrl;
89
use ipl\Orm\Behavior\Binary;
910
use ipl\Orm\Behaviors;
10-
use ipl\Orm\Model;
1111
use ipl\Orm\Relations;
1212

1313
/**

library/Icingadb/Model/Checkcommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
namespace Icinga\Module\Icingadb\Model;
66

7+
use Icinga\Module\Icingadb\Common\Model;
78
use Icinga\Module\Icingadb\Model\Behavior\ReRoute;
89
use ipl\Orm\Behavior\Binary;
910
use ipl\Orm\Behaviors;
10-
use ipl\Orm\Model;
1111
use ipl\Orm\Relations;
1212

1313
/**

library/Icingadb/Model/CheckcommandArgument.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
namespace Icinga\Module\Icingadb\Model;
66

7+
use Icinga\Module\Icingadb\Common\Model;
78
use ipl\Orm\Behavior\Binary;
89
use ipl\Orm\Behaviors;
9-
use ipl\Orm\Model;
1010
use ipl\Orm\Relations;
1111

1212
/**

library/Icingadb/Model/CheckcommandCustomvar.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
namespace Icinga\Module\Icingadb\Model;
66

7+
use Icinga\Module\Icingadb\Common\Model;
78
use ipl\Orm\Behavior\Binary;
89
use ipl\Orm\Behaviors;
9-
use ipl\Orm\Model;
1010
use ipl\Orm\Relations;
1111

1212
/**

library/Icingadb/Model/CheckcommandEnvvar.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use ipl\Orm\Behavior\Binary;
88
use ipl\Orm\Behaviors;
9-
use ipl\Orm\Model;
9+
use Icinga\Module\Icingadb\Common\Model;
1010
use ipl\Orm\Relations;
1111

1212
/**

library/Icingadb/Model/Comment.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use ipl\Orm\Behavior\Binary;
1111
use ipl\Orm\Behavior\MillisecondTimestamp;
1212
use ipl\Orm\Behaviors;
13-
use ipl\Orm\Model;
13+
use Icinga\Module\Icingadb\Common\Model;
1414
use ipl\Orm\Relations;
1515

1616
/**

library/Icingadb/Model/CommentHistory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use ipl\Orm\Behavior\Binary;
1010
use ipl\Orm\Behavior\MillisecondTimestamp;
1111
use ipl\Orm\Behaviors;
12-
use ipl\Orm\Model;
12+
use Icinga\Module\Icingadb\Common\Model;
1313
use ipl\Orm\Relations;
1414

1515
/**

0 commit comments

Comments
 (0)