diff options
author | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2021-09-17 19:15:46 +0200 |
---|---|---|
committer | Arthur Schiwon <blizzz@arthur-schiwon.de> | 2021-09-27 17:52:13 +0200 |
commit | 24f2974267684b364d0396db2acaa6e8dea1c1ad (patch) | |
tree | c89465ca48003a1565f1b7173a502870e7116abd /apps/user_ldap/lib | |
parent | 62a5d27eb7633eaf046e50f8ada8e2a2b2239f83 (diff) | |
download | nextcloud-server-24f2974267684b364d0396db2acaa6e8dea1c1ad.tar.gz nextcloud-server-24f2974267684b364d0396db2acaa6e8dea1c1ad.zip |
ensure that user and group IDs in LDAP's tables are also max 64chars
- limitation by core tables (e.g. sharing), IDs are always 64chars
- when longer group IDs were requested they are hashed (does not affect
displaynames)
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Diffstat (limited to 'apps/user_ldap/lib')
-rw-r--r-- | apps/user_ldap/lib/Access.php | 25 | ||||
-rw-r--r-- | apps/user_ldap/lib/Migration/Version1010Date20200630192842.php | 4 | ||||
-rw-r--r-- | apps/user_ldap/lib/Migration/Version1120Date20210917155206.php | 133 |
3 files changed, 159 insertions, 3 deletions
diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index 0b243b8ad59..862089e9d30 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -60,6 +60,8 @@ use OCA\User_LDAP\User\OfflineUser; use OCP\IConfig; use OCP\ILogger; use OCP\IUserManager; +use function strlen; +use function substr; /** * Class Access @@ -579,7 +581,7 @@ class Access extends LDAPUtility { return false; } } else { - $intName = $ldapName; + $intName = $this->sanitizeGroupIDCandidate($ldapName); } //a new user/group! Add it only if it doesn't conflict with other backend's users or existing groups @@ -838,6 +840,11 @@ class Access extends LDAPUtility { * @return string|false with with the name to use in Nextcloud or false if unsuccessful */ private function createAltInternalOwnCloudName($name, $isUser) { + // ensure there is space for the "_1234" suffix + if (strlen($name) > 59) { + $name = substr($name, 0, 59); + } + $originalTTL = $this->connection->ldapCacheTTL; $this->connection->setConfiguration(['ldapCacheTTL' => 0]); if ($isUser) { @@ -1432,6 +1439,10 @@ class Access extends LDAPUtility { // Every remaining disallowed characters will be removed $name = preg_replace('/[^a-zA-Z0-9_.@-]/u', '', $name); + if (strlen($name) > 64) { + $name = (string)hash('sha256', $name, false); + } + if ($name === '') { throw new \InvalidArgumentException('provided name template for username does not contain any allowed characters'); } @@ -1439,6 +1450,18 @@ class Access extends LDAPUtility { return $name; } + public function sanitizeGroupIDCandidate(string $candidate): string { + $candidate = trim($candidate); + if (strlen($candidate) > 64) { + $candidate = (string)hash('sha256', $candidate, false); + } + if ($candidate === '') { + throw new \InvalidArgumentException('provided name template for username does not contain any allowed characters'); + } + + return $candidate; + } + /** * escapes (user provided) parts for LDAP filter * diff --git a/apps/user_ldap/lib/Migration/Version1010Date20200630192842.php b/apps/user_ldap/lib/Migration/Version1010Date20200630192842.php index 754200405c8..3d9cc40b5b2 100644 --- a/apps/user_ldap/lib/Migration/Version1010Date20200630192842.php +++ b/apps/user_ldap/lib/Migration/Version1010Date20200630192842.php @@ -52,7 +52,7 @@ class Version1010Date20200630192842 extends SimpleMigrationStep { ]); $table->addColumn('owncloud_name', Types::STRING, [ 'notnull' => true, - 'length' => 255, + 'length' => 64, 'default' => '', ]); $table->addColumn('directory_uuid', Types::STRING, [ @@ -73,7 +73,7 @@ class Version1010Date20200630192842 extends SimpleMigrationStep { ]); $table->addColumn('owncloud_name', Types::STRING, [ 'notnull' => true, - 'length' => 255, + 'length' => 64, 'default' => '', ]); $table->addColumn('directory_uuid', Types::STRING, [ diff --git a/apps/user_ldap/lib/Migration/Version1120Date20210917155206.php b/apps/user_ldap/lib/Migration/Version1120Date20210917155206.php new file mode 100644 index 00000000000..d46107733dc --- /dev/null +++ b/apps/user_ldap/lib/Migration/Version1120Date20210917155206.php @@ -0,0 +1,133 @@ +<?php + +declare(strict_types=1); + +namespace OCA\User_LDAP\Migration; + +use Closure; +use OC\Hooks\PublicEmitter; +use OCP\DB\Exception; +use OCP\DB\ISchemaWrapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\IUserManager; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; +use Psr\Log\LoggerInterface; + +class Version1120Date20210917155206 extends SimpleMigrationStep { + + /** @var IDBConnection */ + private $dbc; + /** @var IUserManager */ + private $userManager; + /** @var LoggerInterface */ + private $logger; + + public function __construct(IDBConnection $dbc, IUserManager $userManager, LoggerInterface $logger) { + $this->dbc = $dbc; + $this->userManager = $userManager; + $this->logger = $logger; + } + + public function getName() { + return 'Adjust LDAP user and group id column lengths to match server lengths'; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + // ensure that there is no user or group id longer than 64char in LDAP table + $this->handleIDs('ldap_group_mapping', false); + $this->handleIDs('ldap_user_mapping', true); + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $changeSchema = false; + foreach (['ldap_user_mapping', 'ldap_group_mapping'] as $tableName) { + $table = $schema->getTable($tableName); + $column = $table->getColumn('owncloud_name'); + if ($column->getLength() > 64) { + $column->setLength(64); + $changeSchema = true; + } + } + + return $changeSchema ? $schema : null; + } + + protected function handleIDs(string $table, bool $emitHooks) { + $q = $this->getSelectQuery($table); + $u = $this->getUpdateQuery($table); + + $r = $q->executeQuery(); + while ($row = $r->fetch()) { + $newId = hash('sha256', $row['owncloud_name'], false); + if ($emitHooks) { + $this->emitUnassign($row['owncloud_name'], true); + } + $u->setParameter('uuid', $row['directory_uuid']); + $u->setParameter('newId', $newId); + try { + $u->executeStatement(); + if ($emitHooks) { + $this->emitUnassign($row['owncloud_name'], false); + $this->emitAssign($newId); + } + } catch (Exception $e) { + $this->logger->error('Failed to shorten owncloud_name "{oldId}" to "{newId}" (UUID: "{uuid}" of {table})', + [ + 'app' => 'user_ldap', + 'oldId' => $row['owncloud_name'], + 'newId' => $newId, + 'uuid' => $row['directory_uuid'], + 'table' => $table, + 'exception' => $e, + ] + ); + } + } + $r->closeCursor(); + } + + protected function getSelectQuery(string $table): IQueryBuilder { + $q = $this->dbc->getQueryBuilder(); + $q->select('owncloud_name', 'directory_uuid') + ->from($table) + ->where($q->expr()->like('owncloud_name', $q->createNamedParameter(str_repeat('_', 65) . '%'), Types::STRING)); + return $q; + } + + protected function getUpdateQuery(string $table): IQueryBuilder { + $q = $this->dbc->getQueryBuilder(); + $q->update($table) + ->set('owncloud_name', $q->createParameter('newId')) + ->where($q->expr()->eq('directory_uuid', $q->createParameter('uuid'))); + return $q; + } + + protected function emitUnassign(string $oldId, bool $pre): void { + if ($this->userManager instanceof PublicEmitter) { + $this->userManager->emit('\OC\User', $pre ? 'pre' : 'post' . 'UnassignedUserId', [$oldId]); + } + } + + protected function emitAssign(string $newId): void { + if ($this->userManager instanceof PublicEmitter) { + $this->userManager->emit('\OC\User', 'assignedUserId', [$newId]); + } + } +} |