Completed
Push — master ( ca3aef...5b2d6b )
by Morris
15:49
created

ChangePasswordController::changeUserPassword()   D

Complexity

Conditions 20
Paths 19

Size

Total Lines 144
Code Lines 101

Duplication

Lines 8
Ratio 5.56 %

Importance

Changes 0
Metric Value
cc 20
eloc 101
nc 19
nop 3
dl 8
loc 144
rs 4.7294
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 *
4
 * @author Roeland Jago Douma <[email protected]>
5
 *
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
namespace OC\Settings\Controller;
23
24
use OC\HintException;
25
use OC\User\Session;
26
use OCP\App\IAppManager;
27
use OCP\AppFramework\Controller;
28
use OCP\AppFramework\Http\JSONResponse;
29
use OCP\IGroupManager;
30
use OCP\IL10N;
31
use OCP\IRequest;
32
use OCP\IUser;
33
use OCP\IUserManager;
34
use OCP\IUserSession;
35
36
class ChangePasswordController extends Controller {
37
38
	/** @var string */
39
	private $userId;
40
41
	/** @var IUserManager */
42
	private $userManager;
43
44
	/** @var IL10N */
45
	private $l;
46
47
	/** @var IGroupManager */
48
	private $groupManager;
49
50
	/** @var Session */
51
	private $userSession;
52
53
	/** @var IAppManager */
54
	private $appManager;
55
56
	/**
57
	 * ChangePasswordController constructor.
58
	 *
59
	 * @param string $appName
60
	 * @param IRequest $request
61
	 * @param $userId
62
	 * @param IUserManager $userManager
63
	 * @param IUserSession $userSession
64
	 * @param IGroupManager $groupManager
65
	 * @param IAppManager $appManager
66
	 * @param IL10N $l
67
	 */
68
	public function __construct($appName,
69
								IRequest $request,
70
								$userId,
71
								IUserManager $userManager,
72
								IUserSession $userSession,
73
								IGroupManager $groupManager,
74
								IAppManager $appManager,
75
								IL10N $l) {
76
		parent::__construct($appName, $request);
77
78
		$this->userId = $userId;
79
		$this->userManager = $userManager;
80
		$this->userSession = $userSession;
0 ignored issues
show
Documentation Bug introduced by
$userSession is of type object<OCP\IUserSession>, but the property $userSession was declared to be of type object<OC\User\Session>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
81
		$this->groupManager = $groupManager;
82
		$this->appManager = $appManager;
83
		$this->l = $l;
84
	}
85
86
	/**
87
	 * @NoAdminRequired
88
	 * @NoSubadminRequired
89
	 * @BruteForceProtection(action=changePersonalPassword)
90
	 *
91
	 * @param string $oldpassword
92
	 * @param string $newpassword
93
	 *
94
	 * @return JSONResponse
95
	 */
96
	public function changePersonalPassword($oldpassword = '', $newpassword = null) {
97
		/** @var IUser $user */
98
		$user = $this->userManager->checkPassword($this->userId, $oldpassword);
99 View Code Duplication
		if ($user === false) {
100
			$response = new JSONResponse([
101
				'status' => 'error',
102
				'data' => [
103
					'message' => $this->l->t('Wrong password'),
104
				],
105
			]);
106
			$response->throttle();
107
			return $response;
108
		}
109
110
		try {
111
			if ($newpassword === null || $user->setPassword($newpassword) === false) {
112
				return new JSONResponse([
113
					'status' => 'error'
114
				]);
115
			}
116
		// password policy app throws exception
117
		} catch(HintException $e) {
118
			return new JSONResponse([
119
				'status' => 'error',
120
				'data' => [
121
					'message' => $e->getHint(),
122
				],
123
			]);
124
		}
125
126
		$this->userSession->updateSessionTokenPassword($newpassword);
127
128
		return new JSONResponse([
129
			'status' => 'success',
130
			'data' => [
131
				'message' => $this->l->t('Saved'),
132
			],
133
		]);
134
	}
135
136
	/**
137
	 * @NoAdminRequired
138
	 * @PasswordConfirmationRequired
139
	 *
140
	 * @param string $username
141
	 * @param string $password
142
	 * @param string $recoveryPassword
143
	 *
144
	 * @return JSONResponse
145
	 */
146
	public function changeUserPassword($username = null, $password = null, $recoveryPassword = null) {
147
		if ($username === null) {
148
			return new JSONResponse([
149
				'status' => 'error',
150
				'data' => [
151
					'message' => $this->l->t('No user supplied'),
152
				],
153
			]);
154
		}
155
156
		if ($password === null) {
157
			return new JSONResponse([
158
				'status' => 'error',
159
				'data' => [
160
					'message' => $this->l->t('Unable to change password'),
161
				],
162
			]);
163
		}
164
165
		$currentUser = $this->userSession->getUser();
166
		$targetUser = $this->userManager->get($username);
167
		if ($currentUser === null || $targetUser === null ||
168
			!($this->groupManager->isAdmin($this->userId) ||
169
			 $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
170
		) {
171
			return new JSONResponse([
172
				'status' => 'error',
173
				'data' => [
174
					'message' => $this->l->t('Authentication error'),
175
				],
176
			]);
177
		}
178
179
		if ($this->appManager->isEnabledForUser('encryption')) {
180
			//handle the recovery case
181
			$crypt = new \OCA\Encryption\Crypto\Crypt(
182
				\OC::$server->getLogger(),
183
				\OC::$server->getUserSession(),
184
				\OC::$server->getConfig(),
185
				\OC::$server->getL10N('encryption'));
186
			$keyStorage = \OC::$server->getEncryptionKeyStorage();
187
			$util = new \OCA\Encryption\Util(
188
				new \OC\Files\View(),
189
				$crypt,
190
				\OC::$server->getLogger(),
191
				\OC::$server->getUserSession(),
192
				\OC::$server->getConfig(),
193
				\OC::$server->getUserManager());
194
			$keyManager = new \OCA\Encryption\KeyManager(
195
				$keyStorage,
196
				$crypt,
197
				\OC::$server->getConfig(),
198
				\OC::$server->getUserSession(),
199
				new \OCA\Encryption\Session(\OC::$server->getSession()),
200
				\OC::$server->getLogger(),
201
				$util);
202
			$recovery = new \OCA\Encryption\Recovery(
203
				\OC::$server->getUserSession(),
204
				$crypt,
205
				\OC::$server->getSecureRandom(),
206
				$keyManager,
207
				\OC::$server->getConfig(),
208
				$keyStorage,
209
				\OC::$server->getEncryptionFilesHelper(),
210
				new \OC\Files\View());
211
			$recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled();
212
213
			$validRecoveryPassword = false;
214
			$recoveryEnabledForUser = false;
215
			if ($recoveryAdminEnabled) {
216
				$validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword);
217
				$recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username);
218
			}
219
220
			if ($recoveryEnabledForUser && $recoveryPassword === '') {
221
				return new JSONResponse([
222
					'status' => 'error',
223
					'data' => [
224
						'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'),
225
					]
226
				]);
227
			} elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) {
228
				return new JSONResponse([
229
					'status' => 'error',
230
					'data' => [
231
						'message' => $this->l->t('Wrong admin recovery password. Please check the password and try again.'),
232
					]
233
				]);
234
			} else { // now we know that everything is fine regarding the recovery password, let's try to change the password
235
				try {
236
					$result = $targetUser->setPassword($password, $recoveryPassword);
237
				// password policy app throws exception
238
				} catch(HintException $e) {
239
					return new JSONResponse([
240
						'status' => 'error',
241
						'data' => [
242
							'message' => $e->getHint(),
243
						],
244
					]);
245
				}
246
				if (!$result && $recoveryEnabledForUser) {
247
					return new JSONResponse([
248
						'status' => 'error',
249
						'data' => [
250
							'message' => $this->l->t('Backend doesn\'t support password change, but the user\'s encryption key was updated.'),
251
						]
252
					]);
253
				} elseif (!$result && !$recoveryEnabledForUser) {
254
					return new JSONResponse([
255
						'status' => 'error',
256
						'data' => [
257
							'message' => $this->l->t('Unable to change password'),
258
						]
259
					]);
260
				}
261
			}
262
		} else {
263
			try {
264 View Code Duplication
				if ($targetUser->setPassword($password) === false) {
265
					return new JSONResponse([
266
						'status' => 'error',
267
						'data' => [
268
							'message' => $this->l->t('Unable to change password'),
269
						],
270
					]);
271
				}
272
			// password policy app throws exception
273
			} catch(HintException $e) {
274
				return new JSONResponse([
275
					'status' => 'error',
276
					'data' => [
277
						'message' => $e->getHint(),
278
					],
279
				]);
280
			}
281
		}
282
283
		return new JSONResponse([
284
			'status' => 'success',
285
			'data' => [
286
				'username' => $username,
287
			],
288
		]);
289
	}
290
}
291