Completed
Push — master ( 5bc0ed...184f25 )
by Morris
16:18
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 {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
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)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

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