Passed
Push — master ( e9bf19...6a088d )
by Roeland
20:34 queued 09:56
created
core/Controller/LoginController.php 1 patch
Indentation   +304 added lines, -304 removed lines patch added patch discarded remove patch
@@ -59,308 +59,308 @@
 block discarded – undo
59 59
 
60 60
 class LoginController extends Controller {
61 61
 
62
-	const LOGIN_MSG_INVALIDPASSWORD = 'invalidpassword';
63
-	const LOGIN_MSG_USERDISABLED = 'userdisabled';
64
-
65
-	/** @var IUserManager */
66
-	private $userManager;
67
-	/** @var IConfig */
68
-	private $config;
69
-	/** @var ISession */
70
-	private $session;
71
-	/** @var IUserSession|Session */
72
-	private $userSession;
73
-	/** @var IURLGenerator */
74
-	private $urlGenerator;
75
-	/** @var ILogger */
76
-	private $logger;
77
-	/** @var Defaults */
78
-	private $defaults;
79
-	/** @var Throttler */
80
-	private $throttler;
81
-	/** @var Chain */
82
-	private $loginChain;
83
-	/** @var IInitialStateService */
84
-	private $initialStateService;
85
-
86
-	public function __construct(?string $appName,
87
-								IRequest $request,
88
-								IUserManager $userManager,
89
-								IConfig $config,
90
-								ISession $session,
91
-								IUserSession $userSession,
92
-								IURLGenerator $urlGenerator,
93
-								ILogger $logger,
94
-								Defaults $defaults,
95
-								Throttler $throttler,
96
-								Chain $loginChain,
97
-								IInitialStateService $initialStateService) {
98
-		parent::__construct($appName, $request);
99
-		$this->userManager = $userManager;
100
-		$this->config = $config;
101
-		$this->session = $session;
102
-		$this->userSession = $userSession;
103
-		$this->urlGenerator = $urlGenerator;
104
-		$this->logger = $logger;
105
-		$this->defaults = $defaults;
106
-		$this->throttler = $throttler;
107
-		$this->loginChain = $loginChain;
108
-		$this->initialStateService = $initialStateService;
109
-	}
110
-
111
-	/**
112
-	 * @NoAdminRequired
113
-	 * @UseSession
114
-	 *
115
-	 * @return RedirectResponse
116
-	 */
117
-	public function logout() {
118
-		$loginToken = $this->request->getCookie('nc_token');
119
-		if (!is_null($loginToken)) {
120
-			$this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
121
-		}
122
-		$this->userSession->logout();
123
-
124
-		$response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute(
125
-			'core.login.showLoginForm',
126
-			['clear' => true] // this param the the code in login.js may be removed when the "Clear-Site-Data" is working in the browsers
127
-		));
128
-
129
-		$this->session->set('clearingExecutionContexts', '1');
130
-		$this->session->close();
131
-		$response->addHeader('Clear-Site-Data', '"cache", "storage"');
132
-		return $response;
133
-	}
134
-
135
-	/**
136
-	 * @PublicPage
137
-	 * @NoCSRFRequired
138
-	 * @UseSession
139
-	 *
140
-	 * @param string $user
141
-	 * @param string $redirect_url
142
-	 *
143
-	 * @return TemplateResponse|RedirectResponse
144
-	 */
145
-	public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
146
-		if ($this->userSession->isLoggedIn()) {
147
-			return new RedirectResponse(OC_Util::getDefaultPageUrl());
148
-		}
149
-
150
-		$loginMessages = $this->session->get('loginMessages');
151
-		if (is_array($loginMessages)) {
152
-			list($errors, $messages) = $loginMessages;
153
-			$this->initialStateService->provideInitialState('core', 'loginMessages', $messages);
154
-			$this->initialStateService->provideInitialState('core', 'loginErrors', $errors);
155
-		}
156
-		$this->session->remove('loginMessages');
157
-
158
-		if ($user !== null && $user !== '') {
159
-			$this->initialStateService->provideInitialState('core', 'loginUsername', $user);
160
-		} else {
161
-			$this->initialStateService->provideInitialState('core', 'loginUsername', '');
162
-		}
163
-
164
-		$this->initialStateService->provideInitialState(
165
-			'core',
166
-			'loginAutocomplete',
167
-			$this->config->getSystemValue('login_form_autocomplete', true) === true
168
-		);
169
-
170
-		if (!empty($redirect_url)) {
171
-			$this->initialStateService->provideInitialState('core', 'loginRedirectUrl', $redirect_url);
172
-		}
173
-
174
-		$this->initialStateService->provideInitialState(
175
-			'core',
176
-			'loginThrottleDelay',
177
-			$this->throttler->getDelay($this->request->getRemoteAddress())
178
-		);
179
-
180
-		$this->setPasswordResetInitialState($user);
181
-
182
-		// OpenGraph Support: http://ogp.me/
183
-		Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
184
-		Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
185
-		Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
186
-		Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
187
-		Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
188
-		Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
189
-
190
-		$parameters = [
191
-			'alt_login' => OC_App::getAlternativeLogIns(),
192
-		];
193
-		return new TemplateResponse(
194
-			$this->appName, 'login', $parameters, 'guest'
195
-		);
196
-	}
197
-
198
-	/**
199
-	 * Sets the password reset state
200
-	 *
201
-	 * @param string $username
202
-	 */
203
-	private function setPasswordResetInitialState(?string $username): void {
204
-		if ($username !== null && $username !== '') {
205
-			$user = $this->userManager->get($username);
206
-		} else {
207
-			$user = null;
208
-		}
209
-
210
-		$passwordLink = $this->config->getSystemValue('lost_password_link', '');
211
-
212
-		$this->initialStateService->provideInitialState(
213
-			'core',
214
-			'loginResetPasswordLink',
215
-			$passwordLink
216
-		);
217
-
218
-		$this->initialStateService->provideInitialState(
219
-			'core',
220
-			'loginCanResetPassword',
221
-			$this->canResetPassword($passwordLink, $user)
222
-		);
223
-	}
224
-
225
-	/**
226
-	 * @param string|null $passwordLink
227
-	 * @param IUser|null $user
228
-	 *
229
-	 * Users may not change their passwords if:
230
-	 * - The account is disabled
231
-	 * - The backend doesn't support password resets
232
-	 * - The password reset function is disabled
233
-	 *
234
-	 * @return bool
235
-	 */
236
-	private function canResetPassword(?string $passwordLink, ?IUser $user): bool {
237
-		if ($passwordLink === 'disabled') {
238
-			return false;
239
-		}
240
-
241
-		if (!$passwordLink && $user !== null) {
242
-			return $user->canChangePassword();
243
-		}
244
-
245
-		if ($user !== null && $user->isEnabled() === false) {
246
-			return false;
247
-		}
248
-
249
-		return true;
250
-	}
251
-
252
-	private function generateRedirect(?string $redirectUrl): RedirectResponse {
253
-		if ($redirectUrl !== null && $this->userSession->isLoggedIn()) {
254
-			$location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
255
-			// Deny the redirect if the URL contains a @
256
-			// This prevents unvalidated redirects like ?redirect_url=:[email protected]
257
-			if (strpos($location, '@') === false) {
258
-				return new RedirectResponse($location);
259
-			}
260
-		}
261
-		return new RedirectResponse(OC_Util::getDefaultPageUrl());
262
-	}
263
-
264
-	/**
265
-	 * @PublicPage
266
-	 * @UseSession
267
-	 * @NoCSRFRequired
268
-	 * @BruteForceProtection(action=login)
269
-	 *
270
-	 * @param string $user
271
-	 * @param string $password
272
-	 * @param string $redirect_url
273
-	 * @param string $timezone
274
-	 * @param string $timezone_offset
275
-	 *
276
-	 * @return RedirectResponse
277
-	 */
278
-	public function tryLogin(string $user,
279
-							 string $password,
280
-							 string $redirect_url = null,
281
-							 string $timezone = '',
282
-							 string $timezone_offset = ''): RedirectResponse {
283
-		// If the user is already logged in and the CSRF check does not pass then
284
-		// simply redirect the user to the correct page as required. This is the
285
-		// case when an user has already logged-in, in another tab.
286
-		if (!$this->request->passesCSRFCheck()) {
287
-			return $this->generateRedirect($redirect_url);
288
-		}
289
-
290
-		$data = new LoginData(
291
-			$this->request,
292
-			$user,
293
-			$password,
294
-			$redirect_url,
295
-			$timezone,
296
-			$timezone_offset
297
-		);
298
-		$result = $this->loginChain->process($data);
299
-		if (!$result->isSuccess()) {
300
-			return $this->createLoginFailedResponse(
301
-				$data->getUsername(),
302
-				$user,
303
-				$redirect_url,
304
-				$result->getErrorMessage()
305
-			);
306
-		}
307
-
308
-		if ($result->getRedirectUrl() !== null) {
309
-			return new RedirectResponse($result->getRedirectUrl());
310
-		}
311
-		return $this->generateRedirect($redirect_url);
312
-	}
313
-
314
-	/**
315
-	 * Creates a login failed response.
316
-	 *
317
-	 * @param string $user
318
-	 * @param string $originalUser
319
-	 * @param string $redirect_url
320
-	 * @param string $loginMessage
321
-	 *
322
-	 * @return RedirectResponse
323
-	 */
324
-	private function createLoginFailedResponse(
325
-		$user, $originalUser, $redirect_url, string $loginMessage) {
326
-		// Read current user and append if possible we need to
327
-		// return the unmodified user otherwise we will leak the login name
328
-		$args = $user !== null ? ['user' => $originalUser] : [];
329
-		if ($redirect_url !== null) {
330
-			$args['redirect_url'] = $redirect_url;
331
-		}
332
-		$response = new RedirectResponse(
333
-			$this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)
334
-		);
335
-		$response->throttle(['user' => substr($user, 0, 64)]);
336
-		$this->session->set('loginMessages', [
337
-			[$loginMessage], []
338
-		]);
339
-		return $response;
340
-	}
341
-
342
-	/**
343
-	 * @NoAdminRequired
344
-	 * @UseSession
345
-	 * @BruteForceProtection(action=sudo)
346
-	 *
347
-	 * @param string $password
348
-	 *
349
-	 * @return DataResponse
350
-	 * @license GNU AGPL version 3 or any later version
351
-	 *
352
-	 */
353
-	public function confirmPassword($password) {
354
-		$loginName = $this->userSession->getLoginName();
355
-		$loginResult = $this->userManager->checkPassword($loginName, $password);
356
-		if ($loginResult === false) {
357
-			$response = new DataResponse([], Http::STATUS_FORBIDDEN);
358
-			$response->throttle();
359
-			return $response;
360
-		}
361
-
362
-		$confirmTimestamp = time();
363
-		$this->session->set('last-password-confirm', $confirmTimestamp);
364
-		return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
365
-	}
62
+    const LOGIN_MSG_INVALIDPASSWORD = 'invalidpassword';
63
+    const LOGIN_MSG_USERDISABLED = 'userdisabled';
64
+
65
+    /** @var IUserManager */
66
+    private $userManager;
67
+    /** @var IConfig */
68
+    private $config;
69
+    /** @var ISession */
70
+    private $session;
71
+    /** @var IUserSession|Session */
72
+    private $userSession;
73
+    /** @var IURLGenerator */
74
+    private $urlGenerator;
75
+    /** @var ILogger */
76
+    private $logger;
77
+    /** @var Defaults */
78
+    private $defaults;
79
+    /** @var Throttler */
80
+    private $throttler;
81
+    /** @var Chain */
82
+    private $loginChain;
83
+    /** @var IInitialStateService */
84
+    private $initialStateService;
85
+
86
+    public function __construct(?string $appName,
87
+                                IRequest $request,
88
+                                IUserManager $userManager,
89
+                                IConfig $config,
90
+                                ISession $session,
91
+                                IUserSession $userSession,
92
+                                IURLGenerator $urlGenerator,
93
+                                ILogger $logger,
94
+                                Defaults $defaults,
95
+                                Throttler $throttler,
96
+                                Chain $loginChain,
97
+                                IInitialStateService $initialStateService) {
98
+        parent::__construct($appName, $request);
99
+        $this->userManager = $userManager;
100
+        $this->config = $config;
101
+        $this->session = $session;
102
+        $this->userSession = $userSession;
103
+        $this->urlGenerator = $urlGenerator;
104
+        $this->logger = $logger;
105
+        $this->defaults = $defaults;
106
+        $this->throttler = $throttler;
107
+        $this->loginChain = $loginChain;
108
+        $this->initialStateService = $initialStateService;
109
+    }
110
+
111
+    /**
112
+     * @NoAdminRequired
113
+     * @UseSession
114
+     *
115
+     * @return RedirectResponse
116
+     */
117
+    public function logout() {
118
+        $loginToken = $this->request->getCookie('nc_token');
119
+        if (!is_null($loginToken)) {
120
+            $this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
121
+        }
122
+        $this->userSession->logout();
123
+
124
+        $response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute(
125
+            'core.login.showLoginForm',
126
+            ['clear' => true] // this param the the code in login.js may be removed when the "Clear-Site-Data" is working in the browsers
127
+        ));
128
+
129
+        $this->session->set('clearingExecutionContexts', '1');
130
+        $this->session->close();
131
+        $response->addHeader('Clear-Site-Data', '"cache", "storage"');
132
+        return $response;
133
+    }
134
+
135
+    /**
136
+     * @PublicPage
137
+     * @NoCSRFRequired
138
+     * @UseSession
139
+     *
140
+     * @param string $user
141
+     * @param string $redirect_url
142
+     *
143
+     * @return TemplateResponse|RedirectResponse
144
+     */
145
+    public function showLoginForm(string $user = null, string $redirect_url = null): Http\Response {
146
+        if ($this->userSession->isLoggedIn()) {
147
+            return new RedirectResponse(OC_Util::getDefaultPageUrl());
148
+        }
149
+
150
+        $loginMessages = $this->session->get('loginMessages');
151
+        if (is_array($loginMessages)) {
152
+            list($errors, $messages) = $loginMessages;
153
+            $this->initialStateService->provideInitialState('core', 'loginMessages', $messages);
154
+            $this->initialStateService->provideInitialState('core', 'loginErrors', $errors);
155
+        }
156
+        $this->session->remove('loginMessages');
157
+
158
+        if ($user !== null && $user !== '') {
159
+            $this->initialStateService->provideInitialState('core', 'loginUsername', $user);
160
+        } else {
161
+            $this->initialStateService->provideInitialState('core', 'loginUsername', '');
162
+        }
163
+
164
+        $this->initialStateService->provideInitialState(
165
+            'core',
166
+            'loginAutocomplete',
167
+            $this->config->getSystemValue('login_form_autocomplete', true) === true
168
+        );
169
+
170
+        if (!empty($redirect_url)) {
171
+            $this->initialStateService->provideInitialState('core', 'loginRedirectUrl', $redirect_url);
172
+        }
173
+
174
+        $this->initialStateService->provideInitialState(
175
+            'core',
176
+            'loginThrottleDelay',
177
+            $this->throttler->getDelay($this->request->getRemoteAddress())
178
+        );
179
+
180
+        $this->setPasswordResetInitialState($user);
181
+
182
+        // OpenGraph Support: http://ogp.me/
183
+        Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
184
+        Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
185
+        Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
186
+        Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
187
+        Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
188
+        Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
189
+
190
+        $parameters = [
191
+            'alt_login' => OC_App::getAlternativeLogIns(),
192
+        ];
193
+        return new TemplateResponse(
194
+            $this->appName, 'login', $parameters, 'guest'
195
+        );
196
+    }
197
+
198
+    /**
199
+     * Sets the password reset state
200
+     *
201
+     * @param string $username
202
+     */
203
+    private function setPasswordResetInitialState(?string $username): void {
204
+        if ($username !== null && $username !== '') {
205
+            $user = $this->userManager->get($username);
206
+        } else {
207
+            $user = null;
208
+        }
209
+
210
+        $passwordLink = $this->config->getSystemValue('lost_password_link', '');
211
+
212
+        $this->initialStateService->provideInitialState(
213
+            'core',
214
+            'loginResetPasswordLink',
215
+            $passwordLink
216
+        );
217
+
218
+        $this->initialStateService->provideInitialState(
219
+            'core',
220
+            'loginCanResetPassword',
221
+            $this->canResetPassword($passwordLink, $user)
222
+        );
223
+    }
224
+
225
+    /**
226
+     * @param string|null $passwordLink
227
+     * @param IUser|null $user
228
+     *
229
+     * Users may not change their passwords if:
230
+     * - The account is disabled
231
+     * - The backend doesn't support password resets
232
+     * - The password reset function is disabled
233
+     *
234
+     * @return bool
235
+     */
236
+    private function canResetPassword(?string $passwordLink, ?IUser $user): bool {
237
+        if ($passwordLink === 'disabled') {
238
+            return false;
239
+        }
240
+
241
+        if (!$passwordLink && $user !== null) {
242
+            return $user->canChangePassword();
243
+        }
244
+
245
+        if ($user !== null && $user->isEnabled() === false) {
246
+            return false;
247
+        }
248
+
249
+        return true;
250
+    }
251
+
252
+    private function generateRedirect(?string $redirectUrl): RedirectResponse {
253
+        if ($redirectUrl !== null && $this->userSession->isLoggedIn()) {
254
+            $location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
255
+            // Deny the redirect if the URL contains a @
256
+            // This prevents unvalidated redirects like ?redirect_url=:[email protected]
257
+            if (strpos($location, '@') === false) {
258
+                return new RedirectResponse($location);
259
+            }
260
+        }
261
+        return new RedirectResponse(OC_Util::getDefaultPageUrl());
262
+    }
263
+
264
+    /**
265
+     * @PublicPage
266
+     * @UseSession
267
+     * @NoCSRFRequired
268
+     * @BruteForceProtection(action=login)
269
+     *
270
+     * @param string $user
271
+     * @param string $password
272
+     * @param string $redirect_url
273
+     * @param string $timezone
274
+     * @param string $timezone_offset
275
+     *
276
+     * @return RedirectResponse
277
+     */
278
+    public function tryLogin(string $user,
279
+                                string $password,
280
+                                string $redirect_url = null,
281
+                                string $timezone = '',
282
+                                string $timezone_offset = ''): RedirectResponse {
283
+        // If the user is already logged in and the CSRF check does not pass then
284
+        // simply redirect the user to the correct page as required. This is the
285
+        // case when an user has already logged-in, in another tab.
286
+        if (!$this->request->passesCSRFCheck()) {
287
+            return $this->generateRedirect($redirect_url);
288
+        }
289
+
290
+        $data = new LoginData(
291
+            $this->request,
292
+            $user,
293
+            $password,
294
+            $redirect_url,
295
+            $timezone,
296
+            $timezone_offset
297
+        );
298
+        $result = $this->loginChain->process($data);
299
+        if (!$result->isSuccess()) {
300
+            return $this->createLoginFailedResponse(
301
+                $data->getUsername(),
302
+                $user,
303
+                $redirect_url,
304
+                $result->getErrorMessage()
305
+            );
306
+        }
307
+
308
+        if ($result->getRedirectUrl() !== null) {
309
+            return new RedirectResponse($result->getRedirectUrl());
310
+        }
311
+        return $this->generateRedirect($redirect_url);
312
+    }
313
+
314
+    /**
315
+     * Creates a login failed response.
316
+     *
317
+     * @param string $user
318
+     * @param string $originalUser
319
+     * @param string $redirect_url
320
+     * @param string $loginMessage
321
+     *
322
+     * @return RedirectResponse
323
+     */
324
+    private function createLoginFailedResponse(
325
+        $user, $originalUser, $redirect_url, string $loginMessage) {
326
+        // Read current user and append if possible we need to
327
+        // return the unmodified user otherwise we will leak the login name
328
+        $args = $user !== null ? ['user' => $originalUser] : [];
329
+        if ($redirect_url !== null) {
330
+            $args['redirect_url'] = $redirect_url;
331
+        }
332
+        $response = new RedirectResponse(
333
+            $this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)
334
+        );
335
+        $response->throttle(['user' => substr($user, 0, 64)]);
336
+        $this->session->set('loginMessages', [
337
+            [$loginMessage], []
338
+        ]);
339
+        return $response;
340
+    }
341
+
342
+    /**
343
+     * @NoAdminRequired
344
+     * @UseSession
345
+     * @BruteForceProtection(action=sudo)
346
+     *
347
+     * @param string $password
348
+     *
349
+     * @return DataResponse
350
+     * @license GNU AGPL version 3 or any later version
351
+     *
352
+     */
353
+    public function confirmPassword($password) {
354
+        $loginName = $this->userSession->getLoginName();
355
+        $loginResult = $this->userManager->checkPassword($loginName, $password);
356
+        if ($loginResult === false) {
357
+            $response = new DataResponse([], Http::STATUS_FORBIDDEN);
358
+            $response->throttle();
359
+            return $response;
360
+        }
361
+
362
+        $confirmTimestamp = time();
363
+        $this->session->set('last-password-confirm', $confirmTimestamp);
364
+        return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
365
+    }
366 366
 }
Please login to merge, or discard this patch.