Completed
Push — master ( ca2904...0b464e )
by Morris
22:04
created

OC_User::loginWithApache()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 16
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 27
rs 8.8571
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 Bart Visscher <[email protected]>
9
 * @author Bartek Przybylski <[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
 * @author Vincent Petry <[email protected]>
24
 *
25
 * @license AGPL-3.0
26
 *
27
 * This code is free software: you can redistribute it and/or modify
28
 * it under the terms of the GNU Affero General Public License, version 3,
29
 * as published by the Free Software Foundation.
30
 *
31
 * This program is distributed in the hope that it will be useful,
32
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
 * GNU Affero General Public License for more details.
35
 *
36
 * You should have received a copy of the GNU Affero General Public License, version 3,
37
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
38
 *
39
 */
40
41
/**
42
 * This class provides wrapper methods for user management. Multiple backends are
43
 * supported. User management operations are delegated to the configured backend for
44
 * execution.
45
 *
46
 * Note that &run is deprecated and won't work anymore.
47
 *
48
 * Hooks provided:
49
 *   pre_createUser(&run, uid, password)
50
 *   post_createUser(uid, password)
51
 *   pre_deleteUser(&run, uid)
52
 *   post_deleteUser(uid)
53
 *   pre_setPassword(&run, uid, password, recoveryPassword)
54
 *   post_setPassword(uid, password, recoveryPassword)
55
 *   pre_login(&run, uid, password)
56
 *   post_login(uid)
57
 *   logout()
58
 */
59
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...
60
61
	private static $_usedBackends = array();
62
63
	private static $_setupedBackends = array();
64
65
	// bool, stores if a user want to access a resource anonymously, e.g if they open a public link
66
	private static $incognitoMode = false;
67
68
	/**
69
	 * Adds the backend to the list of used backends
70
	 *
71
	 * @param string|\OCP\UserInterface $backend default: database The backend to use for user management
72
	 * @return bool
73
	 *
74
	 * Set the User Authentication Module
75
	 * @suppress PhanDeprecatedFunction
76
	 */
77
	public static function useBackend($backend = 'database') {
78
		if ($backend instanceof \OCP\UserInterface) {
79
			self::$_usedBackends[get_class($backend)] = $backend;
80
			\OC::$server->getUserManager()->registerBackend($backend);
81
		} else {
82
			// You'll never know what happens
83
			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...
84
				$backend = 'database';
85
			}
86
87
			// Load backend
88
			switch ($backend) {
89
				case 'database':
90
				case 'mysql':
91
				case 'sqlite':
92
					\OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', \OCP\Util::DEBUG);
93
					self::$_usedBackends[$backend] = new \OC\User\Database();
94
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
95
					break;
96
				case 'dummy':
97
					self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
98
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
99
					break;
100
				default:
101
					\OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', \OCP\Util::DEBUG);
102
					$className = 'OC_USER_' . strtoupper($backend);
103
					self::$_usedBackends[$backend] = new $className();
104
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
105
					break;
106
			}
107
		}
108
		return true;
109
	}
110
111
	/**
112
	 * remove all used backends
113
	 */
114
	public static function clearBackends() {
115
		self::$_usedBackends = array();
116
		\OC::$server->getUserManager()->clearBackends();
117
	}
118
119
	/**
120
	 * setup the configured backends in config.php
121
	 * @suppress PhanDeprecatedFunction
122
	 */
123
	public static function setupBackends() {
124
		OC_App::loadApps(['prelogin']);
125
		$backends = \OC::$server->getSystemConfig()->getValue('user_backends', []);
126
		if (isset($backends['default']) && !$backends['default']) {
127
			// clear default backends
128
			self::clearBackends();
129
		}
130
		foreach ($backends as $i => $config) {
131
			if (!is_array($config)) {
132
				continue;
133
			}
134
			$class = $config['class'];
135
			$arguments = $config['arguments'];
136
			if (class_exists($class)) {
137
				if (array_search($i, self::$_setupedBackends) === false) {
138
					// make a reflection object
139
					$reflectionObj = new ReflectionClass($class);
140
141
					// use Reflection to create a new instance, using the $args
142
					$backend = $reflectionObj->newInstanceArgs($arguments);
143
					self::useBackend($backend);
144
					self::$_setupedBackends[] = $i;
145
				} else {
146
					\OCP\Util::writeLog('core', 'User backend ' . $class . ' already initialized.', \OCP\Util::DEBUG);
147
				}
148
			} else {
149
				\OCP\Util::writeLog('core', 'User backend ' . $class . ' not found.', \OCP\Util::ERROR);
150
			}
151
		}
152
	}
153
154
	/**
155
	 * Try to login a user, assuming authentication
156
	 * has already happened (e.g. via Single Sign On).
157
	 *
158
	 * Log in a user and regenerate a new session.
159
	 *
160
	 * @param \OCP\Authentication\IApacheBackend $backend
161
	 * @return bool
162
	 */
163
	public static function loginWithApache(\OCP\Authentication\IApacheBackend $backend) {
164
165
		$uid = $backend->getCurrentUserId();
166
		$run = true;
167
		OC_Hook::emit("OC_User", "pre_login", array("run" => &$run, "uid" => $uid));
168
169
		if ($uid) {
170
			if (self::getUser() !== $uid) {
171
				self::setUserId($uid);
172
				$userSession = \OC::$server->getUserSession();
173
				$userSession->setLoginName($uid);
174
				$request = OC::$server->getRequest();
175
				$userSession->createSessionToken($request, $uid, $uid);
176
				// setup the filesystem
177
				OC_Util::setupFS($uid);
178
				// first call the post_login hooks, the login-process needs to be
179
				// completed before we can safely create the users folder.
180
				// For example encryption needs to initialize the users keys first
181
				// before we can create the user folder with the skeleton files
182
				OC_Hook::emit("OC_User", "post_login", array("uid" => $uid, 'password' => ''));
183
				//trigger creation of user home and /files folder
184
				\OC::$server->getUserFolder($uid);
185
			}
186
			return true;
187
		}
188
		return false;
189
	}
190
191
	/**
192
	 * Verify with Apache whether user is authenticated.
193
	 *
194
	 * @return boolean|null
195
	 *          true: authenticated
196
	 *          false: not authenticated
197
	 *          null: not handled / no backend available
198
	 */
199
	public static function handleApacheAuth() {
200
		$backend = self::findFirstActiveUsedBackend();
201
		if ($backend) {
202
			OC_App::loadApps();
203
204
			//setup extra user backends
205
			self::setupBackends();
206
			\OC::$server->getUserSession()->unsetMagicInCookie();
207
208
			return self::loginWithApache($backend);
209
		}
210
211
		return null;
212
	}
213
214
215
	/**
216
	 * Sets user id for session and triggers emit
217
	 *
218
	 * @param string $uid
219
	 */
220
	public static function setUserId($uid) {
221
		$userSession = \OC::$server->getUserSession();
222
		$userManager = \OC::$server->getUserManager();
223
		if ($user = $userManager->get($uid)) {
224
			$userSession->setUser($user);
225
		} else {
226
			\OC::$server->getSession()->set('user_id', $uid);
227
		}
228
	}
229
230
	/**
231
	 * Check if the user is logged in, considers also the HTTP basic credentials
232
	 *
233
	 * @deprecated use \OC::$server->getUserSession()->isLoggedIn()
234
	 * @return bool
235
	 */
236
	public static function isLoggedIn() {
237
		return \OC::$server->getUserSession()->isLoggedIn();
238
	}
239
240
	/**
241
	 * set incognito mode, e.g. if a user wants to open a public link
242
	 *
243
	 * @param bool $status
244
	 */
245
	public static function setIncognitoMode($status) {
246
		self::$incognitoMode = $status;
247
	}
248
249
	/**
250
	 * get incognito mode status
251
	 *
252
	 * @return bool
253
	 */
254
	public static function isIncognitoMode() {
255
		return self::$incognitoMode;
256
	}
257
258
	/**
259
	 * Returns the current logout URL valid for the currently logged-in user
260
	 *
261
	 * @param \OCP\IURLGenerator $urlGenerator
262
	 * @return string
263
	 */
264
	public static function getLogoutUrl(\OCP\IURLGenerator $urlGenerator) {
265
		$backend = self::findFirstActiveUsedBackend();
266
		if ($backend) {
267
			return $backend->getLogoutUrl();
268
		}
269
270
		$logoutUrl = $urlGenerator->linkToRouteAbsolute(
271
			'core.login.logout',
272
			[
273
				'requesttoken' => \OCP\Util::callRegister(),
274
			]
275
		);
276
277
		return $logoutUrl;
278
	}
279
280
	/**
281
	 * Check if the user is an admin user
282
	 *
283
	 * @param string $uid uid of the admin
284
	 * @return bool
285
	 */
286
	public static function isAdminUser($uid) {
287
		$group = \OC::$server->getGroupManager()->get('admin');
288
		$user = \OC::$server->getUserManager()->get($uid);
289
		if ($group && $user && $group->inGroup($user) && self::$incognitoMode === false) {
290
			return true;
291
		}
292
		return false;
293
	}
294
295
296
	/**
297
	 * get the user id of the user currently logged in.
298
	 *
299
	 * @return string|bool uid or false
300
	 */
301
	public static function getUser() {
302
		$uid = \OC::$server->getSession() ? \OC::$server->getSession()->get('user_id') : null;
303
		if (!is_null($uid) && self::$incognitoMode === false) {
304
			return $uid;
305
		} else {
306
			return false;
307
		}
308
	}
309
310
	/**
311
	 * get the display name of the user currently logged in.
312
	 *
313
	 * @param string $uid
314
	 * @return string|bool uid or false
315
	 */
316
	public static function getDisplayName($uid = null) {
317
		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...
318
			$user = \OC::$server->getUserManager()->get($uid);
319
			if ($user) {
320
				return $user->getDisplayName();
321
			} else {
322
				return $uid;
323
			}
324
		} else {
325
			$user = \OC::$server->getUserSession()->getUser();
326
			if ($user) {
327
				return $user->getDisplayName();
328
			} else {
329
				return false;
330
			}
331
		}
332
	}
333
334
	/**
335
	 * Set password
336
	 *
337
	 * @param string $uid The username
338
	 * @param string $password The new password
339
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
340
	 * @return bool
341
	 *
342
	 * Change the password of a user
343
	 */
344
	public static function setPassword($uid, $password, $recoveryPassword = null) {
345
		$user = \OC::$server->getUserManager()->get($uid);
346
		if ($user) {
347
			return $user->setPassword($password, $recoveryPassword);
348
		} else {
349
			return false;
350
		}
351
	}
352
353
	/**
354
	 * @param string $uid The username
355
	 * @return string
356
	 *
357
	 * returns the path to the users home directory
358
	 * @deprecated Use \OC::$server->getUserManager->getHome()
359
	 */
360
	public static function getHome($uid) {
361
		$user = \OC::$server->getUserManager()->get($uid);
362
		if ($user) {
363
			return $user->getHome();
364
		} else {
365
			return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
366
		}
367
	}
368
369
	/**
370
	 * Get a list of all users
371
	 *
372
	 * @return array an array of all uids
373
	 *
374
	 * Get a list of all users.
375
	 * @param string $search
376
	 * @param integer $limit
377
	 * @param integer $offset
378
	 */
379 View Code Duplication
	public static function getUsers($search = '', $limit = null, $offset = null) {
380
		$users = \OC::$server->getUserManager()->search($search, $limit, $offset);
381
		$uids = array();
382
		foreach ($users as $user) {
383
			$uids[] = $user->getUID();
384
		}
385
		return $uids;
386
	}
387
388
	/**
389
	 * Get a list of all users display name
390
	 *
391
	 * @param string $search
392
	 * @param int $limit
393
	 * @param int $offset
394
	 * @return array associative array with all display names (value) and corresponding uids (key)
395
	 *
396
	 * Get a list of all display names and user ids.
397
	 * @deprecated Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
398
	 */
399 View Code Duplication
	public static function getDisplayNames($search = '', $limit = null, $offset = null) {
400
		$displayNames = array();
401
		$users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
402
		foreach ($users as $user) {
403
			$displayNames[$user->getUID()] = $user->getDisplayName();
404
		}
405
		return $displayNames;
406
	}
407
408
	/**
409
	 * Returns the first active backend from self::$_usedBackends.
410
	 *
411
	 * @return OCP\Authentication\IApacheBackend|null if no backend active, otherwise OCP\Authentication\IApacheBackend
412
	 */
413
	private static function findFirstActiveUsedBackend() {
414
		foreach (self::$_usedBackends as $backend) {
415
			if ($backend instanceof OCP\Authentication\IApacheBackend) {
416
				if ($backend->isSessionActive()) {
417
					return $backend;
418
				}
419
			}
420
		}
421
422
		return null;
423
	}
424
}
425