Completed
Push — master ( c38f87...350aa8 )
by Lukas
27s
created

OC_User::canUserChangePassword()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
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
				$setUidAsDisplayName = true;
191
				if($backend instanceof \OCP\UserInterface
192
					&& $backend->implementsActions(OC_User_Backend::GET_DISPLAYNAME)) {
193
194
					$backendDisplayName = $backend->getDisplayName($uid);
195
					if(is_string($backendDisplayName) && trim($backendDisplayName) !== '') {
196
						$setUidAsDisplayName = false;
197
					}
198
				}
199
				if($setUidAsDisplayName) {
200
					self::setDisplayName($uid);
201
				}
202
				self::getUserSession()->setLoginName($uid);
203
				$request = OC::$server->getRequest();
204
				self::getUserSession()->createSessionToken($request, $uid, $uid);
205
				// setup the filesystem
206
				OC_Util::setupFS($uid);
207
				// first call the post_login hooks, the login-process needs to be
208
				// completed before we can safely create the users folder.
209
				// For example encryption needs to initialize the users keys first
210
				// before we can create the user folder with the skeleton files
211
				OC_Hook::emit("OC_User", "post_login", array("uid" => $uid, 'password' => ''));
212
				//trigger creation of user home and /files folder
213
				\OC::$server->getUserFolder($uid);
214
			}
215
			return true;
216
		}
217
		return false;
218
	}
219
220
	/**
221
	 * Verify with Apache whether user is authenticated.
222
	 *
223
	 * @return boolean|null
224
	 *          true: authenticated
225
	 *          false: not authenticated
226
	 *          null: not handled / no backend available
227
	 */
228
	public static function handleApacheAuth() {
229
		$backend = self::findFirstActiveUsedBackend();
230
		if ($backend) {
231
			OC_App::loadApps();
232
233
			//setup extra user backends
234
			self::setupBackends();
235
			self::unsetMagicInCookie();
236
237
			return self::loginWithApache($backend);
238
		}
239
240
		return null;
241
	}
242
243
244
	/**
245
	 * Sets user id for session and triggers emit
246
	 *
247
	 * @param string $uid
248
	 */
249
	public static function setUserId($uid) {
250
		$userSession = \OC::$server->getUserSession();
251
		$userManager = \OC::$server->getUserManager();
252
		if ($user = $userManager->get($uid)) {
253
			$userSession->setUser($user);
254
		} else {
255
			\OC::$server->getSession()->set('user_id', $uid);
256
		}
257
	}
258
259
	/**
260
	 * Sets user display name for session
261
	 *
262
	 * @param string $uid
263
	 * @param string $displayName
264
	 * @return bool Whether the display name could get set
265
	 */
266 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...
267
		if (is_null($displayName)) {
268
			$displayName = $uid;
269
		}
270
		$user = \OC::$server->getUserManager()->get($uid);
271
		if ($user) {
272
			return $user->setDisplayName($displayName);
273
		} else {
274
			return false;
275
		}
276
	}
277
278
	/**
279
	 * Check if the user is logged in, considers also the HTTP basic credentials
280
	 *
281
	 * @deprecated use \OC::$server->getUserSession()->isLoggedIn()
282
	 * @return bool
283
	 */
284
	public static function isLoggedIn() {
285
		return \OC::$server->getUserSession()->isLoggedIn();
286
	}
287
288
	/**
289
	 * set incognito mode, e.g. if a user wants to open a public link
290
	 *
291
	 * @param bool $status
292
	 */
293
	public static function setIncognitoMode($status) {
294
		self::$incognitoMode = $status;
295
	}
296
297
	/**
298
	 * get incognito mode status
299
	 *
300
	 * @return bool
301
	 */
302
	public static function isIncognitoMode() {
303
		return self::$incognitoMode;
304
	}
305
306
	/**
307
	 * Supplies an attribute to the logout hyperlink. The default behaviour
308
	 * is to return an href with '?logout=true' appended. However, it can
309
	 * supply any attribute(s) which are valid for <a>.
310
	 *
311
	 * @return string with one or more HTML attributes.
312
	 */
313
	public static function getLogoutAttribute() {
314
		$backend = self::findFirstActiveUsedBackend();
315
		if ($backend) {
316
			return $backend->getLogoutAttribute();
317
		}
318
319
		$logoutUrl = \OC::$server->getURLGenerator()->linkToRouteAbsolute(
320
			'core.login.logout',
321
			[
322
				'requesttoken' => \OCP\Util::callRegister(),
323
			]
324
		);
325
326
		return 'href="'.$logoutUrl.'"';
327
	}
328
329
	/**
330
	 * Check if the user is an admin user
331
	 *
332
	 * @param string $uid uid of the admin
333
	 * @return bool
334
	 */
335
	public static function isAdminUser($uid) {
336
		$group = \OC::$server->getGroupManager()->get('admin');
337
		$user = \OC::$server->getUserManager()->get($uid);
338
		if ($group && $user && $group->inGroup($user) && self::$incognitoMode === false) {
339
			return true;
340
		}
341
		return false;
342
	}
343
344
345
	/**
346
	 * get the user id of the user currently logged in.
347
	 *
348
	 * @return string|bool uid or false
349
	 */
350
	public static function getUser() {
351
		$uid = \OC::$server->getSession() ? \OC::$server->getSession()->get('user_id') : null;
352
		if (!is_null($uid) && self::$incognitoMode === false) {
353
			return $uid;
354
		} else {
355
			return false;
356
		}
357
	}
358
359
	/**
360
	 * get the display name of the user currently logged in.
361
	 *
362
	 * @param string $uid
363
	 * @return string uid or false
364
	 */
365
	public static function getDisplayName($uid = null) {
366
		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...
367
			$user = \OC::$server->getUserManager()->get($uid);
368
			if ($user) {
369
				return $user->getDisplayName();
370
			} else {
371
				return $uid;
372
			}
373
		} else {
374
			$user = self::getUserSession()->getUser();
375
			if ($user) {
376
				return $user->getDisplayName();
377
			} else {
378
				return false;
379
			}
380
		}
381
	}
382
383
	/**
384
	 * Autogenerate a password
385
	 *
386
	 * @return string
387
	 *
388
	 * generates a password
389
	 */
390
	public static function generatePassword() {
391
		return \OC::$server->getSecureRandom()->generate(30);
392
	}
393
394
	/**
395
	 * Set password
396
	 *
397
	 * @param string $uid The username
398
	 * @param string $password The new password
399
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
400
	 * @return bool
401
	 *
402
	 * Change the password of a user
403
	 */
404
	public static function setPassword($uid, $password, $recoveryPassword = null) {
405
		$user = \OC::$server->getUserManager()->get($uid);
406
		if ($user) {
407
			return $user->setPassword($password, $recoveryPassword);
408
		} else {
409
			return false;
410
		}
411
	}
412
413
	/**
414
	 * Check whether user can change his avatar
415
	 *
416
	 * @param string $uid The username
417
	 * @return bool
418
	 *
419
	 * Check whether a specified user can change his avatar
420
	 */
421
	public static function canUserChangeAvatar($uid) {
422
		$user = \OC::$server->getUserManager()->get($uid);
423
		if ($user) {
424
			return $user->canChangeAvatar();
425
		} else {
426
			return false;
427
		}
428
	}
429
430
	/**
431
	 * Check whether user can change his password
432
	 *
433
	 * @param string $uid The username
434
	 * @return bool
435
	 *
436
	 * Check whether a specified user can change his password
437
	 */
438
	public static function canUserChangePassword($uid) {
439
		$user = \OC::$server->getUserManager()->get($uid);
440
		if ($user) {
441
			return $user->canChangePassword();
442
		} else {
443
			return false;
444
		}
445
	}
446
447
	/**
448
	 * Check whether user can change his display name
449
	 *
450
	 * @param string $uid The username
451
	 * @return bool
452
	 *
453
	 * Check whether a specified user can change his display name
454
	 */
455
	public static function canUserChangeDisplayName($uid) {
456
		$user = \OC::$server->getUserManager()->get($uid);
457
		if ($user) {
458
			return $user->canChangeDisplayName();
459
		} else {
460
			return false;
461
		}
462
	}
463
464
	/**
465
	 * Check if the password is correct
466
	 *
467
	 * @param string $uid The username
468
	 * @param string $password The password
469
	 * @return string|false user id a string on success, false otherwise
470
	 *
471
	 * Check if the password is correct without logging in the user
472
	 * returns the user id or false
473
	 */
474 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...
475
		$manager = \OC::$server->getUserManager();
476
		$username = $manager->checkPassword($uid, $password);
477
		if ($username !== false) {
478
			return $username->getUID();
479
		}
480
		return false;
481
	}
482
483
	/**
484
	 * @param string $uid The username
485
	 * @return string
486
	 *
487
	 * returns the path to the users home directory
488
	 * @deprecated Use \OC::$server->getUserManager->getHome()
489
	 */
490
	public static function getHome($uid) {
491
		$user = \OC::$server->getUserManager()->get($uid);
492
		if ($user) {
493
			return $user->getHome();
494
		} else {
495
			return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
496
		}
497
	}
498
499
	/**
500
	 * Get a list of all users
501
	 *
502
	 * @return array an array of all uids
503
	 *
504
	 * Get a list of all users.
505
	 * @param string $search
506
	 * @param integer $limit
507
	 * @param integer $offset
508
	 */
509 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...
510
		$users = \OC::$server->getUserManager()->search($search, $limit, $offset);
511
		$uids = array();
512
		foreach ($users as $user) {
513
			$uids[] = $user->getUID();
514
		}
515
		return $uids;
516
	}
517
518
	/**
519
	 * Get a list of all users display name
520
	 *
521
	 * @param string $search
522
	 * @param int $limit
523
	 * @param int $offset
524
	 * @return array associative array with all display names (value) and corresponding uids (key)
525
	 *
526
	 * Get a list of all display names and user ids.
527
	 * @deprecated Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
528
	 */
529 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...
530
		$displayNames = array();
531
		$users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
532
		foreach ($users as $user) {
533
			$displayNames[$user->getUID()] = $user->getDisplayName();
534
		}
535
		return $displayNames;
536
	}
537
538
	/**
539
	 * check if a user exists
540
	 *
541
	 * @param string $uid the username
542
	 * @return boolean
543
	 */
544
	public static function userExists($uid) {
545
		return \OC::$server->getUserManager()->userExists($uid);
546
	}
547
548
	/**
549
	 * disables a user
550
	 *
551
	 * @param string $uid the user to disable
552
	 */
553
	public static function disableUser($uid) {
554
		$user = \OC::$server->getUserManager()->get($uid);
555
		if ($user) {
556
			$user->setEnabled(false);
557
		}
558
	}
559
560
	/**
561
	 * enable a user
562
	 *
563
	 * @param string $uid
564
	 */
565
	public static function enableUser($uid) {
566
		$user = \OC::$server->getUserManager()->get($uid);
567
		if ($user) {
568
			$user->setEnabled(true);
569
		}
570
	}
571
572
	/**
573
	 * checks if a user is enabled
574
	 *
575
	 * @param string $uid
576
	 * @return bool
577
	 */
578
	public static function isEnabled($uid) {
579
		$user = \OC::$server->getUserManager()->get($uid);
580
		if ($user) {
581
			return $user->isEnabled();
582
		} else {
583
			return false;
584
		}
585
	}
586
587
	/**
588
	 * Set cookie value to use in next page load
589
	 *
590
	 * @param string $username username to be set
591
	 * @param string $token
592
	 */
593
	public static function setMagicInCookie($username, $token) {
594
		self::getUserSession()->setMagicInCookie($username, $token);
595
	}
596
597
	/**
598
	 * Remove cookie for "remember username"
599
	 */
600
	public static function unsetMagicInCookie() {
601
		self::getUserSession()->unsetMagicInCookie();
602
	}
603
604
	/**
605
	 * Returns the first active backend from self::$_usedBackends.
606
	 *
607
	 * @return OCP\Authentication\IApacheBackend|null if no backend active, otherwise OCP\Authentication\IApacheBackend
608
	 */
609
	private static function findFirstActiveUsedBackend() {
610
		foreach (self::$_usedBackends as $backend) {
611
			if ($backend instanceof OCP\Authentication\IApacheBackend) {
612
				if ($backend->isSessionActive()) {
613
					return $backend;
614
				}
615
			}
616
		}
617
618
		return null;
619
	}
620
}
621