Skip to content

Commit 7f63268

Browse files
authored
Merge pull request #30260 from nextcloud/backport/29523/stable22
[stable22] Support LDAP dns longer than 255 characters
2 parents 9748125 + eeefca2 commit 7f63268

File tree

7 files changed

+258
-34
lines changed

7 files changed

+258
-34
lines changed

apps/user_ldap/appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
A user logs into Nextcloud with their LDAP or AD credentials, and is granted access based on an authentication request handled by the LDAP or AD server. Nextcloud does not store LDAP or AD passwords, rather these credentials are used to authenticate a user and then Nextcloud uses a session for the user ID. More information is available in the LDAP User and Group Backend documentation.
1010

1111
</description>
12-
<version>1.12.1</version>
12+
<version>1.12.2</version>
1313
<licence>agpl</licence>
1414
<author>Dominik Schmidt</author>
1515
<author>Arthur Schiwon</author>

apps/user_ldap/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
'OCA\\User_LDAP\\Migration\\UnsetDefaultProvider' => $baseDir . '/../lib/Migration/UnsetDefaultProvider.php',
6363
'OCA\\User_LDAP\\Migration\\Version1010Date20200630192842' => $baseDir . '/../lib/Migration/Version1010Date20200630192842.php',
6464
'OCA\\User_LDAP\\Migration\\Version1120Date20210917155206' => $baseDir . '/../lib/Migration/Version1120Date20210917155206.php',
65+
'OCA\\User_LDAP\\Migration\\Version1130Date20211102154716' => $baseDir . '/../lib/Migration/Version1130Date20211102154716.php',
6566
'OCA\\User_LDAP\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
6667
'OCA\\User_LDAP\\PagedResults\\IAdapter' => $baseDir . '/../lib/PagedResults/IAdapter.php',
6768
'OCA\\User_LDAP\\PagedResults\\Php73' => $baseDir . '/../lib/PagedResults/Php73.php',

apps/user_ldap/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class ComposerStaticInitUser_LDAP
7777
'OCA\\User_LDAP\\Migration\\UnsetDefaultProvider' => __DIR__ . '/..' . '/../lib/Migration/UnsetDefaultProvider.php',
7878
'OCA\\User_LDAP\\Migration\\Version1010Date20200630192842' => __DIR__ . '/..' . '/../lib/Migration/Version1010Date20200630192842.php',
7979
'OCA\\User_LDAP\\Migration\\Version1120Date20210917155206' => __DIR__ . '/..' . '/../lib/Migration/Version1120Date20210917155206.php',
80+
'OCA\\User_LDAP\\Migration\\Version1130Date20211102154716' => __DIR__ . '/..' . '/../lib/Migration/Version1130Date20211102154716.php',
8081
'OCA\\User_LDAP\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
8182
'OCA\\User_LDAP\\PagedResults\\IAdapter' => __DIR__ . '/..' . '/../lib/PagedResults/IAdapter.php',
8283
'OCA\\User_LDAP\\PagedResults\\Php73' => __DIR__ . '/..' . '/../lib/PagedResults/Php73.php',

apps/user_ldap/lib/Mapping/AbstractMapping.php

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public function __construct(\OCP\IDBConnection $dbc) {
6868
public function isColNameValid($col) {
6969
switch ($col) {
7070
case 'ldap_dn':
71+
case 'ldap_dn_hash':
7172
case 'owncloud_name':
7273
case 'directory_uuid':
7374
return true;
@@ -151,11 +152,11 @@ public function setDNbyUUID($fdn, $uuid) {
151152
$oldDn = $this->getDnByUUID($uuid);
152153
$statement = $this->dbc->prepare('
153154
UPDATE `' . $this->getTableName() . '`
154-
SET `ldap_dn` = ?
155+
SET `ldap_dn_hash` = ?, `ldap_dn` = ?
155156
WHERE `directory_uuid` = ?
156157
');
157158

158-
$r = $this->modify($statement, [$fdn, $uuid]);
159+
$r = $this->modify($statement, [$this->getDNHash($fdn), $fdn, $uuid]);
159160

160161
if ($r && is_string($oldDn) && isset($this->cache[$oldDn])) {
161162
$this->cache[$fdn] = $this->cache[$oldDn];
@@ -178,12 +179,24 @@ public function setUUIDbyDN($uuid, $fdn) {
178179
$statement = $this->dbc->prepare('
179180
UPDATE `' . $this->getTableName() . '`
180181
SET `directory_uuid` = ?
181-
WHERE `ldap_dn` = ?
182+
WHERE `ldap_dn_hash` = ?
182183
');
183184

184185
unset($this->cache[$fdn]);
185186

186-
return $this->modify($statement, [$uuid, $fdn]);
187+
return $this->modify($statement, [$uuid, $this->getDNHash($fdn)]);
188+
}
189+
190+
/**
191+
* Get the hash to store in database column ldap_dn_hash for a given dn
192+
*/
193+
protected function getDNHash(string $fdn): string {
194+
$hash = hash('sha256', $fdn, false);
195+
if (is_string($hash)) {
196+
return $hash;
197+
} else {
198+
throw new \RuntimeException('hash function did not return a string');
199+
}
187200
}
188201

189202
/**
@@ -194,16 +207,19 @@ public function setUUIDbyDN($uuid, $fdn) {
194207
*/
195208
public function getNameByDN($fdn) {
196209
if (!isset($this->cache[$fdn])) {
197-
$this->cache[$fdn] = $this->getXbyY('owncloud_name', 'ldap_dn', $fdn);
210+
$this->cache[$fdn] = $this->getXbyY('owncloud_name', 'ldap_dn_hash', $this->getDNHash($fdn));
198211
}
199212
return $this->cache[$fdn];
200213
}
201214

202-
protected function prepareListOfIdsQuery(array $dnList): IQueryBuilder {
215+
/**
216+
* @param array<string> $hashList
217+
*/
218+
protected function prepareListOfIdsQuery(array $hashList): IQueryBuilder {
203219
$qb = $this->dbc->getQueryBuilder();
204-
$qb->select('owncloud_name', 'ldap_dn')
220+
$qb->select('owncloud_name', 'ldap_dn_hash', 'ldap_dn')
205221
->from($this->getTableName(false))
206-
->where($qb->expr()->in('ldap_dn', $qb->createNamedParameter($dnList, QueryBuilder::PARAM_STR_ARRAY)));
222+
->where($qb->expr()->in('ldap_dn_hash', $qb->createNamedParameter($hashList, QueryBuilder::PARAM_STR_ARRAY)));
207223
return $qb;
208224
}
209225

@@ -216,13 +232,18 @@ protected function collectResultsFromListOfIdsQuery(IQueryBuilder $qb, array &$r
216232
$stmt->closeCursor();
217233
}
218234

235+
/**
236+
* @param array<string> $fdns
237+
* @return array<string,string>
238+
*/
219239
public function getListOfIdsByDn(array $fdns): array {
220240
$totalDBParamLimit = 65000;
221241
$sliceSize = 1000;
222242
$maxSlices = $totalDBParamLimit / $sliceSize;
223243
$results = [];
224244

225245
$slice = 1;
246+
$fdns = array_map([$this, 'getDNHash'], $fdns);
226247
$fdnsSlice = count($fdns) > $sliceSize ? array_slice($fdns, 0, $sliceSize) : $fdns;
227248
$qb = $this->prepareListOfIdsQuery($fdnsSlice);
228249

@@ -240,7 +261,7 @@ public function getListOfIdsByDn(array $fdns): array {
240261
}
241262

242263
if (!empty($fdnsSlice)) {
243-
$qb->orWhere($qb->expr()->in('ldap_dn', $qb->createNamedParameter($fdnsSlice, QueryBuilder::PARAM_STR_ARRAY)));
264+
$qb->orWhere($qb->expr()->in('ldap_dn_hash', $qb->createNamedParameter($fdnsSlice, QueryBuilder::PARAM_STR_ARRAY)));
244265
}
245266

246267
if ($slice % $maxSlices === 0) {
@@ -305,7 +326,7 @@ public function getDnByUUID($uuid) {
305326
* @throws \Exception
306327
*/
307328
public function getUUIDByDN($dn) {
308-
return $this->getXbyY('directory_uuid', 'ldap_dn', $dn);
329+
return $this->getXbyY('directory_uuid', 'ldap_dn_hash', $this->getDNHash($dn));
309330
}
310331

311332
/**
@@ -339,9 +360,9 @@ public function getList($offset = null, $limit = null) {
339360
* @return bool
340361
*/
341362
public function map($fdn, $name, $uuid) {
342-
if (mb_strlen($fdn) > 255) {
363+
if (mb_strlen($fdn) > 4096) {
343364
\OC::$server->getLogger()->error(
344-
'Cannot map, because the DN exceeds 255 characters: {dn}',
365+
'Cannot map, because the DN exceeds 4096 characters: {dn}',
345366
[
346367
'app' => 'user_ldap',
347368
'dn' => $fdn,
@@ -351,6 +372,7 @@ public function map($fdn, $name, $uuid) {
351372
}
352373

353374
$row = [
375+
'ldap_dn_hash' => $this->getDNHash($fdn),
354376
'ldap_dn' => $fdn,
355377
'owncloud_name' => $name,
356378
'directory_uuid' => $uuid
@@ -438,7 +460,7 @@ public function clearCb(callable $preCallback, callable $postCallback): bool {
438460
*/
439461
public function count() {
440462
$qb = $this->dbc->getQueryBuilder();
441-
$query = $qb->select($qb->func()->count('ldap_dn'))
463+
$query = $qb->select($qb->func()->count('ldap_dn_hash'))
442464
->from($this->getTableName());
443465
$res = $query->execute();
444466
$count = $res->fetchOne();

apps/user_ldap/lib/Migration/Version1010Date20200630192842.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,13 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
6060
'length' => 255,
6161
'default' => '',
6262
]);
63+
$table->addColumn('ldap_dn_hash', Types::STRING, [
64+
'notnull' => false,
65+
'length' => 64,
66+
]);
6367
$table->setPrimaryKey(['owncloud_name']);
64-
$table->addUniqueIndex(['ldap_dn'], 'ldap_dn_users');
68+
$table->addUniqueIndex(['ldap_dn_hash'], 'ldap_user_dn_hashes');
69+
$table->addUniqueIndex(['directory_uuid'], 'ldap_user_directory_uuid');
6570
}
6671

6772
if (!$schema->hasTable('ldap_group_mapping')) {
@@ -81,8 +86,13 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
8186
'length' => 255,
8287
'default' => '',
8388
]);
84-
$table->setPrimaryKey(['ldap_dn']);
85-
$table->addUniqueIndex(['owncloud_name'], 'owncloud_name_groups');
89+
$table->addColumn('ldap_dn_hash', Types::STRING, [
90+
'notnull' => false,
91+
'length' => 64,
92+
]);
93+
$table->setPrimaryKey(['owncloud_name']);
94+
$table->addUniqueIndex(['ldap_dn_hash'], 'ldap_group_dn_hashes');
95+
$table->addUniqueIndex(['directory_uuid'], 'ldap_group_directory_uuid');
8696
}
8797

8898
if (!$schema->hasTable('ldap_group_members')) {

apps/user_ldap/lib/Migration/Version1120Date20210917155206.php

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22

33
declare(strict_types=1);
44

5+
/**
6+
* @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
7+
*
8+
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
9+
*
10+
* @license GNU AGPL version 3 or any later version
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU Affero General Public License as
14+
* published by the Free Software Foundation, either version 3 of the
15+
* License, or (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU Affero General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
527
namespace OCA\User_LDAP\Migration;
628

729
use Closure;
@@ -70,19 +92,19 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
7092
}
7193

7294
protected function handleIDs(string $table, bool $emitHooks) {
73-
$q = $this->getSelectQuery($table);
74-
$u = $this->getUpdateQuery($table);
95+
$select = $this->getSelectQuery($table);
96+
$update = $this->getUpdateQuery($table);
7597

76-
$r = $q->executeQuery();
77-
while ($row = $r->fetch()) {
98+
$result = $select->executeQuery();
99+
while ($row = $result->fetch()) {
78100
$newId = hash('sha256', $row['owncloud_name'], false);
79101
if ($emitHooks) {
80102
$this->emitUnassign($row['owncloud_name'], true);
81103
}
82-
$u->setParameter('uuid', $row['directory_uuid']);
83-
$u->setParameter('newId', $newId);
104+
$update->setParameter('uuid', $row['directory_uuid']);
105+
$update->setParameter('newId', $newId);
84106
try {
85-
$u->executeStatement();
107+
$update->executeStatement();
86108
if ($emitHooks) {
87109
$this->emitUnassign($row['owncloud_name'], false);
88110
$this->emitAssign($newId);
@@ -100,23 +122,23 @@ protected function handleIDs(string $table, bool $emitHooks) {
100122
);
101123
}
102124
}
103-
$r->closeCursor();
125+
$result->closeCursor();
104126
}
105127

106128
protected function getSelectQuery(string $table): IQueryBuilder {
107-
$q = $this->dbc->getQueryBuilder();
108-
$q->select('owncloud_name', 'directory_uuid')
129+
$qb = $this->dbc->getQueryBuilder();
130+
$qb->select('owncloud_name', 'directory_uuid')
109131
->from($table)
110-
->where($q->expr()->like('owncloud_name', $q->createNamedParameter(str_repeat('_', 65) . '%'), Types::STRING));
111-
return $q;
132+
->where($qb->expr()->like('owncloud_name', $qb->createNamedParameter(str_repeat('_', 65) . '%'), Types::STRING));
133+
return $qb;
112134
}
113135

114136
protected function getUpdateQuery(string $table): IQueryBuilder {
115-
$q = $this->dbc->getQueryBuilder();
116-
$q->update($table)
117-
->set('owncloud_name', $q->createParameter('newId'))
118-
->where($q->expr()->eq('directory_uuid', $q->createParameter('uuid')));
119-
return $q;
137+
$qb = $this->dbc->getQueryBuilder();
138+
$qb->update($table)
139+
->set('owncloud_name', $qb->createParameter('newId'))
140+
->where($qb->expr()->eq('directory_uuid', $qb->createParameter('uuid')));
141+
return $qb;
120142
}
121143

122144
protected function emitUnassign(string $oldId, bool $pre): void {

0 commit comments

Comments
 (0)