Completed
Push — master ( 7130fa...91c87d )
by Lukas
07:44
created

OC_User   F

Complexity

Total Complexity 74

Size/Duplication

Total Lines 550
Duplicated Lines 6.36 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 0
Metric Value
dl 35
loc 550
rs 2.3809
c 0
b 0
f 0
wmc 74
lcom 1
cbo 17

32 Methods

Rating   Name   Duplication   Size   Complexity  
A getUserSession() 0 3 1
C useBackend() 0 33 8
A clearBackends() 0 4 1
C setupBackends() 0 30 7
A loginWithCookie() 0 3 1
B loginWithApache() 0 27 3
A handleApacheAuth() 0 14 2
A setUserId() 0 9 2
A setDisplayName() 11 11 3
A isLoggedIn() 0 3 1
A setIncognitoMode() 0 3 1
A isIncognitoMode() 0 3 1
A getLogoutAttribute() 0 15 2
A isAdminUser() 0 6 3
A getUser() 0 8 4
A getDisplayName() 0 17 4
A generatePassword() 0 3 1
A setPassword() 0 8 2
A canUserChangeAvatar() 0 8 2
A canUserChangePassword() 0 8 2
A canUserChangeDisplayName() 0 8 2
A checkPassword() 8 8 2
A getHome() 0 8 2
A getUsers() 8 8 2
A getDisplayNames() 8 8 2
A userExists() 0 3 1
A disableUser() 0 6 2
A enableUser() 0 6 2
A isEnabled() 0 8 2
A setMagicInCookie() 0 3 1
A unsetMagicInCookie() 0 3 1
A findFirstActiveUsedBackend() 0 11 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like OC_User 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 OC_User, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Aldo "xoen" Giambelluca <[email protected]>
6
 * @author Andreas Fischer <[email protected]>
7
 * @author Arthur Schiwon <[email protected]>
8
 * @author Bartek Przybylski <[email protected]>
9
 * @author Bart Visscher <[email protected]>
10
 * @author Björn Schießle <[email protected]>
11
 * @author Christoph Wurst <[email protected]>
12
 * @author Georg Ehrke <[email protected]>
13
 * @author Jakob Sack <[email protected]>
14
 * @author Jörn Friedrich Dreyer <[email protected]>
15
 * @author Lukas Reschke <[email protected]>
16
 * @author Morris Jobke <[email protected]>
17
 * @author Robin Appelman <[email protected]>
18
 * @author Robin McCorkell <[email protected]>
19
 * @author Roeland Jago Douma <[email protected]>
20
 * @author shkdee <[email protected]>
21
 * @author Thomas Müller <[email protected]>
22
 * @author Tom Needham <[email protected]>
23
 *
24
 * @license AGPL-3.0
25
 *
26
 * This code is free software: you can redistribute it and/or modify
27
 * it under the terms of the GNU Affero General Public License, version 3,
28
 * as published by the Free Software Foundation.
29
 *
30
 * This program is distributed in the hope that it will be useful,
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
 * GNU Affero General Public License for more details.
34
 *
35
 * You should have received a copy of the GNU Affero General Public License, version 3,
36
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
37
 *
38
 */
39
40
/**
41
 * This class provides wrapper methods for user management. Multiple backends are
42
 * supported. User management operations are delegated to the configured backend for
43
 * execution.
44
 *
45
 * Note that &run is deprecated and won't work anymore.
46
 *
47
 * Hooks provided:
48
 *   pre_createUser(&run, uid, password)
49
 *   post_createUser(uid, password)
50
 *   pre_deleteUser(&run, uid)
51
 *   post_deleteUser(uid)
52
 *   pre_setPassword(&run, uid, password, recoveryPassword)
53
 *   post_setPassword(uid, password, recoveryPassword)
54
 *   pre_login(&run, uid, password)
55
 *   post_login(uid)
56
 *   logout()
57
 */
58
class OC_User {
59
60
	/**
61
	 * @return \OC\User\Session
62
	 */
63
	public static function getUserSession() {
64
		return OC::$server->getUserSession();
65
	}
66
67
	private static $_usedBackends = array();
68
69
	private static $_setupedBackends = array();
70
71
	// bool, stores if a user want to access a resource anonymously, e.g if they open a public link
72
	private static $incognitoMode = false;
73
74
	/**
75
	 * Adds the backend to the list of used backends
76
	 *
77
	 * @param string|\OCP\UserInterface $backend default: database The backend to use for user management
78
	 * @return bool
79
	 *
80
	 * Set the User Authentication Module
81
	 */
82
	public static function useBackend($backend = 'database') {
83
		if ($backend instanceof \OCP\UserInterface) {
84
			self::$_usedBackends[get_class($backend)] = $backend;
85
			\OC::$server->getUserManager()->registerBackend($backend);
86
		} else {
87
			// You'll never know what happens
88
			if (null === $backend OR !is_string($backend)) {
89
				$backend = 'database';
90
			}
91
92
			// Load backend
93
			switch ($backend) {
94
				case 'database':
95
				case 'mysql':
96
				case 'sqlite':
97
					\OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', \OCP\Util::DEBUG);
98
					self::$_usedBackends[$backend] = new \OC\User\Database();
99
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
100
					break;
101
				case 'dummy':
102
					self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
103
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
104
					break;
105
				default:
106
					\OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', \OCP\Util::DEBUG);
107
					$className = 'OC_USER_' . strtoupper($backend);
108
					self::$_usedBackends[$backend] = new $className();
109
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
110
					break;
111
			}
112
		}
113
		return true;
114
	}
115
116
	/**
117
	 * remove all used backends
118
	 */
119
	public static function clearBackends() {
120
		self::$_usedBackends = array();
121
		\OC::$server->getUserManager()->clearBackends();
122
	}
123
124
	/**
125
	 * setup the configured backends in config.php
126
	 */
127
	public static function setupBackends() {
128
		OC_App::loadApps(['prelogin']);
129
		$backends = \OC::$server->getSystemConfig()->getValue('user_backends', []);
130
		if (isset($backends['default']) && !$backends['default']) {
131
			// clear default backends
132
			self::clearBackends();
133
		}
134
		foreach ($backends as $i => $config) {
135
			if (!is_array($config)) {
136
				continue;
137
			}
138
			$class = $config['class'];
139
			$arguments = $config['arguments'];
140
			if (class_exists($class)) {
141
				if (array_search($i, self::$_setupedBackends) === false) {
142
					// make a reflection object
143
					$reflectionObj = new ReflectionClass($class);
144
145
					// use Reflection to create a new instance, using the $args
146
					$backend = $reflectionObj->newInstanceArgs($arguments);
147
					self::useBackend($backend);
148
					self::$_setupedBackends[] = $i;
149
				} else {
150
					\OCP\Util::writeLog('core', 'User backend ' . $class . ' already initialized.', \OCP\Util::DEBUG);
151
				}
152
			} else {
153
				\OCP\Util::writeLog('core', 'User backend ' . $class . ' not found.', \OCP\Util::ERROR);
154
			}
155
		}
156
	}
157
158
	/**
159
160
	 * Try to login a user using the magic cookie (remember login)
161
	 *
162
	 * @deprecated use \OCP\IUserSession::loginWithCookie()
163
	 * @param string $uid The username of the user to log in
164
	 * @param string $token
165
	 * @param string $oldSessionId
166
	 * @return bool
167
	 */
168
	public static function loginWithCookie($uid, $token, $oldSessionId) {
169
		return self::getUserSession()->loginWithCookie($uid, $token, $oldSessionId);
170
	}
171
172
	/**
173
	 * Try to login a user, assuming authentication
174
	 * has already happened (e.g. via Single Sign On).
175
	 *
176
	 * Log in a user and regenerate a new session.
177
	 *
178
	 * @param \OCP\Authentication\IApacheBackend $backend
179
	 * @return bool
180
	 */
181
	public static function loginWithApache(\OCP\Authentication\IApacheBackend $backend) {
182
183
		$uid = $backend->getCurrentUserId();
184
		$run = true;
185
		OC_Hook::emit("OC_User", "pre_login", array("run" => &$run, "uid" => $uid));
186
187
		if ($uid) {
188
			if (self::getUser() !== $uid) {
189
				self::setUserId($uid);
190
				self::setDisplayName($uid);
191
				self::getUserSession()->setLoginName($uid);
192
				$request = OC::$server->getRequest();
193
				self::getUserSession()->createSessionToken($request, $uid, $uid);
194
				// setup the filesystem
195
				OC_Util::setupFS($uid);
196
				// first call the post_login hooks, the login-process needs to be
197
				// completed before we can safely create the users folder.
198
				// For example encryption needs to initialize the users keys first
199
				// before we can create the user folder with the skeleton files
200
				OC_Hook::emit("OC_User", "post_login", array("uid" => $uid, 'password' => ''));
201
				//trigger creation of user home and /files folder
202
				\OC::$server->getUserFolder($uid);
203
			}
204
			return true;
205
		}
206
		return false;
207
	}
208
209
	/**
210
	 * Verify with Apache whether user is authenticated.
211
	 *
212
	 * @return boolean|null
213
	 *          true: authenticated
214
	 *          false: not authenticated
215
	 *          null: not handled / no backend available
216
	 */
217
	public static function handleApacheAuth() {
218
		$backend = self::findFirstActiveUsedBackend();
219
		if ($backend) {
220
			OC_App::loadApps();
221
222
			//setup extra user backends
223
			self::setupBackends();
224
			self::unsetMagicInCookie();
225
226
			return self::loginWithApache($backend);
227
		}
228
229
		return null;
230
	}
231
232
233
	/**
234
	 * Sets user id for session and triggers emit
235
	 *
236
	 * @param string $uid
237
	 */
238
	public static function setUserId($uid) {
239
		$userSession = \OC::$server->getUserSession();
240
		$userManager = \OC::$server->getUserManager();
241
		if ($user = $userManager->get($uid)) {
242
			$userSession->setUser($user);
243
		} else {
244
			\OC::$server->getSession()->set('user_id', $uid);
245
		}
246
	}
247
248
	/**
249
	 * Sets user display name for session
250
	 *
251
	 * @param string $uid
252
	 * @param string $displayName
253
	 * @return bool Whether the display name could get set
254
	 */
255 View Code Duplication
	public static function setDisplayName($uid, $displayName = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
256
		if (is_null($displayName)) {
257
			$displayName = $uid;
258
		}
259
		$user = \OC::$server->getUserManager()->get($uid);
260
		if ($user) {
261
			return $user->setDisplayName($displayName);
262
		} else {
263
			return false;
264
		}
265
	}
266
267
	/**
268
	 * Check if the user is logged in, considers also the HTTP basic credentials
269
	 *
270
	 * @deprecated use \OC::$server->getUserSession()->isLoggedIn()
271
	 * @return bool
272
	 */
273
	public static function isLoggedIn() {
274
		return \OC::$server->getUserSession()->isLoggedIn();
275
	}
276
277
	/**
278
	 * set incognito mode, e.g. if a user wants to open a public link
279
	 *
280
	 * @param bool $status
281
	 */
282
	public static function setIncognitoMode($status) {
283
		self::$incognitoMode = $status;
284
	}
285
286
	/**
287
	 * get incognito mode status
288
	 *
289
	 * @return bool
290
	 */
291
	public static function isIncognitoMode() {
292
		return self::$incognitoMode;
293
	}
294
295
	/**
296
	 * Supplies an attribute to the logout hyperlink. The default behaviour
297
	 * is to return an href with '?logout=true' appended. However, it can
298
	 * supply any attribute(s) which are valid for <a>.
299
	 *
300
	 * @return string with one or more HTML attributes.
301
	 */
302
	public static function getLogoutAttribute() {
303
		$backend = self::findFirstActiveUsedBackend();
304
		if ($backend) {
305
			return $backend->getLogoutAttribute();
306
		}
307
308
		$logoutUrl = \OC::$server->getURLGenerator()->linkToRouteAbsolute(
309
			'core.login.logout',
310
			[
311
				'requesttoken' => \OCP\Util::callRegister(),
312
			]
313
		);
314
315
		return 'href="'.$logoutUrl.'"';
316
	}
317
318
	/**
319
	 * Check if the user is an admin user
320
	 *
321
	 * @param string $uid uid of the admin
322
	 * @return bool
323
	 */
324
	public static function isAdminUser($uid) {
325
		if (OC_Group::inGroup($uid, 'admin') && self::$incognitoMode === false) {
0 ignored issues
show
Deprecated Code introduced by
The method OC_Group::inGroup() has been deprecated with message: Use \OC::$server->getGroupManager->inGroup($user);

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...
326
			return true;
327
		}
328
		return false;
329
	}
330
331
332
	/**
333
	 * get the user id of the user currently logged in.
334
	 *
335
	 * @return string|bool uid or false
336
	 */
337
	public static function getUser() {
338
		$uid = \OC::$server->getSession() ? \OC::$server->getSession()->get('user_id') : null;
339
		if (!is_null($uid) && self::$incognitoMode === false) {
340
			return $uid;
341
		} else {
342
			return false;
343
		}
344
	}
345
346
	/**
347
	 * get the display name of the user currently logged in.
348
	 *
349
	 * @param string $uid
350
	 * @return string uid or false
351
	 */
352
	public static function getDisplayName($uid = null) {
353
		if ($uid) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $uid of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
354
			$user = \OC::$server->getUserManager()->get($uid);
355
			if ($user) {
356
				return $user->getDisplayName();
357
			} else {
358
				return $uid;
359
			}
360
		} else {
361
			$user = self::getUserSession()->getUser();
362
			if ($user) {
363
				return $user->getDisplayName();
364
			} else {
365
				return false;
366
			}
367
		}
368
	}
369
370
	/**
371
	 * Autogenerate a password
372
	 *
373
	 * @return string
374
	 *
375
	 * generates a password
376
	 */
377
	public static function generatePassword() {
378
		return \OC::$server->getSecureRandom()->generate(30);
379
	}
380
381
	/**
382
	 * Set password
383
	 *
384
	 * @param string $uid The username
385
	 * @param string $password The new password
386
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
387
	 * @return bool
388
	 *
389
	 * Change the password of a user
390
	 */
391
	public static function setPassword($uid, $password, $recoveryPassword = null) {
392
		$user = \OC::$server->getUserManager()->get($uid);
393
		if ($user) {
394
			return $user->setPassword($password, $recoveryPassword);
395
		} else {
396
			return false;
397
		}
398
	}
399
400
	/**
401
	 * Check whether user can change his avatar
402
	 *
403
	 * @param string $uid The username
404
	 * @return bool
405
	 *
406
	 * Check whether a specified user can change his avatar
407
	 */
408
	public static function canUserChangeAvatar($uid) {
409
		$user = \OC::$server->getUserManager()->get($uid);
410
		if ($user) {
411
			return $user->canChangeAvatar();
412
		} else {
413
			return false;
414
		}
415
	}
416
417
	/**
418
	 * Check whether user can change his password
419
	 *
420
	 * @param string $uid The username
421
	 * @return bool
422
	 *
423
	 * Check whether a specified user can change his password
424
	 */
425
	public static function canUserChangePassword($uid) {
426
		$user = \OC::$server->getUserManager()->get($uid);
427
		if ($user) {
428
			return $user->canChangePassword();
429
		} else {
430
			return false;
431
		}
432
	}
433
434
	/**
435
	 * Check whether user can change his display name
436
	 *
437
	 * @param string $uid The username
438
	 * @return bool
439
	 *
440
	 * Check whether a specified user can change his display name
441
	 */
442
	public static function canUserChangeDisplayName($uid) {
443
		$user = \OC::$server->getUserManager()->get($uid);
444
		if ($user) {
445
			return $user->canChangeDisplayName();
446
		} else {
447
			return false;
448
		}
449
	}
450
451
	/**
452
	 * Check if the password is correct
453
	 *
454
	 * @param string $uid The username
455
	 * @param string $password The password
456
	 * @return string|false user id a string on success, false otherwise
457
	 *
458
	 * Check if the password is correct without logging in the user
459
	 * returns the user id or false
460
	 */
461 View Code Duplication
	public static function checkPassword($uid, $password) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
462
		$manager = \OC::$server->getUserManager();
463
		$username = $manager->checkPassword($uid, $password);
464
		if ($username !== false) {
465
			return $username->getUID();
466
		}
467
		return false;
468
	}
469
470
	/**
471
	 * @param string $uid The username
472
	 * @return string
473
	 *
474
	 * returns the path to the users home directory
475
	 * @deprecated Use \OC::$server->getUserManager->getHome()
476
	 */
477
	public static function getHome($uid) {
478
		$user = \OC::$server->getUserManager()->get($uid);
479
		if ($user) {
480
			return $user->getHome();
481
		} else {
482
			return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
483
		}
484
	}
485
486
	/**
487
	 * Get a list of all users
488
	 *
489
	 * @return array an array of all uids
490
	 *
491
	 * Get a list of all users.
492
	 * @param string $search
493
	 * @param integer $limit
494
	 * @param integer $offset
495
	 */
496 View Code Duplication
	public static function getUsers($search = '', $limit = null, $offset = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
497
		$users = \OC::$server->getUserManager()->search($search, $limit, $offset);
498
		$uids = array();
499
		foreach ($users as $user) {
500
			$uids[] = $user->getUID();
501
		}
502
		return $uids;
503
	}
504
505
	/**
506
	 * Get a list of all users display name
507
	 *
508
	 * @param string $search
509
	 * @param int $limit
510
	 * @param int $offset
511
	 * @return array associative array with all display names (value) and corresponding uids (key)
512
	 *
513
	 * Get a list of all display names and user ids.
514
	 * @deprecated Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
515
	 */
516 View Code Duplication
	public static function getDisplayNames($search = '', $limit = null, $offset = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
517
		$displayNames = array();
518
		$users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
519
		foreach ($users as $user) {
520
			$displayNames[$user->getUID()] = $user->getDisplayName();
521
		}
522
		return $displayNames;
523
	}
524
525
	/**
526
	 * check if a user exists
527
	 *
528
	 * @param string $uid the username
529
	 * @return boolean
530
	 */
531
	public static function userExists($uid) {
532
		return \OC::$server->getUserManager()->userExists($uid);
533
	}
534
535
	/**
536
	 * disables a user
537
	 *
538
	 * @param string $uid the user to disable
539
	 */
540
	public static function disableUser($uid) {
541
		$user = \OC::$server->getUserManager()->get($uid);
542
		if ($user) {
543
			$user->setEnabled(false);
544
		}
545
	}
546
547
	/**
548
	 * enable a user
549
	 *
550
	 * @param string $uid
551
	 */
552
	public static function enableUser($uid) {
553
		$user = \OC::$server->getUserManager()->get($uid);
554
		if ($user) {
555
			$user->setEnabled(true);
556
		}
557
	}
558
559
	/**
560
	 * checks if a user is enabled
561
	 *
562
	 * @param string $uid
563
	 * @return bool
564
	 */
565
	public static function isEnabled($uid) {
566
		$user = \OC::$server->getUserManager()->get($uid);
567
		if ($user) {
568
			return $user->isEnabled();
569
		} else {
570
			return false;
571
		}
572
	}
573
574
	/**
575
	 * Set cookie value to use in next page load
576
	 *
577
	 * @param string $username username to be set
578
	 * @param string $token
579
	 */
580
	public static function setMagicInCookie($username, $token) {
581
		self::getUserSession()->setMagicInCookie($username, $token);
582
	}
583
584
	/**
585
	 * Remove cookie for "remember username"
586
	 */
587
	public static function unsetMagicInCookie() {
588
		self::getUserSession()->unsetMagicInCookie();
589
	}
590
591
	/**
592
	 * Returns the first active backend from self::$_usedBackends.
593
	 *
594
	 * @return OCP\Authentication\IApacheBackend|null if no backend active, otherwise OCP\Authentication\IApacheBackend
595
	 */
596
	private static function findFirstActiveUsedBackend() {
597
		foreach (self::$_usedBackends as $backend) {
598
			if ($backend instanceof OCP\Authentication\IApacheBackend) {
599
				if ($backend->isSessionActive()) {
600
					return $backend;
601
				}
602
			}
603
		}
604
605
		return null;
606
	}
607
}
608