summaryrefslogtreecommitdiffstats
path: root/apps/user_ldap/lib/Migration
diff options
context:
space:
mode:
authorArthur Schiwon <blizzz@arthur-schiwon.de>2022-02-02 18:10:10 +0100
committerCôme Chilliet <come.chilliet@nextcloud.com>2022-02-10 10:14:58 +0100
commit71fb44953e216affbe98c6c8c7106e1d62ee33fd (patch)
tree1726cfc412960360a7f1e4a0f0ea7d28e5896471 /apps/user_ldap/lib/Migration
parentde01da72d8e1dadb0b152ec822aa4e79ec990785 (diff)
downloadnextcloud-server-71fb44953e216affbe98c6c8c7106e1d62ee33fd.tar.gz
nextcloud-server-71fb44953e216affbe98c6c8c7106e1d62ee33fd.zip
invalidated duplicated UUIDs prior to migration change
- in a proper setup there are no duplicated UUIDs - not all setups are proper - log warning to admin Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Diffstat (limited to 'apps/user_ldap/lib/Migration')
-rw-r--r--apps/user_ldap/lib/Migration/Version1130Date20211102154716.php90
1 files changed, 90 insertions, 0 deletions
diff --git a/apps/user_ldap/lib/Migration/Version1130Date20211102154716.php b/apps/user_ldap/lib/Migration/Version1130Date20211102154716.php
index 8695f90ca65..94f0f0aa82e 100644
--- a/apps/user_ldap/lib/Migration/Version1130Date20211102154716.php
+++ b/apps/user_ldap/lib/Migration/Version1130Date20211102154716.php
@@ -27,6 +27,7 @@ declare(strict_types=1);
namespace OCA\User_LDAP\Migration;
use Closure;
+use Generator;
use OCP\DB\Exception;
use OCP\DB\ISchemaWrapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
@@ -52,6 +53,12 @@ class Version1130Date20211102154716 extends SimpleMigrationStep {
return 'Adjust LDAP user and group ldap_dn column lengths and add ldap_dn_hash columns';
}
+ public function preSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
+ foreach (['ldap_user_mapping', 'ldap_group_mapping'] as $tableName) {
+ $this->processDuplicateUUIDs($tableName);
+ }
+ }
+
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
@@ -172,4 +179,87 @@ class Version1130Date20211102154716 extends SimpleMigrationStep {
->where($qb->expr()->eq('owncloud_name', $qb->createParameter('name')));
return $qb;
}
+
+ /**
+ * @throws Exception
+ */
+ protected function processDuplicateUUIDs(string $table): void {
+ $uuids = $this->getDuplicatedUuids($table);
+ $idsWithUuidToInvalidate = [];
+ foreach ($uuids as $uuid) {
+ array_push($idsWithUuidToInvalidate, ...$this->getNextcloudIdsByUuid($table, $uuid));
+ }
+ $this->invalidateUuids($table, $idsWithUuidToInvalidate);
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function invalidateUuids(string $table, array $idList): void {
+ $update = $this->dbc->getQueryBuilder();
+ $update->update($table)
+ ->set('directory_uuid', $update->createParameter('invalidatedUuid'))
+ ->where($update->expr()->eq('owncloud_name', $update->createParameter('nextcloudId')));
+
+ while ($nextcloudId = array_shift($idList)) {
+ $update->setParameter('nextcloudId', $nextcloudId);
+ $update->setParameter('invalidatedUuid', 'invalidated_' . \bin2hex(\random_bytes(6)));
+ try {
+ $update->executeStatement();
+ $this->logger->warning(
+ 'LDAP user or group with ID {nid} has a duplicated UUID value which therefore was invalidated. You may double-check your LDAP configuration and trigger an update of the UUID.',
+ [
+ 'app' => 'user_ldap',
+ 'nid' => $nextcloudId,
+ ]
+ );
+ } catch (Exception $e) {
+ // Catch possible, but unlikely duplications if new invalidated errors.
+ // There is the theoretical chance of an infinity loop is, when
+ // the constraint violation has a different background. I cannot
+ // think of one at the moment.
+ if ($e->getReason() !== Exception::REASON_CONSTRAINT_VIOLATION) {
+ throw $e;
+ }
+ $idList[] = $nextcloudId;
+ }
+ }
+ }
+
+ /**
+ * @throws \OCP\DB\Exception
+ * @return array<string>
+ */
+ protected function getNextcloudIdsByUuid(string $table, string $uuid): array {
+ $select = $this->dbc->getQueryBuilder();
+ $select->select('owncloud_name')
+ ->from($table)
+ ->where($select->expr()->eq('directory_uuid', $select->createNamedParameter($uuid)));
+
+ $result = $select->executeQuery();
+ $idList = [];
+ while ($id = $result->fetchOne()) {
+ $idList[] = $id;
+ }
+ $result->closeCursor();
+ return $idList;
+ }
+
+ /**
+ * @return Generator<string>
+ * @throws \OCP\DB\Exception
+ */
+ protected function getDuplicatedUuids(string $table): Generator{
+ $select = $this->dbc->getQueryBuilder();
+ $select->select('directory_uuid')
+ ->from($table)
+ ->groupBy('directory_uuid')
+ ->having($select->expr()->gt($select->func()->count('owncloud_name'), $select->createNamedParameter(1)));
+
+ $result = $select->executeQuery();
+ while ($uuid = $result->fetchOne()) {
+ yield $uuid;
+ }
+ $result->closeCursor();
+ }
}