diff options
Diffstat (limited to 'apps/user_ldap/lib')
-rw-r--r-- | apps/user_ldap/lib/Migration/Version1130Date20211102154716.php | 90 |
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(); + } } |