Skip to content

Commit e62725a

Browse files
committed
If one enables to store roles in the database for the first time, migrate them
This prevents the admin from breaking Icinga Web with one checkbox.
1 parent eb97af8 commit e62725a

File tree

1 file changed

+121
-2
lines changed

1 file changed

+121
-2
lines changed

application/controllers/ConfigController.php

+121-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33

44
namespace Icinga\Controllers;
55

6+
use DateTime;
67
use Exception;
78
use Icinga\Application\Version;
9+
use Icinga\Common\Database;
10+
use Icinga\Forms\Security\RoleForm;
11+
use Icinga\Model\Role;
12+
use Icinga\Util\StringHelper;
813
use InvalidArgumentException;
914
use Icinga\Application\Config;
1015
use Icinga\Application\Icinga;
@@ -23,12 +28,18 @@
2328
use Icinga\Web\Notification;
2429
use Icinga\Web\Url;
2530
use Icinga\Web\Widget;
31+
use ipl\Sql\Connection;
32+
use ipl\Sql\Insert;
33+
use ipl\Sql\Select;
34+
use ipl\Sql\Update;
2635

2736
/**
2837
* Application and module configuration
2938
*/
3039
class ConfigController extends Controller
3140
{
41+
use Database;
42+
3243
/**
3344
* Create and return the tabs to display when showing application configuration
3445
*/
@@ -99,13 +110,21 @@ public function generalAction()
99110
$form->setOnSuccess(function (GeneralConfigForm $form) {
100111
$config = Config::app();
101112
$useStrictCsp = (bool) $config->get('security', 'use_strict_csp', false);
113+
$storeRolesInDb = (bool) $config->get('global', 'store_roles_in_db', false);
102114
if ($form->onSuccess() === false) {
103115
return false;
104116
}
105117

106118
$appConfigForm = $form->getSubForm('form_config_general_application');
107-
if ($appConfigForm && (bool) $appConfigForm->getValue('security_use_strict_csp') !== $useStrictCsp) {
108-
$this->getResponse()->setReloadWindow(true);
119+
120+
if ($appConfigForm) {
121+
if ((bool) $appConfigForm->getValue('security_use_strict_csp') !== $useStrictCsp) {
122+
$this->getResponse()->setReloadWindow(true);
123+
}
124+
125+
if (! $storeRolesInDb && $appConfigForm->getValue('global_store_roles_in_db')) {
126+
$this->migrateRolesToFreshDb();
127+
}
109128
}
110129
})->handleRequest();
111130

@@ -114,6 +133,106 @@ public function generalAction()
114133
$this->createApplicationTabs()->activate('general');
115134
}
116135

136+
/**
137+
* Migrate roles.ini to database if the latter contains no roles
138+
*/
139+
private function migrateRolesToFreshDb(): void
140+
{
141+
$roles = Config::app('roles');
142+
$now = (new DateTime())->getTimestamp() * 1000;
143+
144+
$this->getDb()->transaction(function (Connection $db) use ($roles, $now) {
145+
if (Role::on($db)->columns('id')->first()) {
146+
return;
147+
}
148+
149+
foreach ($roles as $name => $role) {
150+
$db->prepexec(
151+
(new Insert())
152+
->into('icingaweb_role')
153+
->columns(['name', 'unrestricted', 'ctime'])
154+
->values([$name, $role->unrestricted ? 'y' : 'n', $now])
155+
);
156+
157+
$id = $db->lastInsertId();
158+
$permissions = StringHelper::trimSplit($role->permissions);
159+
$refusals = StringHelper::trimSplit($role->refusals);
160+
$permissionsAndRefusals = [];
161+
162+
foreach (StringHelper::trimSplit($role->users) as $user) {
163+
$db->prepexec(
164+
(new Insert())
165+
->into('icingaweb_role_user')
166+
->columns(['role_id', 'user_name'])
167+
->values([$id, $user])
168+
);
169+
}
170+
171+
foreach (StringHelper::trimSplit($role->groups) as $group) {
172+
$db->prepexec(
173+
(new Insert())
174+
->into('icingaweb_role_group')
175+
->columns(['role_id', 'group_name'])
176+
->values([$id, $group])
177+
);
178+
}
179+
180+
foreach ([$permissions, $refusals] as $permissionsOrRefusals) {
181+
foreach ($permissionsOrRefusals as $permissionOrRefusal) {
182+
$permissionsAndRefusals[$permissionOrRefusal] = ['allowed' => 'n', 'denied' => 'n'];
183+
}
184+
}
185+
186+
foreach ($permissions as $permission) {
187+
$permissionsAndRefusals[$permission]['allowed'] = 'y';
188+
}
189+
190+
foreach ($refusals as $refusal) {
191+
$permissionsAndRefusals[$refusal]['denied'] = 'y';
192+
}
193+
194+
foreach ($permissionsAndRefusals as $permission => $authz) {
195+
$db->prepexec(
196+
(new Insert())
197+
->into('icingaweb_role_permission')
198+
->columns(['role_id', 'permission', 'allowed', 'denied'])
199+
->values([$id, $permission, $authz['allowed'], $authz['denied']])
200+
);
201+
}
202+
203+
foreach (RoleForm::collectProvidedPrivileges()[1] as $restrictionList) {
204+
foreach ($restrictionList as $restriction => $_) {
205+
if (isset($role->$restriction)) {
206+
$db->prepexec(
207+
(new Insert())
208+
->into('icingaweb_role_restriction')
209+
->columns(['role_id', 'restriction', 'filter'])
210+
->values([$id, $restriction, $role->$restriction])
211+
);
212+
}
213+
}
214+
}
215+
}
216+
217+
foreach ($roles as $name => $role) {
218+
if (isset($role->parent)) {
219+
$db->prepexec(
220+
(new Update())
221+
->table('icingaweb_role')
222+
->set([
223+
'parent_id' => (new Select())
224+
->from('icingaweb_role')
225+
->where(['name = ?' => $role->parent])
226+
->columns(['id'])
227+
,
228+
])
229+
->where(['name = ?' => $name])
230+
);
231+
}
232+
}
233+
});
234+
}
235+
117236
/**
118237
* Display the list of all modules
119238
*/

0 commit comments

Comments
 (0)