AppPasswordController   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 46
c 2
b 0
f 0
dl 0
loc 100
rs 10
wmc 11

4 Methods

Rating   Name   Duplication   Size   Complexity  
A deleteAppPassword() 0 15 3
A getAppPassword() 0 38 4
A rotateAppPassword() 0 18 3
A __construct() 0 10 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @copyright Copyright (c) 2018, Roeland Jago Douma <[email protected]>
7
 *
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Daniel Kesselberg <[email protected]>
10
 * @author Roeland Jago Douma <[email protected]>
11
 *
12
 * @license GNU AGPL version 3 or any later version
13
 *
14
 * This program is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License as
16
 * published by the Free Software Foundation, either version 3 of the
17
 * License, or (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26
 *
27
 */
28
namespace OC\Core\Controller;
29
30
use OC\Authentication\Events\AppPasswordCreatedEvent;
31
use OC\Authentication\Exceptions\InvalidTokenException;
32
use OC\Authentication\Token\IProvider;
33
use OC\Authentication\Token\IToken;
34
use OCP\AppFramework\Http\DataResponse;
35
use OCP\AppFramework\OCS\OCSForbiddenException;
36
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
37
use OCP\Authentication\Exceptions\PasswordUnavailableException;
38
use OCP\Authentication\LoginCredentials\IStore;
39
use OCP\EventDispatcher\IEventDispatcher;
40
use OCP\IRequest;
41
use OCP\ISession;
42
use OCP\Security\ISecureRandom;
43
44
class AppPasswordController extends \OCP\AppFramework\OCSController {
45
	public function __construct(
46
		string $appName,
47
		IRequest $request,
48
		private ISession $session,
49
		private ISecureRandom $random,
50
		private IProvider $tokenProvider,
51
		private IStore $credentialStore,
52
		private IEventDispatcher $eventDispatcher,
53
	) {
54
		parent::__construct($appName, $request);
55
	}
56
57
	/**
58
	 * @NoAdminRequired
59
	 *
60
	 * @throws OCSForbiddenException
61
	 */
62
	public function getAppPassword(): DataResponse {
63
		// We do not allow the creation of new tokens if this is an app password
64
		if ($this->session->exists('app_password')) {
65
			throw new OCSForbiddenException('You cannot request an new apppassword with an apppassword');
66
		}
67
68
		try {
69
			$credentials = $this->credentialStore->getLoginCredentials();
70
		} catch (CredentialsUnavailableException $e) {
71
			throw new OCSForbiddenException();
72
		}
73
74
		try {
75
			$password = $credentials->getPassword();
76
		} catch (PasswordUnavailableException $e) {
77
			$password = null;
78
		}
79
80
		$userAgent = $this->request->getHeader('USER_AGENT');
81
82
		$token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
83
84
		$generatedToken = $this->tokenProvider->generateToken(
85
			$token,
86
			$credentials->getUID(),
87
			$credentials->getLoginName(),
88
			$password,
89
			$userAgent,
90
			IToken::PERMANENT_TOKEN,
91
			IToken::DO_NOT_REMEMBER
92
		);
93
94
		$this->eventDispatcher->dispatchTyped(
95
			new AppPasswordCreatedEvent($generatedToken)
96
		);
97
98
		return new DataResponse([
99
			'apppassword' => $token
100
		]);
101
	}
102
103
	/**
104
	 * @NoAdminRequired
105
	 */
106
	public function deleteAppPassword(): DataResponse {
107
		if (!$this->session->exists('app_password')) {
108
			throw new OCSForbiddenException('no app password in use');
109
		}
110
111
		$appPassword = $this->session->get('app_password');
112
113
		try {
114
			$token = $this->tokenProvider->getToken($appPassword);
115
		} catch (InvalidTokenException $e) {
116
			throw new OCSForbiddenException('could not remove apptoken');
117
		}
118
119
		$this->tokenProvider->invalidateTokenById($token->getUID(), $token->getId());
120
		return new DataResponse();
121
	}
122
123
	/**
124
	 * @NoAdminRequired
125
	 */
126
	public function rotateAppPassword(): DataResponse {
127
		if (!$this->session->exists('app_password')) {
128
			throw new OCSForbiddenException('no app password in use');
129
		}
130
131
		$appPassword = $this->session->get('app_password');
132
133
		try {
134
			$token = $this->tokenProvider->getToken($appPassword);
135
		} catch (InvalidTokenException $e) {
136
			throw new OCSForbiddenException('could not rotate apptoken');
137
		}
138
139
		$newToken = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
140
		$this->tokenProvider->rotate($token, $appPassword, $newToken);
141
142
		return new DataResponse([
143
			'apppassword' => $newToken,
144
		]);
145
	}
146
}
147