From 82f13803aa6438c9b35b4e7e93d9b5530299387f Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Tue, 10 Oct 2023 18:19:08 +0200 Subject: [PATCH] Migrate oc_storages for other auth backend Signed-off-by: Louis Chemineau --- apps/files_external/lib/Command/MigrateOc.php | 195 ++++++++++++------ 1 file changed, 136 insertions(+), 59 deletions(-) diff --git a/apps/files_external/lib/Command/MigrateOc.php b/apps/files_external/lib/Command/MigrateOc.php index 5b9a3cc12986d..01f63589d8a42 100644 --- a/apps/files_external/lib/Command/MigrateOc.php +++ b/apps/files_external/lib/Command/MigrateOc.php @@ -62,68 +62,131 @@ protected function configure(): void { } protected function execute(InputInterface $input, OutputInterface $output): int { - $configs = $this->getWndConfigs(); $dryRun = $input->getOption('dry-run'); - $output->writeln("Found " . count($configs) . " wnd storages"); + $this->migrateStorageConfigPasswords($dryRun, $output); + $this->migrateStorageCredentials($dryRun, $output); + $this->migrateWndStorage($dryRun, $output); + $this->migrateWndExternalStorages($dryRun, $output); - foreach ($configs as $config) { - if (!isset($config['user'])) { - $output->writeln("Only basic username password authentication is currently supported"); - return 1; - } + return 0; + } - if (isset($config['root']) && $config['root'] !== '' && $config['root'] !== '/') { - $root = '/' . trim($config['root'], '/') . '/'; - } else { - $root = '/'; - } + private function migrateWndStorage(bool $dryRun, OutputInterface $output): void { + $configs = $this->getWndExternalStorageConfigs(); + $output->writeln("Found " . count($configs) . " wnd storages"); - if (isset($config['domain']) && $config['domain'] !== "" - && \strpos($config['user'], "\\") === false && \strpos($config['user'], "/") === false - ) { - $usernameWithDomain = $config['domain'] . "\\" . $config['user']; - } else { - $usernameWithDomain = $config['user']; - } - $wndStorageId = "wnd::{$usernameWithDomain}@{$config['host']}/{$config['share']}/{$root}"; - - $storage = new SMB($config); - $storageId = $storage->getId(); - if (!$dryRun) { - if (!$this->setStorageId($wndStorageId, $storageId)) { - $output->writeln("No WMD storage with id $wndStorageId found"); - return 1; - } + foreach ($configs as $config) { + $output->writeln("" . $config['host'] . ' - ' . $config['auth_backend'] . ""); + + switch($config['auth_backend']) { + case 'password::password': + $this->migrateWndStorageWithCredentials($dryRun, $output, $config); + break; + case 'password::sessioncredentials': + // Impossible to do as credentials are stored in memory. + $output->writeln(" Cannot migrate storages authenticated by sessions credentials"); + break; + case 'password::logincredentials': + $sessionCredentials = $this->getStorageCredentialsWithIdentifier($config['auth_backend'].'/credentials'); + foreach ($sessionCredentials as $credentials) { + $config['user'] = $credentials['user']; + $config['password'] = $credentials['password']; + $this->migrateWndStorageWithCredentials($dryRun, $output, $config); + } + break; + case 'password::userprovided': + $sessionCredentials = $this->getStorageCredentialsWithIdentifier($config['auth_backend'].'/'.$config['mount_id']); + foreach ($sessionCredentials as $credentials) { + $config['user'] = $credentials['user']; + $config['password'] = $credentials['password']; + $this->migrateWndStorageWithCredentials($dryRun, $output, $config); + } + break; + case 'password::global': + $sessionCredentials = $this->getStorageCredentialsWithIdentifier($config['auth_backend']); + foreach ($sessionCredentials as $credentials) { + $config['user'] = $credentials['user']; + $config['password'] = $credentials['password']; + $this->migrateWndStorageWithCredentials($dryRun, $output, $config); + } + break; + case 'password::hardcodedconfigcredentials': + $output->writeln(" Cannot migrate storages authenticated by hard coded credentials"); + break; + case 'kerberos::kerberos': + // Impossible to do as credentials are stored in memory. + $output->writeln(" Cannot migrate storages authenticated by kerberos"); + continue 2; + break; + default: + echo "UNSUPPORTED AUTH BACKEND !"; + continue 2; } } + } - if (count($configs) && !$dryRun) { - $this->migrateWndBackend(); + private function migrateWndStorageWithCredentials(bool $dryRun, OutputInterface $output, array $config): void { + if (isset($config['root']) && $config['root'] !== '' && $config['root'] !== '/') { + $root = '/' . trim($config['root'], '/') . '/'; + } else { + $root = '/'; + } - $output->writeln("Successfully migrated"); + if (isset($config['domain']) && $config['domain'] !== "" + && \strpos($config['user'], "\\") === false && \strpos($config['user'], "/") === false + ) { + $usernameWithDomain = $config['domain'] . "\\" . $config['user']; + } else { + $usernameWithDomain = $config['user']; } + $wndStorageId = "wnd::{$usernameWithDomain}@{$config['host']}/{$config['share']}/{$root}"; - $this->migrateV2StoragePasswords($dryRun, $output); - $this->migrateUserCredentials($dryRun, $output); + $storage = new SMB($config); + $storageId = $storage->getId(); - return 0; + $query = $this->connection->getQueryBuilder(); + $rowCount = $query->select('id') + ->from('storages') + ->where($query->expr()->eq('id', $query->createNamedParameter($wndStorageId))) + ->executeQuery() + ->rowCount(); + + if ($rowCount === 1) { + $output->writeln(" - Found one storage $wndStorageId"); + if (!$dryRun && !$this->setStorageId($wndStorageId, $storageId)) { + $output->writeln("Failed to update WMD storage with id $wndStorageId"); + } + } elseif ($rowCount > 1) { + $output->writeln("More than one storage found $wndStorageId"); + } } - private function migrateWndBackend(): int { + private function migrateWndExternalStorages(bool $dryRun, OutputInterface $output): void { $query = $this->connection->getQueryBuilder(); - $query->update('external_mounts') - ->set('storage_backend', $query->createNamedParameter('smb')) - ->where($query->expr()->eq('storage_backend', $query->createNamedParameter('windows_network_drive'))); - return $query->executeStatement(); + $rowCount = $query->select('mount_id') + ->from('external_mounts') + ->where($query->expr()->eq('storage_backend', $query->createNamedParameter('windows_network_drive'))) + ->executeQuery() + ->rowCount(); + + $output->writeln("Found " . $rowCount . " wnd external storages"); + + if ($rowCount > 0 && !$dryRun) { + $query = $this->connection->getQueryBuilder(); + $query->update('external_mounts') + ->set('storage_backend', $query->createNamedParameter('smb')) + ->where($query->expr()->eq('storage_backend', $query->createNamedParameter('windows_network_drive'))) + ->executeStatement(); + } } /** * @return array> */ - private function getWndConfigs(): array { + private function getWndExternalStorageConfigs(): array { $query = $this->connection->getQueryBuilder(); - $query->select('c.mount_id', 'key', 'value') + $query->select('c.mount_id', 'key', 'value', 'm.auth_backend') ->from('external_config', 'c') ->innerJoin('c', 'external_mounts', 'm', $query->expr()->eq('c.mount_id', 'm.mount_id')) ->where($query->expr()->eq('storage_backend', $query->createNamedParameter('windows_network_drive'))); @@ -134,6 +197,8 @@ private function getWndConfigs(): array { $mountId = (int)$row['mount_id']; if (!isset($configs[$mountId])) { $configs[$mountId] = []; + $configs[$mountId]['mount_id'] = $row['mount_id']; + $configs[$mountId]['auth_backend'] = $row['auth_backend']; } $configs[$mountId][$row['key']] = $row['value']; } @@ -143,7 +208,7 @@ private function getWndConfigs(): array { /** * @return array */ - private function getV2StoragePasswords(): array { + private function getStorageConfigPasswords(): array { $query = $this->connection->getQueryBuilder(); $query->select('config_id', 'value') ->from('external_config') @@ -158,11 +223,11 @@ private function getV2StoragePasswords(): array { return $configs; } - private function migrateV2StoragePasswords(bool $dryRun, OutputInterface $output): void { - $passwords = $this->getV2StoragePasswords(); + private function migrateStorageConfigPasswords(bool $dryRun, OutputInterface $output): void { + $passwords = $this->getStorageConfigPasswords(); + $output->writeln("Found " . count($passwords) . " config passwords that need re-encoding"); if (count($passwords)) { - $output->writeln("Found " . count($passwords) . " stored passwords that need re-encoding"); foreach ($passwords as $id => $password) { $decoded = $this->decodePassword($password); if (!$dryRun) { @@ -183,37 +248,49 @@ private function setStorageConfig(int $id, string $value): void { /** * @return array> */ - private function getUserCredentials(): array { + private function getStorageCredentials(): array { $query = $this->connection->getQueryBuilder(); - $query->select('user', 'identifier', 'credentials') - ->from('credentials'); + $query->select('id', 'user', 'identifier', 'credentials') + ->from('storages_credentials') + ->where($query->expr()->like('credentials', $query->createNamedParameter('v2|%'))); return $query->executeQuery()->fetchAll(); } - private function migrateUserCredentials(bool $dryRun, OutputInterface $output): void { - $passwords = $this->getUserCredentials(); + /** + * @return array> + */ + private function getStorageCredentialsWithIdentifier(string $identifier): array { + $query = $this->connection->getQueryBuilder(); + $query->select('credentials') + ->from('storages_credentials') + ->where($query->expr()->eq('identifier', $query->createNamedParameter($identifier))); + + $rows = $query->executeQuery()->fetchAll(); + + return array_map(fn ($row): string => json_decode($this->crypto->decrypt($row['credentials']), true), $rows); + } + + private function migrateStorageCredentials(bool $dryRun, OutputInterface $output): void { + $passwords = $this->getStorageCredentials(); + $output->writeln("Found " . count($passwords) . " stored credentials that need re-encoding"); if (count($passwords)) { - $output->writeln("Found " . count($passwords) . " stored user credentials that need re-encoding"); foreach ($passwords as $passwordRow) { $decoded = $this->decodePassword($passwordRow["credentials"]); if (!$dryRun) { - $this->setStorageCredentials($passwordRow, $this->encryptPassword($decoded)); + $this->setStorageCredentials($passwordRow['id'], $this->encryptPassword($decoded)); } } } } - private function setStorageCredentials(array $row, string $encryptedPassword): void { + private function setStorageCredentials(string $id, string $encryptedPassword): void { $query = $this->connection->getQueryBuilder(); - $query->insert('storages_credentials') - ->values([ - 'user' => $query->createNamedParameter($row['user']), - 'identifier' => $query->createNamedParameter($row['identifier']), - 'credentials' => $query->createNamedParameter($encryptedPassword), - ]) + $query->update('storages_credentials') + ->set('credentials', $query->createNamedParameter($encryptedPassword)) + ->where($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT))) ->executeStatement(); }