Passed
Push — master ( 2c1eac...4adb60 )
by John
28:02 queued 12:52
created

Version1130Date20211102154716   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 1
Metric Value
eloc 78
c 7
b 0
f 1
dl 0
loc 135
rs 10
wmc 17

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 2 1
A __construct() 0 3 1
A getUpdateQuery() 0 6 1
B changeSchema() 0 61 9
A getSelectQuery() 0 6 1
A postSchemaChange() 0 3 1
A handleDNHashes() 0 24 3
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2020 Joas Schilling <[email protected]>
7
 *
8
 * @author Côme Chilliet <[email protected]>
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
27
namespace OCA\User_LDAP\Migration;
28
29
use Closure;
30
use OCP\DB\Exception;
31
use OCP\DB\ISchemaWrapper;
32
use OCP\DB\QueryBuilder\IQueryBuilder;
33
use OCP\DB\Types;
34
use OCP\IDBConnection;
35
use OCP\Migration\IOutput;
36
use OCP\Migration\SimpleMigrationStep;
37
use Psr\Log\LoggerInterface;
38
39
class Version1130Date20211102154716 extends SimpleMigrationStep {
40
41
	/** @var IDBConnection */
42
	private $dbc;
43
	/** @var LoggerInterface */
44
	private $logger;
45
46
	public function __construct(IDBConnection $dbc, LoggerInterface $logger) {
47
		$this->dbc = $dbc;
48
		$this->logger = $logger;
49
	}
50
51
	public function getName() {
52
		return 'Adjust LDAP user and group ldap_dn column lengths and add ldap_dn_hash columns';
53
	}
54
55
	/**
56
	 * @param IOutput $output
57
	 * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
58
	 * @param array $options
59
	 * @return null|ISchemaWrapper
60
	 */
61
	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
62
		/** @var ISchemaWrapper $schema */
63
		$schema = $schemaClosure();
64
65
		$changeSchema = false;
66
		foreach (['ldap_user_mapping', 'ldap_group_mapping'] as $tableName) {
67
			$table = $schema->getTable($tableName);
68
			if (!$table->hasColumn('ldap_dn_hash')) {
69
				$table->addColumn('ldap_dn_hash', Types::STRING, [
70
					'notnull' => false,
71
					'length' => 64,
72
				]);
73
				$changeSchema = true;
74
			}
75
			$column = $table->getColumn('ldap_dn');
76
			if ($tableName === 'ldap_user_mapping') {
77
				if ($column->getLength() < 4096) {
78
					$column->setLength(4096);
79
					$changeSchema = true;
80
				}
81
82
				if ($table->hasIndex('ldap_dn_users')) {
83
					$table->dropIndex('ldap_dn_users');
84
					$changeSchema = true;
85
				}
86
				if (!$table->hasIndex('ldap_user_dn_hashes')) {
87
					$table->addUniqueIndex(['ldap_dn_hash'], 'ldap_user_dn_hashes');
88
					$changeSchema = true;
89
				}
90
				if (!$table->hasIndex('ldap_user_directory_uuid')) {
91
					$table->addUniqueIndex(['directory_uuid'], 'ldap_user_directory_uuid');
92
					$changeSchema = true;
93
				}
94
			} else {
95
				// We need to copy the table twice to be able to change primary key, prepare the backup table
96
				$table2 = $schema->createTable('ldap_group_mapping_backup');
97
				$table2->addColumn('ldap_dn', Types::STRING, [
98
					'notnull' => true,
99
					'length' => 4096,
100
					'default' => '',
101
				]);
102
				$table2->addColumn('owncloud_name', Types::STRING, [
103
					'notnull' => true,
104
					'length' => 64,
105
					'default' => '',
106
				]);
107
				$table2->addColumn('directory_uuid', Types::STRING, [
108
					'notnull' => true,
109
					'length' => 255,
110
					'default' => '',
111
				]);
112
				$table2->addColumn('ldap_dn_hash', Types::STRING, [
113
					'notnull' => false,
114
					'length' => 64,
115
				]);
116
				$table2->setPrimaryKey(['owncloud_name'], 'lgm_backup_primary');
117
				$changeSchema = true;
118
			}
119
		}
120
121
		return $changeSchema ? $schema : null;
122
	}
123
124
	/**
125
	 * @param IOutput $output
126
	 * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
127
	 * @param array $options
128
	 */
129
	public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
130
		$this->handleDNHashes('ldap_group_mapping');
131
		$this->handleDNHashes('ldap_user_mapping');
132
	}
133
134
	protected function handleDNHashes(string $table): void {
135
		$select = $this->getSelectQuery($table);
136
		$update = $this->getUpdateQuery($table);
137
138
		$result = $select->executeQuery();
139
		while ($row = $result->fetch()) {
140
			$dnHash = hash('sha256', $row['ldap_dn'], false);
141
			$update->setParameter('name', $row['owncloud_name']);
142
			$update->setParameter('dn_hash', $dnHash);
143
			try {
144
				$update->executeStatement();
145
			} catch (Exception $e) {
146
				$this->logger->error('Failed to add hash "{dnHash}" ("{name}" of {table})',
147
					[
148
						'app' => 'user_ldap',
149
						'name' => $row['owncloud_name'],
150
						'dnHash' => $dnHash,
151
						'table' => $table,
152
						'exception' => $e,
153
					]
154
				);
155
			}
156
		}
157
		$result->closeCursor();
158
	}
159
160
	protected function getSelectQuery(string $table): IQueryBuilder {
161
		$qb = $this->dbc->getQueryBuilder();
162
		$qb->select('owncloud_name', 'ldap_dn', 'ldap_dn_hash')
163
			->from($table)
164
			->where($qb->expr()->isNull('ldap_dn_hash'));
165
		return $qb;
166
	}
167
168
	protected function getUpdateQuery(string $table): IQueryBuilder {
169
		$qb = $this->dbc->getQueryBuilder();
170
		$qb->update($table)
171
			->set('ldap_dn_hash', $qb->createParameter('dn_hash'))
172
			->where($qb->expr()->eq('owncloud_name', $qb->createParameter('name')));
173
		return $qb;
174
	}
175
}
176