new: [CLI] admin reencrypt command

pull/7938/head
Jakub Onderka 2021-11-07 17:21:55 +01:00
parent 5569d7d2bf
commit 012b8c4b21
4 changed files with 85 additions and 5 deletions

View File

@ -45,6 +45,15 @@ class AdminShell extends AppShell
],
],
]);
$parser->addSubcommand('reencrypt', [
'help' => __('Reencrypt encrypted values in database (authkeys and sensitive system settings).'),
'parser' => [
'options' => [
'old' => ['help' => __('Old key. If not provided, current key will be used.')],
'new' => ['help' => __('New key. If not provided, new key will be generated.')],
],
],
]);
$parser->addSubcommand('removeOrphanedCorrelations', [
'help' => __('Remove orphaned correlations.'),
]);
@ -891,4 +900,51 @@ class AdminShell extends AppShell
$this->out('Redis: ' . ($newStatus !== '0' ? 'True' : 'False'));
}
}
public function reencrypt()
{
$old = $this->params['old'] ?? null;
$new = $this->params['new'] ?? null;
if ($new !== null && strlen($new) < 32) {
$this->error('New key must be at least 32 char long.');
}
if ($old === null) {
$old = Configure::read('Security.encryption_key');
}
if ($new === null) {
// Generate random new key
$randomTool = new RandomTool();
$new = $randomTool->random_str();
}
$this->Server->getDataSource()->begin();
try {
/** @var SystemSetting $systemSetting */
$systemSetting = ClassRegistry::init('SystemSetting');
$systemSetting->reencrypt($old, $new);
$this->Server->reencryptAuthKeys($old, $new);
/** @var Cerebrate $cerebrate */
$cerebrate = ClassRegistry::init('Cerebrate');
$cerebrate->reencryptAuthKeys($old, $new);
$result = $this->Server->serverSettingsSaveValue('Security.encryption_key', $new, true);
$this->Server->getDataSource()->commit();
if (!$result) {
$this->error('Encrypt key was changed, but it is not possible to save key to config file', __('Please insert new key "%s" to config file manually.', $new));
}
} catch (Exception $e) {
$this->Server->getDataSource()->rollback();
throw $e;
}
$this->out(__('New encryption key "%s" saved into config file.', $new));
}
}

View File

@ -438,7 +438,11 @@ class Cerebrate extends AppModel
$toSave = [];
foreach ($cerebrates as $id => $authkey) {
if (EncryptedValue::isEncrypted($authkey)) {
$authkey = BetterSecurity::decrypt(substr($authkey, 2), $old);
try {
$authkey = BetterSecurity::decrypt(substr($authkey, 2), $old);
} catch (Exception $e) {
throw new Exception("Could not decrypt auth key for Cerebrate #$id", 0, $e);
}
}
if (!empty($new)) {
$authkey = EncryptedValue::ENCRYPTED_MAGIC . BetterSecurity::encrypt($authkey, $new);
@ -448,6 +452,9 @@ class Cerebrate extends AppModel
'authkey' => $authkey,
]];
}
return $this->saveMany($toSave);
if (empty($toSave)) {
return true;
}
return $this->saveMany($toSave, ['validate' => false, 'fields' => ['authkey']]);
}
}

View File

@ -2276,6 +2276,9 @@ class Server extends AppModel
/** @var array $config */
require $configFilePath;
if (!isset($config)) {
throw new Exception("Could not load config file `$configFilePath`.");
}
$config = Hash::insert($config, $setting, $value);
$settingsToSave = array(
@ -4543,7 +4546,11 @@ class Server extends AppModel
$toSave = [];
foreach ($servers as $id => $authkey) {
if (EncryptedValue::isEncrypted($authkey)) {
$authkey = BetterSecurity::decrypt(substr($authkey, 2), $old);
try {
$authkey = BetterSecurity::decrypt(substr($authkey, 2), $old);
} catch (Exception $e) {
throw new Exception("Could not decrypt auth key for server #$id", 0, $e);
}
}
if (!empty($new)) {
$authkey = EncryptedValue::ENCRYPTED_MAGIC . BetterSecurity::encrypt($authkey, $new);
@ -4553,7 +4560,10 @@ class Server extends AppModel
'authkey' => $authkey,
]];
}
return $this->saveMany($toSave);
if (empty($toSave)) {
return true;
}
return $this->saveMany($toSave, ['validate' => false, 'fields' => ['authkey']]);
}
/**

View File

@ -122,7 +122,11 @@ class SystemSetting extends AppModel
continue;
}
if (EncryptedValue::isEncrypted($value)) {
$value = BetterSecurity::decrypt(substr($value, 2), $old);
try {
$value = BetterSecurity::decrypt(substr($value, 2), $old);
} catch (Exception $e) {
throw new Exception("Could not decrypt `$setting` setting.", 0, $e);
}
}
if (!empty($new)) {
$value = EncryptedValue::ENCRYPTED_MAGIC . BetterSecurity::encrypt($value, $new);
@ -132,6 +136,9 @@ class SystemSetting extends AppModel
'value' => $value,
]];
}
if (empty($toSave)) {
return true;
}
return $this->saveMany($toSave);
}