Passed
Push — master ( 18ff26...b73f40 )
by Christoph
12:59 queued 11s
created

OC_User::setIncognitoMode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
rs 10
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 Björn Schießle <[email protected]>
10
 * @author Christoph Wurst <[email protected]>
11
 * @author Georg Ehrke <[email protected]>
12
 * @author Jakob Sack <[email protected]>
13
 * @author Jörn Friedrich Dreyer <[email protected]>
14
 * @author Lukas Reschke <[email protected]>
15
 * @author Morris Jobke <[email protected]>
16
 * @author Robin Appelman <[email protected]>
17
 * @author Robin McCorkell <[email protected]>
18
 * @author Roeland Jago Douma <[email protected]>
19
 * @author shkdee <[email protected]>
20
 * @author Thomas Müller <[email protected]>
21
 * @author Vincent Petry <[email protected]>
22
 *
23
 * @license AGPL-3.0
24
 *
25
 * This code is free software: you can redistribute it and/or modify
26
 * it under the terms of the GNU Affero General Public License, version 3,
27
 * as published by the Free Software Foundation.
28
 *
29
 * This program is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
 * GNU Affero General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU Affero General Public License, version 3,
35
 * along with this program. If not, see <http://www.gnu.org/licenses/>
36
 *
37
 */
38
use OCP\EventDispatcher\IEventDispatcher;
39
use OCP\ILogger;
40
use OCP\IUserManager;
41
use OCP\User\Events\UserLoggedInEvent;
42
43
/**
44
 * This class provides wrapper methods for user management. Multiple backends are
45
 * supported. User management operations are delegated to the configured backend for
46
 * execution.
47
 *
48
 * Note that &run is deprecated and won't work anymore.
49
 *
50
 * Hooks provided:
51
 *   pre_createUser(&run, uid, password)
52
 *   post_createUser(uid, password)
53
 *   pre_deleteUser(&run, uid)
54
 *   post_deleteUser(uid)
55
 *   pre_setPassword(&run, uid, password, recoveryPassword)
56
 *   post_setPassword(uid, password, recoveryPassword)
57
 *   pre_login(&run, uid, password)
58
 *   post_login(uid)
59
 *   logout()
60
 */
61
class OC_User {
62
	private static $_usedBackends = [];
63
64
	private static $_setupedBackends = [];
65
66
	// bool, stores if a user want to access a resource anonymously, e.g if they open a public link
67
	private static $incognitoMode = false;
68
69
	/**
70
	 * Adds the backend to the list of used backends
71
	 *
72
	 * @param string|\OCP\UserInterface $backend default: database The backend to use for user management
73
	 * @return bool
74
	 *
75
	 * Set the User Authentication Module
76
	 * @suppress PhanDeprecatedFunction
77
	 */
78
	public static function useBackend($backend = 'database') {
79
		if ($backend instanceof \OCP\UserInterface) {
80
			self::$_usedBackends[get_class($backend)] = $backend;
81
			\OC::$server->getUserManager()->registerBackend($backend);
82
		} else {
83
			// You'll never know what happens
84
			if (null === $backend or !is_string($backend)) {
0 ignored issues
show
introduced by
The condition is_string($backend) is always true.
Loading history...
85
				$backend = 'database';
86
			}
87
88
			// Load backend
89
			switch ($backend) {
90
				case 'database':
91
				case 'mysql':
92
				case 'sqlite':
93
					\OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::DEBUG has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

93
					\OCP\Util::writeLog('core', 'Adding user backend ' . $backend . '.', /** @scrutinizer ignore-deprecated */ ILogger::DEBUG);

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
94
					self::$_usedBackends[$backend] = new \OC\User\Database();
95
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
96
					break;
97
				case 'dummy':
98
					self::$_usedBackends[$backend] = new \Test\Util\User\Dummy();
0 ignored issues
show
Bug introduced by
The type Test\Util\User\Dummy was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
99
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
100
					break;
101
				default:
102
					\OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::DEBUG has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

102
					\OCP\Util::writeLog('core', 'Adding default user backend ' . $backend . '.', /** @scrutinizer ignore-deprecated */ ILogger::DEBUG);

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
103
					$className = 'OC_USER_' . strtoupper($backend);
104
					self::$_usedBackends[$backend] = new $className();
105
					\OC::$server->getUserManager()->registerBackend(self::$_usedBackends[$backend]);
106
					break;
107
			}
108
		}
109
		return true;
110
	}
111
112
	/**
113
	 * remove all used backends
114
	 */
115
	public static function clearBackends() {
116
		self::$_usedBackends = [];
117
		\OC::$server->getUserManager()->clearBackends();
118
	}
119
120
	/**
121
	 * setup the configured backends in config.php
122
	 * @suppress PhanDeprecatedFunction
123
	 */
124
	public static function setupBackends() {
125
		OC_App::loadApps(['prelogin']);
126
		$backends = \OC::$server->getSystemConfig()->getValue('user_backends', []);
127
		if (isset($backends['default']) && !$backends['default']) {
128
			// clear default backends
129
			self::clearBackends();
130
		}
131
		foreach ($backends as $i => $config) {
132
			if (!is_array($config)) {
133
				continue;
134
			}
135
			$class = $config['class'];
136
			$arguments = $config['arguments'];
137
			if (class_exists($class)) {
138
				if (array_search($i, self::$_setupedBackends) === false) {
139
					// make a reflection object
140
					$reflectionObj = new ReflectionClass($class);
141
142
					// use Reflection to create a new instance, using the $args
143
					$backend = $reflectionObj->newInstanceArgs($arguments);
144
					self::useBackend($backend);
145
					self::$_setupedBackends[] = $i;
146
				} else {
147
					\OCP\Util::writeLog('core', 'User backend ' . $class . ' already initialized.', ILogger::DEBUG);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::DEBUG has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

147
					\OCP\Util::writeLog('core', 'User backend ' . $class . ' already initialized.', /** @scrutinizer ignore-deprecated */ ILogger::DEBUG);

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
148
				}
149
			} else {
150
				\OCP\Util::writeLog('core', 'User backend ' . $class . ' not found.', ILogger::ERROR);
0 ignored issues
show
Deprecated Code introduced by
The constant OCP\ILogger::ERROR has been deprecated: 20.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

150
				\OCP\Util::writeLog('core', 'User backend ' . $class . ' not found.', /** @scrutinizer ignore-deprecated */ ILogger::ERROR);

This class constant 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 constant will be removed from the class and what other constant to use instead.

Loading history...
151
			}
152
		}
153
	}
154
155
	/**
156
	 * Try to login a user, assuming authentication
157
	 * has already happened (e.g. via Single Sign On).
158
	 *
159
	 * Log in a user and regenerate a new session.
160
	 *
161
	 * @param \OCP\Authentication\IApacheBackend $backend
162
	 * @return bool
163
	 */
164
	public static function loginWithApache(\OCP\Authentication\IApacheBackend $backend) {
165
		$uid = $backend->getCurrentUserId();
166
		$run = true;
167
		OC_Hook::emit("OC_User", "pre_login", ["run" => &$run, "uid" => $uid, 'backend' => $backend]);
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(
183
					'OC_User',
184
					'post_login',
185
					[
186
						'uid' => $uid,
187
						'password' => '',
188
						'isTokenLogin' => false,
189
					]
190
				);
191
				/** @var IEventDispatcher $dispatcher */
192
				$dispatcher = \OC::$server->get(IEventDispatcher::class);
193
				$dispatcher->dispatchTyped(new UserLoggedInEvent(
194
						\OC::$server->get(IUserManager::class)->get($uid),
195
						$uid,
196
						'',
197
						false)
198
				);
199
200
				//trigger creation of user home and /files folder
201
				\OC::$server->getUserFolder($uid);
202
			}
203
			return true;
204
		}
205
		return false;
206
	}
207
208
	/**
209
	 * Verify with Apache whether user is authenticated.
210
	 *
211
	 * @return boolean|null
212
	 *          true: authenticated
213
	 *          false: not authenticated
214
	 *          null: not handled / no backend available
215
	 */
216
	public static function handleApacheAuth() {
217
		$backend = self::findFirstActiveUsedBackend();
218
		if ($backend) {
219
			OC_App::loadApps();
220
221
			//setup extra user backends
222
			self::setupBackends();
223
			\OC::$server->getUserSession()->unsetMagicInCookie();
224
225
			return self::loginWithApache($backend);
226
		}
227
228
		return null;
229
	}
230
231
232
	/**
233
	 * Sets user id for session and triggers emit
234
	 *
235
	 * @param string $uid
236
	 */
237
	public static function setUserId($uid) {
238
		$userSession = \OC::$server->getUserSession();
239
		$userManager = \OC::$server->getUserManager();
240
		if ($user = $userManager->get($uid)) {
241
			$userSession->setUser($user);
242
		} else {
243
			\OC::$server->getSession()->set('user_id', $uid);
244
		}
245
	}
246
247
	/**
248
	 * Check if the user is logged in, considers also the HTTP basic credentials
249
	 *
250
	 * @deprecated use \OC::$server->getUserSession()->isLoggedIn()
251
	 * @return bool
252
	 */
253
	public static function isLoggedIn() {
254
		return \OC::$server->getUserSession()->isLoggedIn();
255
	}
256
257
	/**
258
	 * set incognito mode, e.g. if a user wants to open a public link
259
	 *
260
	 * @param bool $status
261
	 */
262
	public static function setIncognitoMode($status) {
263
		self::$incognitoMode = $status;
264
	}
265
266
	/**
267
	 * get incognito mode status
268
	 *
269
	 * @return bool
270
	 */
271
	public static function isIncognitoMode() {
272
		return self::$incognitoMode;
273
	}
274
275
	/**
276
	 * Returns the current logout URL valid for the currently logged-in user
277
	 *
278
	 * @param \OCP\IURLGenerator $urlGenerator
279
	 * @return string
280
	 */
281
	public static function getLogoutUrl(\OCP\IURLGenerator $urlGenerator) {
282
		$backend = self::findFirstActiveUsedBackend();
283
		if ($backend) {
284
			return $backend->getLogoutUrl();
285
		}
286
287
		$user = \OC::$server->getUserSession()->getUser();
288
		if ($user instanceof \OCP\IUser) {
0 ignored issues
show
introduced by
$user is always a sub-type of OCP\IUser.
Loading history...
289
			$backend = $user->getBackend();
290
			if ($backend instanceof \OCP\User\Backend\ICustomLogout) {
291
				return $backend->getLogoutUrl();
292
			}
293
		}
294
295
		$logoutUrl = $urlGenerator->linkToRoute('core.login.logout');
296
		$logoutUrl .= '?requesttoken=' . urlencode(\OCP\Util::callRegister());
297
298
		return $logoutUrl;
299
	}
300
301
	/**
302
	 * Check if the user is an admin user
303
	 *
304
	 * @param string $uid uid of the admin
305
	 * @return bool
306
	 */
307
	public static function isAdminUser($uid) {
308
		$group = \OC::$server->getGroupManager()->get('admin');
309
		$user = \OC::$server->getUserManager()->get($uid);
310
		if ($group && $user && $group->inGroup($user) && self::$incognitoMode === false) {
311
			return true;
312
		}
313
		return false;
314
	}
315
316
317
	/**
318
	 * get the user id of the user currently logged in.
319
	 *
320
	 * @return string|bool uid or false
321
	 */
322
	public static function getUser() {
323
		$uid = \OC::$server->getSession() ? \OC::$server->getSession()->get('user_id') : null;
324
		if (!is_null($uid) && self::$incognitoMode === false) {
325
			return $uid;
326
		} else {
327
			return false;
328
		}
329
	}
330
331
	/**
332
	 * Set password
333
	 *
334
	 * @param string $uid The username
335
	 * @param string $password The new password
336
	 * @param string $recoveryPassword for the encryption app to reset encryption keys
337
	 * @return bool
338
	 *
339
	 * Change the password of a user
340
	 */
341
	public static function setPassword($uid, $password, $recoveryPassword = null) {
342
		$user = \OC::$server->getUserManager()->get($uid);
343
		if ($user) {
344
			return $user->setPassword($password, $recoveryPassword);
345
		} else {
346
			return false;
347
		}
348
	}
349
350
	/**
351
	 * @param string $uid The username
352
	 * @return string
353
	 *
354
	 * returns the path to the users home directory
355
	 * @deprecated Use \OC::$server->getUserManager->getHome()
356
	 */
357
	public static function getHome($uid) {
358
		$user = \OC::$server->getUserManager()->get($uid);
359
		if ($user) {
360
			return $user->getHome();
361
		} else {
362
			return \OC::$server->getSystemConfig()->getValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $uid;
363
		}
364
	}
365
366
	/**
367
	 * Get a list of all users display name
368
	 *
369
	 * @param string $search
370
	 * @param int $limit
371
	 * @param int $offset
372
	 * @return array associative array with all display names (value) and corresponding uids (key)
373
	 *
374
	 * Get a list of all display names and user ids.
375
	 * @deprecated Use \OC::$server->getUserManager->searchDisplayName($search, $limit, $offset) instead.
376
	 */
377
	public static function getDisplayNames($search = '', $limit = null, $offset = null) {
378
		$displayNames = [];
379
		$users = \OC::$server->getUserManager()->searchDisplayName($search, $limit, $offset);
380
		foreach ($users as $user) {
381
			$displayNames[$user->getUID()] = $user->getDisplayName();
382
		}
383
		return $displayNames;
384
	}
385
386
	/**
387
	 * Returns the first active backend from self::$_usedBackends.
388
	 *
389
	 * @return OCP\Authentication\IApacheBackend|null if no backend active, otherwise OCP\Authentication\IApacheBackend
390
	 */
391
	private static function findFirstActiveUsedBackend() {
392
		foreach (self::$_usedBackends as $backend) {
393
			if ($backend instanceof OCP\Authentication\IApacheBackend) {
394
				if ($backend->isSessionActive()) {
395
					return $backend;
396
				}
397
			}
398
		}
399
400
		return null;
401
	}
402
}
403