Skip to content

Commit

Permalink
Migrate oc_storages for other auth backend
Browse files Browse the repository at this point in the history
Signed-off-by: Louis Chemineau <[email protected]>
  • Loading branch information
artonge committed Oct 11, 2023
1 parent d7ce6de commit f96abd5
Showing 1 changed file with 136 additions and 59 deletions.
195 changes: 136 additions & 59 deletions apps/files_external/lib/Command/MigrateOc.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 <info>" . count($configs) . "</info> 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("<error>Only basic username password authentication is currently supported</error>");
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 <info>" . count($configs) . "</info> 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("<error>No WMD storage with id $wndStorageId found</error>");
return 1;
}
foreach ($configs as $config) {
$output->writeln("<info>" . $config['host'] . ' - ' . $config['auth_backend'] . "</info>");

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(" <error>Cannot migrate storages authenticated by sessions credentials</error>");
break;
case 'password::logincredentials':
$sessionCredentials = $this->getStorageCredentialsWithIdentifier($config['auth_backend'].'/credentials');
foreach ($sessionCredentials as $credentials) {
$config['user'] = $credentials['user'];

Check failure on line 93 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidArrayOffset

apps/files_external/lib/Command/MigrateOc.php:93:25: InvalidArrayOffset: Cannot access value on variable $credentials using offset value of 'user', expecting int (see https://psalm.dev/115)

Check failure on line 93 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / Psalm

Cannot access value on variable $credentials using offset value of 'user', expecting int (see https://psalm.dev/115)

Check failure

Code scanning / Psalm

InvalidArrayOffset Error

Cannot access value on variable $credentials using offset value of 'user', expecting int
$config['password'] = $credentials['password'];

Check failure on line 94 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidArrayOffset

apps/files_external/lib/Command/MigrateOc.php:94:29: InvalidArrayOffset: Cannot access value on variable $credentials using offset value of 'password', expecting int (see https://psalm.dev/115)

Check failure on line 94 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / Psalm

Cannot access value on variable $credentials using offset value of 'password', expecting int (see https://psalm.dev/115)

Check failure

Code scanning / Psalm

InvalidArrayOffset Error

Cannot access value on variable $credentials using offset value of 'password', expecting int
$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'];

Check failure on line 101 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidArrayOffset

apps/files_external/lib/Command/MigrateOc.php:101:25: InvalidArrayOffset: Cannot access value on variable $credentials using offset value of 'user', expecting int (see https://psalm.dev/115)

Check failure on line 101 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / Psalm

Cannot access value on variable $credentials using offset value of 'user', expecting int (see https://psalm.dev/115)

Check failure

Code scanning / Psalm

InvalidArrayOffset Error

Cannot access value on variable $credentials using offset value of 'user', expecting int
$config['password'] = $credentials['password'];

Check failure on line 102 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidArrayOffset

apps/files_external/lib/Command/MigrateOc.php:102:29: InvalidArrayOffset: Cannot access value on variable $credentials using offset value of 'password', expecting int (see https://psalm.dev/115)

Check failure on line 102 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / Psalm

Cannot access value on variable $credentials using offset value of 'password', expecting int (see https://psalm.dev/115)

Check failure

Code scanning / Psalm

InvalidArrayOffset Error

Cannot access value on variable $credentials using offset value of 'password', expecting int
$this->migrateWndStorageWithCredentials($dryRun, $output, $config);
}
break;
case 'password::global':
$sessionCredentials = $this->getStorageCredentialsWithIdentifier($config['auth_backend']);
foreach ($sessionCredentials as $credentials) {
$config['user'] = $credentials['user'];

Check failure on line 109 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidArrayOffset

apps/files_external/lib/Command/MigrateOc.php:109:25: InvalidArrayOffset: Cannot access value on variable $credentials using offset value of 'user', expecting int (see https://psalm.dev/115)

Check failure on line 109 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / Psalm

Cannot access value on variable $credentials using offset value of 'user', expecting int (see https://psalm.dev/115)

Check failure

Code scanning / Psalm

InvalidArrayOffset Error

Cannot access value on variable $credentials using offset value of 'user', expecting int
$config['password'] = $credentials['password'];

Check failure on line 110 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidArrayOffset

apps/files_external/lib/Command/MigrateOc.php:110:29: InvalidArrayOffset: Cannot access value on variable $credentials using offset value of 'password', expecting int (see https://psalm.dev/115)

Check failure on line 110 in apps/files_external/lib/Command/MigrateOc.php

View workflow job for this annotation

GitHub Actions / Psalm

Cannot access value on variable $credentials using offset value of 'password', expecting int (see https://psalm.dev/115)

Check failure

Code scanning / Psalm

InvalidArrayOffset Error

Cannot access value on variable $credentials using offset value of 'password', expecting int
$this->migrateWndStorageWithCredentials($dryRun, $output, $config);
}
break;
case 'password::hardcodedconfigcredentials':
$output->writeln(" <error>Cannot migrate storages authenticated by hard coded credentials</error>");
break;
case 'kerberos::kerberos':
// Impossible to do as credentials are stored in memory.
$output->writeln(" <error>Cannot migrate storages authenticated by kerberos</error>");
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) {

Check notice

Code scanning / Psalm

MissingReturnType Note

Method OCA\Files_External\Command\MigrateOc::migrateWndStorageWithCredentials does not have a return type, expecting 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("<error>Failed to update WMD storage with id $wndStorageId</error>");
}
} elseif ($rowCount > 1) {
$output->writeln("<error>More than one storage found $wndStorageId</error>");
}
}

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 <info>" . $rowCount . "</info> 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<int, array<string, string>>
*/
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')));
Expand All @@ -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'];
}
Expand All @@ -143,7 +208,7 @@ private function getWndConfigs(): array {
/**
* @return array<int, string>
*/
private function getV2StoragePasswords(): array {
private function getStorageConfigPasswords(): array {
$query = $this->connection->getQueryBuilder();
$query->select('config_id', 'value')
->from('external_config')
Expand All @@ -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 <info>" . count($passwords) . "</info> config passwords that need re-encoding");

if (count($passwords)) {
$output->writeln("Found <info>" . count($passwords) . "</info> stored passwords that need re-encoding");
foreach ($passwords as $id => $password) {
$decoded = $this->decodePassword($password);
if (!$dryRun) {
Expand All @@ -183,37 +248,49 @@ private function setStorageConfig(int $id, string $value): void {
/**
* @return array<array<string, string>>
*/
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<string>
*/
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) => json_decode($this->crypto->decrypt($row['credentials']), true), $rows);

Check notice

Code scanning / Psalm

MissingClosureReturnType Note

Closure does not have a return type, expecting mixed
}

private function migrateStorageCredentials(bool $dryRun, OutputInterface $output): void {
$passwords = $this->getStorageCredentials();
$output->writeln("Found <info>" . count($passwords) . "</info> stored credentials that need re-encoding");

if (count($passwords)) {
$output->writeln("Found <info>" . count($passwords) . "</info> 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();
}

Expand Down

0 comments on commit f96abd5

Please sign in to comment.