Passed
Push — master ( 092a1f...510a29 )
by Joas
12:31 queued 11s
created

User_Proxy   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 331
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 47
eloc 84
dl 0
loc 331
rs 8.64
c 1
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A implementsActions() 0 3 1
A setPassword() 0 2 1
A createUser() 0 2 1
A setDisplayName() 0 2 1
A getBackendName() 0 2 1
A canChangeAvatar() 0 2 1
A deleteUser() 0 2 1
A userExistsOnLDAP() 0 3 2
A countUsers() 0 9 3
A getHome() 0 2 1
A userExists() 0 17 6
A dn2UserName() 0 3 1
A getDisplayNames() 0 10 3
B callOnLastSeenOn() 0 27 7
A getLDAPAccess() 0 2 1
A walkBackends() 0 14 5
A getNewLDAPConnection() 0 2 1
A hasUserListings() 0 2 1
A checkPassword() 0 2 1
A loginName2UserName() 0 3 1
A getUsers() 0 10 3
A getDisplayName() 0 2 1
A __construct() 0 15 3

How to fix   Complexity   

Complex Class

Complex classes like User_Proxy often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use User_Proxy, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Christopher Schäpers <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin McCorkell <[email protected]>
11
 * @author Roger Szabo <[email protected]>
12
 * @author root <[email protected]>
13
 * @author Thomas Müller <[email protected]>
14
 * @author Vinicius Cubas Brand <[email protected]>
15
 *
16
 * @license AGPL-3.0
17
 *
18
 * This code is free software: you can redistribute it and/or modify
19
 * it under the terms of the GNU Affero General Public License, version 3,
20
 * as published by the Free Software Foundation.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU Affero General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU Affero General Public License, version 3,
28
 * along with this program. If not, see <http://www.gnu.org/licenses/>
29
 *
30
 */
31
32
namespace OCA\User_LDAP;
33
34
use OCA\User_LDAP\User\User;
35
use OCP\IConfig;
36
use OCP\IUserSession;
37
use OCP\Notification\IManager as INotificationManager;
38
39
class User_Proxy extends Proxy implements \OCP\IUserBackend, \OCP\UserInterface, IUserLDAP {
40
	private $backends = [];
41
	/** @var User_LDAP */
42
	private $refBackend = null;
43
44
	/**
45
	 * Constructor
46
	 *
47
	 * @param array $serverConfigPrefixes array containing the config Prefixes
48
	 * @param ILDAPWrapper $ldap
49
	 * @param IConfig $ocConfig
50
	 * @param INotificationManager $notificationManager
51
	 * @param IUserSession $userSession
52
	 */
53
	public function __construct(
54
		array $serverConfigPrefixes,
55
		ILDAPWrapper $ldap,
56
		IConfig $ocConfig,
57
		INotificationManager $notificationManager,
58
		IUserSession $userSession,
59
		UserPluginManager $userPluginManager
60
	) {
61
		parent::__construct($ldap);
62
		foreach($serverConfigPrefixes as $configPrefix) {
63
			$this->backends[$configPrefix] =
64
				new User_LDAP($this->getAccess($configPrefix), $ocConfig, $notificationManager, $userSession, $userPluginManager);
65
66
			if(is_null($this->refBackend)) {
67
				$this->refBackend = &$this->backends[$configPrefix];
68
			}
69
		}
70
	}
71
72
	/**
73
	 * Tries the backends one after the other until a positive result is returned from the specified method
74
	 * @param string $uid the uid connected to the request
75
	 * @param string $method the method of the user backend that shall be called
76
	 * @param array $parameters an array of parameters to be passed
77
	 * @return mixed the result of the method or false
78
	 */
79
	protected function walkBackends($uid, $method, $parameters) {
80
		$cacheKey = $this->getUserCacheKey($uid);
81
		foreach($this->backends as $configPrefix => $backend) {
82
			$instance = $backend;
83
			if(!method_exists($instance, $method)
84
				&& method_exists($this->getAccess($configPrefix), $method)) {
85
				$instance = $this->getAccess($configPrefix);
86
			}
87
			if($result = call_user_func_array(array($instance, $method), $parameters)) {
88
				$this->writeToCache($cacheKey, $configPrefix);
89
				return $result;
90
			}
91
		}
92
		return false;
93
	}
94
95
	/**
96
	 * Asks the backend connected to the server that supposely takes care of the uid from the request.
97
	 * @param string $uid the uid connected to the request
98
	 * @param string $method the method of the user backend that shall be called
99
	 * @param array $parameters an array of parameters to be passed
100
	 * @param mixed $passOnWhen the result matches this variable
101
	 * @return mixed the result of the method or false
102
	 */
103
	protected function callOnLastSeenOn($uid, $method, $parameters, $passOnWhen) {
104
		$cacheKey = $this->getUserCacheKey($uid);
105
		$prefix = $this->getFromCache($cacheKey);
106
		//in case the uid has been found in the past, try this stored connection first
107
		if(!is_null($prefix)) {
108
			if(isset($this->backends[$prefix])) {
109
				$instance = $this->backends[$prefix];
110
				if(!method_exists($instance, $method)
111
					&& method_exists($this->getAccess($prefix), $method)) {
112
					$instance = $this->getAccess($prefix);
113
				}
114
				$result = call_user_func_array([$instance, $method], $parameters);
115
				if($result === $passOnWhen) {
116
					//not found here, reset cache to null if user vanished
117
					//because sometimes methods return false with a reason
118
					$userExists = call_user_func_array(
119
						[$this->backends[$prefix], 'userExistsOnLDAP'],
120
						[$uid]
121
					);
122
					if(!$userExists) {
123
						$this->writeToCache($cacheKey, null);
124
					}
125
				}
126
				return $result;
127
			}
128
		}
129
		return false;
130
	}
131
132
	/**
133
	 * Check if backend implements actions
134
	 * @param int $actions bitwise-or'ed actions
135
	 * @return boolean
136
	 *
137
	 * Returns the supported actions as int to be
138
	 * compared with \OC\User\Backend::CREATE_USER etc.
139
	 */
140
	public function implementsActions($actions) {
141
		//it's the same across all our user backends obviously
142
		return $this->refBackend->implementsActions($actions);
143
	}
144
145
	/**
146
	 * Backend name to be shown in user management
147
	 * @return string the name of the backend to be shown
148
	 */
149
	public function getBackendName() {
150
		return $this->refBackend->getBackendName();
151
	}
152
153
	/**
154
	 * Get a list of all users
155
	 *
156
	 * @param string $search
157
	 * @param null|int $limit
158
	 * @param null|int $offset
159
	 * @return string[] an array of all uids
160
	 */
161
	public function getUsers($search = '', $limit = 10, $offset = 0) {
162
		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
163
		$users = array();
164
		foreach($this->backends as $backend) {
165
			$backendUsers = $backend->getUsers($search, $limit, $offset);
166
			if (is_array($backendUsers)) {
167
				$users = array_merge($users, $backendUsers);
168
			}
169
		}
170
		return $users;
171
	}
172
173
	/**
174
	 * check if a user exists
175
	 * @param string $uid the username
176
	 * @return boolean
177
	 */
178
	public function userExists($uid) {
179
		$existsOnLDAP = false;
180
		$existsLocally = $this->handleRequest($uid, 'userExists', array($uid));
181
		if($existsLocally) {
182
			$existsOnLDAP = $this->userExistsOnLDAP($uid);
183
		}
184
		if($existsLocally && !$existsOnLDAP) {
185
			try {
186
				$user = $this->getLDAPAccess($uid)->userManager->get($uid);
187
				if($user instanceof User) {
188
					$user->markUser();
189
				}
190
			} catch (\Exception $e) {
191
				// ignore
192
			}
193
		}
194
		return $existsLocally;
195
	}
196
197
	/**
198
	 * check if a user exists on LDAP
199
	 * @param string|\OCA\User_LDAP\User\User $user either the Nextcloud user
200
	 * name or an instance of that user
201
	 * @return boolean
202
	 */
203
	public function userExistsOnLDAP($user) {
204
		$id = ($user instanceof User) ? $user->getUsername() : $user;
205
		return $this->handleRequest($id, 'userExistsOnLDAP', array($user));
206
	}
207
208
	/**
209
	 * Check if the password is correct
210
	 * @param string $uid The username
211
	 * @param string $password The password
212
	 * @return bool
213
	 *
214
	 * Check if the password is correct without logging in the user
215
	 */
216
	public function checkPassword($uid, $password) {
217
		return $this->handleRequest($uid, 'checkPassword', array($uid, $password));
218
	}
219
220
	/**
221
	 * returns the username for the given login name, if available
222
	 *
223
	 * @param string $loginName
224
	 * @return string|false
225
	 */
226
	public function loginName2UserName($loginName) {
227
		$id = 'LOGINNAME,' . $loginName;
228
		return $this->handleRequest($id, 'loginName2UserName', array($loginName));
229
	}
230
	
231
	/**
232
	 * returns the username for the given LDAP DN, if available
233
	 *
234
	 * @param string $dn
235
	 * @return string|false with the username
236
	 */
237
	public function dn2UserName($dn) {
238
		$id = 'DN,' . $dn;
239
		return $this->handleRequest($id, 'dn2UserName', array($dn));
240
	}
241
242
	/**
243
	 * get the user's home directory
244
	 * @param string $uid the username
245
	 * @return boolean
246
	 */
247
	public function getHome($uid) {
248
		return $this->handleRequest($uid, 'getHome', array($uid));
249
	}
250
251
	/**
252
	 * get display name of the user
253
	 * @param string $uid user ID of the user
254
	 * @return string display name
255
	 */
256
	public function getDisplayName($uid) {
257
		return $this->handleRequest($uid, 'getDisplayName', array($uid));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->handleRequ...playName', array($uid)) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
258
	}
259
260
	/**
261
	 * set display name of the user
262
	 *
263
	 * @param string $uid user ID of the user
264
	 * @param string $displayName new display name
265
	 * @return string display name
266
	 */
267
	public function setDisplayName($uid, $displayName) {
268
		return $this->handleRequest($uid, 'setDisplayName', array($uid, $displayName));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->handleRequ...ay($uid, $displayName)) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
269
	}
270
271
	/**
272
	 * checks whether the user is allowed to change his avatar in Nextcloud
273
	 * @param string $uid the Nextcloud user name
274
	 * @return boolean either the user can or cannot
275
	 */
276
	public function canChangeAvatar($uid) {
277
		return $this->handleRequest($uid, 'canChangeAvatar', [$uid], true);
278
	}
279
280
	/**
281
	 * Get a list of all display names and user ids.
282
	 * @param string $search
283
	 * @param string|null $limit
284
	 * @param string|null $offset
285
	 * @return array an array of all displayNames (value) and the corresponding uids (key)
286
	 */
287
	public function getDisplayNames($search = '', $limit = null, $offset = null) {
288
		//we do it just as the /OC_User implementation: do not play around with limit and offset but ask all backends
289
		$users = array();
290
		foreach($this->backends as $backend) {
291
			$backendUsers = $backend->getDisplayNames($search, $limit, $offset);
292
			if (is_array($backendUsers)) {
293
				$users = $users + $backendUsers;
294
			}
295
		}
296
		return $users;
297
	}
298
299
	/**
300
	 * delete a user
301
	 * @param string $uid The username of the user to delete
302
	 * @return bool
303
	 *
304
	 * Deletes a user
305
	 */
306
	public function deleteUser($uid) {
307
		return $this->handleRequest($uid, 'deleteUser', array($uid));
308
	}
309
	
310
	/**
311
	 * Set password
312
	 * @param string $uid The username
313
	 * @param string $password The new password
314
	 * @return bool
315
	 *
316
	 */
317
	public function setPassword($uid, $password) {
318
		return $this->handleRequest($uid, 'setPassword', array($uid, $password));
319
	}
320
321
	/**
322
	 * @return bool
323
	 */
324
	public function hasUserListings() {
325
		return $this->refBackend->hasUserListings();
326
	}
327
328
	/**
329
	 * Count the number of users
330
	 * @return int|bool
331
	 */
332
	public function countUsers() {
333
		$users = false;
334
		foreach($this->backends as $backend) {
335
			$backendUsers = $backend->countUsers();
336
			if ($backendUsers !== false) {
337
				$users += $backendUsers;
338
			}
339
		}
340
		return $users;
341
	}
342
343
	/**
344
	 * Return access for LDAP interaction.
345
	 * @param string $uid
346
	 * @return Access instance of Access for LDAP interaction
347
	 */
348
	public function getLDAPAccess($uid) {
349
		return $this->handleRequest($uid, 'getLDAPAccess', array($uid));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->handleRequ...APAccess', array($uid)) could also return false which is incompatible with the documented return type OCA\User_LDAP\Access. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
350
	}
351
	
352
	/**
353
	 * Return a new LDAP connection for the specified user.
354
	 * The connection needs to be closed manually.
355
	 * @param string $uid
356
	 * @return resource of the LDAP connection
357
	 */
358
	public function getNewLDAPConnection($uid) {
359
		return $this->handleRequest($uid, 'getNewLDAPConnection', array($uid));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->handleRequ...nnection', array($uid)) could also return false which is incompatible with the documented return type resource. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
360
	}
361
362
	/**
363
	 * Creates a new user in LDAP
364
	 * @param $username
365
	 * @param $password
366
	 * @return bool
367
	 */
368
	public function createUser($username, $password) {
369
		return $this->handleRequest($username, 'createUser', array($username,$password));
370
	}
371
}
372