Completed
Push — master ( abdf8c...733110 )
by Blizzz
10:14
created

Helper   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 247
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 247
rs 10
wmc 28
lcom 1
cbo 7

9 Methods

Rating   Name   Duplication   Size   Complexity  
B getServerConfigurationPrefixes() 0 31 4
A getServerConfigurationHosts() 0 21 2
B deleteServerConfiguration() 0 30 5
A haveDisabledConfigurations() 0 10 4
A getDomainFromURL() 0 15 4
A setLDAPProvider() 0 6 2
B sanitizeDN() 0 37 3
A DNasBaseParameter() 0 3 1
A loginName2UserName() 0 20 3
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Brice Maron <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Jörn Friedrich Dreyer <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Thomas Müller <[email protected]>
12
 * @author Vincent Petry <[email protected]>
13
 * @author Roger Szabo <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OCA\User_LDAP;
32
33
class Helper {
34
35
	/**
36
	 * returns prefixes for each saved LDAP/AD server configuration.
37
	 * @param bool $activeConfigurations optional, whether only active configuration shall be
38
	 * retrieved, defaults to false
39
	 * @return array with a list of the available prefixes
40
	 *
41
	 * Configuration prefixes are used to set up configurations for n LDAP or
42
	 * AD servers. Since configuration is stored in the database, table
43
	 * appconfig under appid user_ldap, the common identifiers in column
44
	 * 'configkey' have a prefix. The prefix for the very first server
45
	 * configuration is empty.
46
	 * Configkey Examples:
47
	 * Server 1: ldap_login_filter
48
	 * Server 2: s1_ldap_login_filter
49
	 * Server 3: s2_ldap_login_filter
50
	 *
51
	 * The prefix needs to be passed to the constructor of Connection class,
52
	 * except the default (first) server shall be connected to.
53
	 *
54
	 */
55
	public function getServerConfigurationPrefixes($activeConfigurations = false) {
56
		$referenceConfigkey = 'ldap_configuration_active';
57
58
		$sql = '
59
			SELECT DISTINCT `configkey`
60
			FROM `*PREFIX*appconfig`
61
			WHERE `appid` = \'user_ldap\'
62
				AND `configkey` LIKE ?
63
		';
64
65
		if($activeConfigurations) {
66
			if (\OC::$server->getConfig()->getSystemValue( 'dbtype', 'sqlite' ) === 'oci') {
67
				//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
68
				$sql .= ' AND to_char(`configvalue`)=\'1\'';
69
			} else {
70
				$sql .= ' AND `configvalue` = \'1\'';
71
			}
72
		}
73
74
		$stmt = \OCP\DB::prepare($sql);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::prepare() has been deprecated with message: 8.1.0 use prepare() of \OCP\IDBConnection - \OC::$server->getDatabaseConnection()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
75
76
		$serverConfigs = $stmt->execute(array('%'.$referenceConfigkey))->fetchAll();
77
		$prefixes = array();
78
79
		foreach($serverConfigs as $serverConfig) {
80
			$len = strlen($serverConfig['configkey']) - strlen($referenceConfigkey);
81
			$prefixes[] = substr($serverConfig['configkey'], 0, $len);
82
		}
83
84
		return $prefixes;
85
	}
86
87
	/**
88
	 *
89
	 * determines the host for every configured connection
90
	 * @return array an array with configprefix as keys
91
	 *
92
	 */
93
	public function getServerConfigurationHosts() {
94
		$referenceConfigkey = 'ldap_host';
95
96
		$query = '
97
			SELECT DISTINCT `configkey`, `configvalue`
98
			FROM `*PREFIX*appconfig`
99
			WHERE `appid` = \'user_ldap\'
100
				AND `configkey` LIKE ?
101
		';
102
		$query = \OCP\DB::prepare($query);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::prepare() has been deprecated with message: 8.1.0 use prepare() of \OCP\IDBConnection - \OC::$server->getDatabaseConnection()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
103
		$configHosts = $query->execute(array('%'.$referenceConfigkey))->fetchAll();
104
		$result = array();
105
106
		foreach($configHosts as $configHost) {
107
			$len = strlen($configHost['configkey']) - strlen($referenceConfigkey);
108
			$prefix = substr($configHost['configkey'], 0, $len);
109
			$result[$prefix] = $configHost['configvalue'];
110
		}
111
112
		return $result;
113
	}
114
115
	/**
116
	 * deletes a given saved LDAP/AD server configuration.
117
	 * @param string $prefix the configuration prefix of the config to delete
118
	 * @return bool true on success, false otherwise
119
	 */
120
	public function deleteServerConfiguration($prefix) {
121
		if(!in_array($prefix, self::getServerConfigurationPrefixes())) {
122
			return false;
123
		}
124
125
		$saveOtherConfigurations = '';
126
		if(empty($prefix)) {
127
			$saveOtherConfigurations = 'AND `configkey` NOT LIKE \'s%\'';
128
		}
129
130
		$query = \OCP\DB::prepare('
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::prepare() has been deprecated with message: 8.1.0 use prepare() of \OCP\IDBConnection - \OC::$server->getDatabaseConnection()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
131
			DELETE
132
			FROM `*PREFIX*appconfig`
133
			WHERE `configkey` LIKE ?
134
				'.$saveOtherConfigurations.'
135
				AND `appid` = \'user_ldap\'
136
				AND `configkey` NOT IN (\'enabled\', \'installed_version\', \'types\', \'bgjUpdateGroupsLastRun\')
137
		');
138
		$delRows = $query->execute(array($prefix.'%'));
139
140
		if(\OCP\DB::isError($delRows)) {
0 ignored issues
show
Deprecated Code introduced by
The method OCP\DB::isError() has been deprecated with message: 8.1.0 Doctrine returns false on error (and throws an exception)

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
141
			return false;
142
		}
143
144
		if($delRows === 0) {
145
			return false;
146
		}
147
148
		return true;
149
	}
150
151
	/**
152
	 * checks whether there is one or more disabled LDAP configurations
153
	 * @throws \Exception
154
	 * @return bool
155
	 */
156
	public function haveDisabledConfigurations() {
157
		$all = $this->getServerConfigurationPrefixes(false);
158
		$active = $this->getServerConfigurationPrefixes(true);
159
160
		if(!is_array($all) || !is_array($active)) {
161
			throw new \Exception('Unexpected Return Value');
162
		}
163
164
		return count($all) !== count($active) || count($all) === 0;
165
	}
166
167
	/**
168
	 * extracts the domain from a given URL
169
	 * @param string $url the URL
170
	 * @return string|false domain as string on success, false otherwise
171
	 */
172
	public function getDomainFromURL($url) {
173
		$uinfo = parse_url($url);
174
		if(!is_array($uinfo)) {
175
			return false;
176
		}
177
178
		$domain = false;
179
		if(isset($uinfo['host'])) {
180
			$domain = $uinfo['host'];
181
		} else if(isset($uinfo['path'])) {
182
			$domain = $uinfo['path'];
183
		}
184
185
		return $domain;
186
	}
187
	
188
	/**
189
	 *
190
	 * Set the LDAPProvider in the config
191
	 *
192
	 */
193
	public function setLDAPProvider() {
194
		$current = \OC::$server->getConfig()->getSystemValue('ldapProviderFactory', null);
195
		if(is_null($current)) {
196
			\OC::$server->getConfig()->setSystemValue('ldapProviderFactory', '\\OCA\\User_LDAP\\LDAPProviderFactory');
197
		}
198
	}
199
	
200
	/**
201
	 * sanitizes a DN received from the LDAP server
202
	 * @param array $dn the DN in question
203
	 * @return array the sanitized DN
204
	 */
205
	public function sanitizeDN($dn) {
206
		//treating multiple base DNs
207
		if(is_array($dn)) {
208
			$result = array();
209
			foreach($dn as $singleDN) {
210
				$result[] = $this->sanitizeDN($singleDN);
211
			}
212
			return $result;
213
		}
214
215
		//OID sometimes gives back DNs with whitespace after the comma
216
		// a la "uid=foo, cn=bar, dn=..." We need to tackle this!
217
		$dn = preg_replace('/([^\\\]),(\s+)/u', '\1,', $dn);
218
219
		//make comparisons and everything work
220
		$dn = mb_strtolower($dn, 'UTF-8');
221
222
		//escape DN values according to RFC 2253 – this is already done by ldap_explode_dn
223
		//to use the DN in search filters, \ needs to be escaped to \5c additionally
224
		//to use them in bases, we convert them back to simple backslashes in readAttribute()
225
		$replacements = array(
226
			'\,' => '\5c2C',
227
			'\=' => '\5c3D',
228
			'\+' => '\5c2B',
229
			'\<' => '\5c3C',
230
			'\>' => '\5c3E',
231
			'\;' => '\5c3B',
232
			'\"' => '\5c22',
233
			'\#' => '\5c23',
234
			'('  => '\28',
235
			')'  => '\29',
236
			'*'  => '\2A',
237
		);
238
		$dn = str_replace(array_keys($replacements), array_values($replacements), $dn);
239
240
		return $dn;
241
	}
242
	
243
	/**
244
	 * converts a stored DN so it can be used as base parameter for LDAP queries, internally we store them for usage in LDAP filters
245
	 * @param string $dn the DN
246
	 * @return string
247
	 */
248
	public function DNasBaseParameter($dn) {
249
		return str_ireplace('\\5c', '\\', $dn);
250
	}
251
252
	/**
253
	 * listens to a hook thrown by server2server sharing and replaces the given
254
	 * login name by a username, if it matches an LDAP user.
255
	 *
256
	 * @param array $param
257
	 * @throws \Exception
258
	 */
259
	public static function loginName2UserName($param) {
260
		if(!isset($param['uid'])) {
261
			throw new \Exception('key uid is expected to be set in $param');
262
		}
263
264
		//ain't it ironic?
265
		$helper = new Helper();
266
267
		$configPrefixes = $helper->getServerConfigurationPrefixes(true);
268
		$ldapWrapper = new LDAP();
269
		$ocConfig = \OC::$server->getConfig();
270
271
		$userBackend  = new User_Proxy(
272
			$configPrefixes, $ldapWrapper, $ocConfig
273
		);
274
		$uid = $userBackend->loginName2UserName($param['uid'] );
275
		if($uid !== false) {
276
			$param['uid'] = $uid;
277
		}
278
	}
279
}
280