Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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 <[email protected]>
  • Loading branch information
blizzz authored and come-nc committed Feb 10, 2022
commit f975fe4ff395c61020e898867b824ab8354ff942
90 changes: 90 additions & 0 deletions apps/user_ldap/lib/Migration/Version1130Date20211102154716.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
namespace OCA\User_LDAP\Migration;

use Closure;
use Generator;
use OCP\DB\Exception;
use OCP\DB\ISchemaWrapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
Expand All @@ -52,6 +53,12 @@ public function getName() {
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`
Expand Down Expand Up @@ -172,4 +179,87 @@ protected function getUpdateQuery(string $table): IQueryBuilder {
->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();
}
}