|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @author Christoph Wurst <[email protected]> |
|
4
|
|
|
* @author Joas Schilling <[email protected]> |
|
5
|
|
|
* @author Lukas Reschke <[email protected]> |
|
6
|
|
|
* @author Semih Serhat Karakaya <[email protected]> |
|
7
|
|
|
* @author Thomas Müller <[email protected]> |
|
8
|
|
|
* |
|
9
|
|
|
* @copyright Copyright (c) 2018, ownCloud GmbH |
|
10
|
|
|
* @license AGPL-3.0 |
|
11
|
|
|
* |
|
12
|
|
|
* This code is free software: you can redistribute it and/or modify |
|
13
|
|
|
* it under the terms of the GNU Affero General Public License, version 3, |
|
14
|
|
|
* as published by the Free Software Foundation. |
|
15
|
|
|
* |
|
16
|
|
|
* This program is distributed in the hope that it will be useful, |
|
17
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
19
|
|
|
* GNU Affero General Public License for more details. |
|
20
|
|
|
* |
|
21
|
|
|
* You should have received a copy of the GNU Affero General Public License, version 3, |
|
22
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|
23
|
|
|
* |
|
24
|
|
|
*/ |
|
25
|
|
|
|
|
26
|
|
|
namespace OC\Core\Controller; |
|
27
|
|
|
|
|
28
|
|
|
use OC\Authentication\TwoFactorAuth\Manager; |
|
29
|
|
|
use OC\User\Session; |
|
30
|
|
|
use OC_App; |
|
31
|
|
|
use OC_Util; |
|
32
|
|
|
use OCP\AppFramework\Controller; |
|
33
|
|
|
use OCP\AppFramework\Http\RedirectResponse; |
|
34
|
|
|
use OCP\AppFramework\Http\TemplateResponse; |
|
35
|
|
|
use OCP\IConfig; |
|
36
|
|
|
use OCP\IRequest; |
|
37
|
|
|
use OCP\ISession; |
|
38
|
|
|
use OCP\IURLGenerator; |
|
39
|
|
|
use OCP\IUser; |
|
40
|
|
|
use OCP\IUserManager; |
|
41
|
|
|
|
|
42
|
|
|
class LoginController extends Controller { |
|
43
|
|
|
|
|
44
|
|
|
/** @var IUserManager */ |
|
45
|
|
|
private $userManager; |
|
46
|
|
|
|
|
47
|
|
|
/** @var IConfig */ |
|
48
|
|
|
private $config; |
|
49
|
|
|
|
|
50
|
|
|
/** @var ISession */ |
|
51
|
|
|
private $session; |
|
52
|
|
|
|
|
53
|
|
|
/** @var Session */ |
|
54
|
|
|
private $userSession; |
|
55
|
|
|
|
|
56
|
|
|
/** @var IURLGenerator */ |
|
57
|
|
|
private $urlGenerator; |
|
58
|
|
|
|
|
59
|
|
|
/** @var Manager */ |
|
60
|
|
|
private $twoFactorManager; |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* @param string $appName |
|
64
|
|
|
* @param IRequest $request |
|
65
|
|
|
* @param IUserManager $userManager |
|
66
|
|
|
* @param IConfig $config |
|
67
|
|
|
* @param ISession $session |
|
68
|
|
|
* @param Session $userSession |
|
69
|
|
|
* @param IURLGenerator $urlGenerator |
|
70
|
|
|
* @param Manager $twoFactorManager |
|
71
|
|
|
*/ |
|
72
|
|
|
public function __construct($appName, IRequest $request, IUserManager $userManager, IConfig $config, ISession $session, |
|
73
|
|
|
Session $userSession, IURLGenerator $urlGenerator, Manager $twoFactorManager) { |
|
74
|
|
|
parent::__construct($appName, $request); |
|
75
|
|
|
$this->userManager = $userManager; |
|
76
|
|
|
$this->config = $config; |
|
77
|
|
|
$this->session = $session; |
|
78
|
|
|
$this->userSession = $userSession; |
|
79
|
|
|
$this->urlGenerator = $urlGenerator; |
|
80
|
|
|
$this->twoFactorManager = $twoFactorManager; |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
/** |
|
84
|
|
|
* @NoAdminRequired |
|
85
|
|
|
* @UseSession |
|
86
|
|
|
* |
|
87
|
|
|
* @return RedirectResponse |
|
88
|
|
|
*/ |
|
89
|
|
View Code Duplication |
public function logout() { |
|
90
|
|
|
$loginToken = $this->request->getCookie('oc_token'); |
|
91
|
|
|
if ($loginToken !== null) { |
|
92
|
|
|
$this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken); |
|
93
|
|
|
} |
|
94
|
|
|
$this->userSession->logout(); |
|
95
|
|
|
|
|
96
|
|
|
return new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('core.login.showLoginForm')); |
|
97
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
/** |
|
100
|
|
|
* @PublicPage |
|
101
|
|
|
* @NoCSRFRequired |
|
102
|
|
|
* @UseSession |
|
103
|
|
|
* |
|
104
|
|
|
* @param string $user |
|
105
|
|
|
* @param string $redirect_url |
|
106
|
|
|
* @param string $remember_login |
|
107
|
|
|
* |
|
108
|
|
|
* @return TemplateResponse|RedirectResponse |
|
109
|
|
|
*/ |
|
110
|
|
|
public function showLoginForm($user, $redirect_url, $remember_login) { |
|
111
|
|
|
if (\OC_User::handleApacheAuth() || $this->userSession->isLoggedIn()) { |
|
112
|
|
|
return new RedirectResponse($this->getDefaultUrl()); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
$parameters = []; |
|
116
|
|
|
$loginMessages = $this->session->get('loginMessages'); |
|
117
|
|
|
$errors = []; |
|
118
|
|
|
$messages = []; |
|
119
|
|
|
if (\is_array($loginMessages)) { |
|
120
|
|
|
list($errors, $messages) = $loginMessages; |
|
121
|
|
|
} |
|
122
|
|
|
$this->session->remove('loginMessages'); |
|
123
|
|
|
foreach ($errors as $value) { |
|
124
|
|
|
$parameters[$value] = true; |
|
125
|
|
|
} |
|
126
|
|
|
|
|
127
|
|
|
$parameters['messages'] = $messages; |
|
128
|
|
View Code Duplication |
if ($user !== null && $user !== '') { |
|
|
|
|
|
|
129
|
|
|
$parameters['loginName'] = $user; |
|
130
|
|
|
$parameters['user_autofocus'] = false; |
|
131
|
|
|
} else { |
|
132
|
|
|
$parameters['loginName'] = ''; |
|
133
|
|
|
$parameters['user_autofocus'] = true; |
|
134
|
|
|
} |
|
135
|
|
|
if (!empty($redirect_url)) { |
|
136
|
|
|
$parameters['redirect_url'] = $redirect_url; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
$parameters['canResetPassword'] = true; |
|
140
|
|
|
$parameters['resetPasswordLink'] = $this->config->getSystemValue('lost_password_link', ''); |
|
141
|
|
|
if (!$parameters['resetPasswordLink']) { |
|
142
|
|
|
if ($user !== null && $user !== '') { |
|
143
|
|
|
$userObj = $this->userManager->get($user); |
|
144
|
|
|
if ($userObj instanceof IUser) { |
|
145
|
|
|
$parameters['canResetPassword'] = $userObj->canChangePassword(); |
|
146
|
|
|
} |
|
147
|
|
|
} |
|
148
|
|
|
} elseif ($parameters['resetPasswordLink'] === 'disabled') { |
|
149
|
|
|
$parameters['canResetPassword'] = false; |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
$altLogins = OC_App::getAlternativeLogIns(); |
|
153
|
|
|
$altLogins2 = $this->config->getSystemValue('login.alternatives'); |
|
154
|
|
|
if (\is_array($altLogins2) && !empty($altLogins2)) { |
|
155
|
|
|
$altLogins = \array_merge($altLogins, $altLogins2); |
|
156
|
|
|
} |
|
157
|
|
|
$parameters['alt_login'] = $altLogins; |
|
158
|
|
|
$parameters['rememberLoginAllowed'] = OC_Util::rememberLoginAllowed(); |
|
159
|
|
|
$parameters['rememberLoginState'] = !empty($remember_login) ? $remember_login : 0; |
|
160
|
|
|
|
|
161
|
|
View Code Duplication |
if ($user !== null && $user !== '') { |
|
|
|
|
|
|
162
|
|
|
$parameters['loginName'] = $user; |
|
163
|
|
|
$parameters['user_autofocus'] = false; |
|
164
|
|
|
} else { |
|
165
|
|
|
$parameters['loginName'] = ''; |
|
166
|
|
|
$parameters['user_autofocus'] = true; |
|
167
|
|
|
} |
|
168
|
|
|
|
|
169
|
|
|
/** |
|
170
|
|
|
* If redirect_url is not empty and remember_login is null and |
|
171
|
|
|
* user not logged in and check if the string |
|
172
|
|
|
* webroot+"/index.php/f/" is in redirect_url then |
|
173
|
|
|
* user is trying to access files for which he needs to login. |
|
174
|
|
|
*/ |
|
175
|
|
|
|
|
176
|
|
|
if (!empty($redirect_url) && ($remember_login === null) && |
|
177
|
|
|
($this->userSession->isLoggedIn() === false) && |
|
178
|
|
|
(\strpos($this->urlGenerator->getAbsoluteURL(\urldecode($redirect_url)), |
|
179
|
|
|
$this->urlGenerator->getAbsoluteURL('/index.php/f/')) !== false)) { |
|
180
|
|
|
$parameters['accessLink'] = true; |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
return new TemplateResponse( |
|
184
|
|
|
$this->appName, 'login', $parameters, 'guest' |
|
185
|
|
|
); |
|
186
|
|
|
} |
|
187
|
|
|
|
|
188
|
|
|
/** |
|
189
|
|
|
* @PublicPage |
|
190
|
|
|
* @UseSession |
|
191
|
|
|
* |
|
192
|
|
|
* @param string $user |
|
193
|
|
|
* @param string $password |
|
194
|
|
|
* @param string $redirect_url |
|
195
|
|
|
* @param string $timezone |
|
196
|
|
|
* @return RedirectResponse |
|
197
|
|
|
* @throws \OCP\PreConditionNotMetException |
|
198
|
|
|
* @throws \OC\User\LoginException |
|
199
|
|
|
*/ |
|
200
|
|
|
public function tryLogin($user, $password, $redirect_url, $timezone = null) { |
|
201
|
|
|
$originalUser = $user; |
|
202
|
|
|
// TODO: Add all the insane error handling |
|
203
|
|
|
$loginResult = $this->userSession->login($user, $password); |
|
204
|
|
|
if ($loginResult !== true) { |
|
205
|
|
|
$users = $this->userManager->getByEmail($user); |
|
206
|
|
|
// we only allow login by email if unique |
|
207
|
|
|
if (\count($users) === 1) { |
|
208
|
|
|
$user = $users[0]->getUID(); |
|
209
|
|
|
$loginResult = $this->userSession->login($user, $password); |
|
210
|
|
|
} |
|
211
|
|
|
} |
|
212
|
|
|
if ($loginResult !== true) { |
|
213
|
|
|
$this->session->set('loginMessages', [ |
|
214
|
|
|
['invalidpassword'], [] |
|
215
|
|
|
]); |
|
216
|
|
|
$args = []; |
|
217
|
|
|
// Read current user and append if possible - we need to return the unmodified user otherwise we will leak the login name |
|
218
|
|
|
if ($user !== null) { |
|
219
|
|
|
$args['user'] = $originalUser; |
|
220
|
|
|
} |
|
221
|
|
|
// keep the redirect url |
|
222
|
|
|
if (!empty($redirect_url)) { |
|
223
|
|
|
$args['redirect_url'] = $redirect_url; |
|
224
|
|
|
} |
|
225
|
|
|
return new RedirectResponse($this->urlGenerator->linkToRoute('core.login.showLoginForm', $args)); |
|
226
|
|
|
} |
|
227
|
|
|
/* @var $userObject IUser */ |
|
228
|
|
|
$userObject = $this->userSession->getUser(); |
|
229
|
|
|
// TODO: remove password checks from above and let the user session handle failures |
|
230
|
|
|
// requires https://github.com/owncloud/core/pull/24616 |
|
231
|
|
|
$this->userSession->createSessionToken($this->request, $userObject->getUID(), $user, $password); |
|
232
|
|
|
|
|
233
|
|
|
// User has successfully logged in, now remove the password reset link, when it is available |
|
234
|
|
|
$this->config->deleteUserValue($userObject->getUID(), 'owncloud', 'lostpassword'); |
|
235
|
|
|
|
|
236
|
|
|
// Save the timezone |
|
237
|
|
|
if ($timezone !== null) { |
|
238
|
|
|
$this->config->setUserValue($userObject->getUID(), 'core', 'timezone', $timezone); |
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
if ($this->twoFactorManager->isTwoFactorAuthenticated($userObject)) { |
|
242
|
|
|
$this->twoFactorManager->prepareTwoFactorLogin($userObject); |
|
243
|
|
|
if ($redirect_url !== null) { |
|
244
|
|
|
return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.selectChallenge', [ |
|
245
|
|
|
'redirect_url' => $redirect_url |
|
246
|
|
|
])); |
|
247
|
|
|
} |
|
248
|
|
|
return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.selectChallenge')); |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
if ($redirect_url !== null && $this->userSession->isLoggedIn()) { |
|
252
|
|
|
$location = $this->urlGenerator->getAbsoluteURL(\urldecode($redirect_url)); |
|
253
|
|
|
// Deny the redirect if the URL contains a @ |
|
254
|
|
|
// This prevents unvalidated redirects like ?redirect_url=:[email protected] |
|
255
|
|
|
if (\strpos($location, '@') === false) { |
|
256
|
|
|
return new RedirectResponse($location); |
|
257
|
|
|
} |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
return new RedirectResponse($this->getDefaultUrl()); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
/** |
|
264
|
|
|
* @return string |
|
265
|
|
|
*/ |
|
266
|
|
|
protected function getDefaultUrl() { |
|
267
|
|
|
return OC_Util::getDefaultPageUrl(); |
|
268
|
|
|
} |
|
269
|
|
|
|
|
270
|
|
|
/** |
|
271
|
|
|
* @return ISession |
|
272
|
|
|
*/ |
|
273
|
|
|
public function getSession() { |
|
274
|
|
|
return $this->session; |
|
275
|
|
|
} |
|
276
|
|
|
} |
|
277
|
|
|
|
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.