Completed
Push — master ( dccb89...31024b )
by Morris
12:39
created

OCSAuthAPIController   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 168
Duplicated Lines 4.76 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 8
loc 168
rs 10
wmc 10
lcom 1
cbo 8

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 1
B requestSharedSecret() 4 36 3
B getSharedSecret() 4 25 3
A isValidToken() 0 4 1
A requestSharedSecretLegacy() 0 3 1
A getSharedSecretLegacy() 0 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Robin Appelman <[email protected]>
8
 * @author Roeland Jago Douma <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
28
namespace OCA\Federation\Controller;
29
30
use OCA\Federation\DbHandler;
31
use OCA\Federation\TrustedServers;
32
use OCP\AppFramework\Http;
33
use OCP\AppFramework\OCS\OCSForbiddenException;
34
use OCP\AppFramework\OCSController;
35
use OCP\BackgroundJob\IJobList;
36
use OCP\ILogger;
37
use OCP\IRequest;
38
use OCP\Security\ISecureRandom;
39
40
/**
41
 * Class OCSAuthAPI
42
 *
43
 * OCS API end-points to exchange shared secret between two connected Nextclouds
44
 *
45
 * @package OCA\Federation\Controller
46
 */
47
class OCSAuthAPIController extends OCSController{
48
49
	/** @var ISecureRandom  */
50
	private $secureRandom;
51
52
	/** @var IJobList */
53
	private $jobList;
54
55
	/** @var TrustedServers */
56
	private $trustedServers;
57
58
	/** @var DbHandler */
59
	private $dbHandler;
60
61
	/** @var ILogger */
62
	private $logger;
63
64
	/**
65
	 * OCSAuthAPI constructor.
66
	 *
67
	 * @param string $appName
68
	 * @param IRequest $request
69
	 * @param ISecureRandom $secureRandom
70
	 * @param IJobList $jobList
71
	 * @param TrustedServers $trustedServers
72
	 * @param DbHandler $dbHandler
73
	 * @param ILogger $logger
74
	 */
75
	public function __construct(
76
		$appName,
77
		IRequest $request,
78
		ISecureRandom $secureRandom,
79
		IJobList $jobList,
80
		TrustedServers $trustedServers,
81
		DbHandler $dbHandler,
82
		ILogger $logger
83
	) {
84
		parent::__construct($appName, $request);
85
86
		$this->secureRandom = $secureRandom;
87
		$this->jobList = $jobList;
88
		$this->trustedServers = $trustedServers;
89
		$this->dbHandler = $dbHandler;
90
		$this->logger = $logger;
91
	}
92
93
	/**
94
	 * @NoCSRFRequired
95
	 * @PublicPage
96
	 *
97
	 * request received to ask remote server for a shared secret, for legacy end-points
98
	 *
99
	 * @param string $url
100
	 * @param string $token
101
	 * @return Http\DataResponse
102
	 * @throws OCSForbiddenException
103
	 */
104
	public function requestSharedSecretLegacy($url, $token) {
105
		return $this->requestSharedSecret($url, $token);
106
	}
107
108
109
	/**
110
	 * @NoCSRFRequired
111
	 * @PublicPage
112
	 *
113
	 * create shared secret and return it, for legacy end-points
114
	 *
115
	 * @param string $url
116
	 * @param string $token
117
	 * @return Http\DataResponse
118
	 * @throws OCSForbiddenException
119
	 */
120
	public function getSharedSecretLegacy($url, $token) {
121
		return $this->getSharedSecret($url, $token);
122
	}
123
124
	/**
125
	 * @NoCSRFRequired
126
	 * @PublicPage
127
	 *
128
	 * request received to ask remote server for a shared secret
129
	 *
130
	 * @param string $url
131
	 * @param string $token
132
	 * @return Http\DataResponse
133
	 * @throws OCSForbiddenException
134
	 */
135
	public function requestSharedSecret($url, $token) {
136 View Code Duplication
		if ($this->trustedServers->isTrustedServer($url) === false) {
137
			$this->logger->error('remote server not trusted (' . $url . ') while requesting shared secret', ['app' => 'federation']);
138
			throw new OCSForbiddenException();
139
		}
140
141
		// if both server initiated the exchange of the shared secret the greater
142
		// token wins
143
		$localToken = $this->dbHandler->getToken($url);
144
		if (strcmp($localToken, $token) > 0) {
145
			$this->logger->info(
146
				'remote server (' . $url . ') presented lower token. We will initiate the exchange of the shared secret.',
147
				['app' => 'federation']
148
			);
149
			throw new OCSForbiddenException();
150
		}
151
152
		// we ask for the shared secret so we no longer have to ask the other server
153
		// to request the shared secret
154
		$this->jobList->remove('OCA\Federation\BackgroundJob\RequestSharedSecret',
155
			[
156
				'url' => $url,
157
				'token' => $localToken
158
			]
159
		);
160
161
		$this->jobList->add(
162
			'OCA\Federation\BackgroundJob\GetSharedSecret',
163
			[
164
				'url' => $url,
165
				'token' => $token,
166
			]
167
		);
168
169
		return new Http\DataResponse();
170
	}
171
172
	/**
173
	 * @NoCSRFRequired
174
	 * @PublicPage
175
	 *
176
	 * create shared secret and return it
177
	 *
178
	 * @param string $url
179
	 * @param string $token
180
	 * @return Http\DataResponse
181
	 * @throws OCSForbiddenException
182
	 */
183
	public function getSharedSecret($url, $token) {
184 View Code Duplication
		if ($this->trustedServers->isTrustedServer($url) === false) {
185
			$this->logger->error('remote server not trusted (' . $url . ') while getting shared secret', ['app' => 'federation']);
186
			throw new OCSForbiddenException();
187
		}
188
189
		if ($this->isValidToken($url, $token) === false) {
190
			$expectedToken = $this->dbHandler->getToken($url);
191
			$this->logger->error(
192
				'remote server (' . $url . ') didn\'t send a valid token (got "' . $token . '" but expected "'. $expectedToken . '") while getting shared secret',
193
				['app' => 'federation']
194
			);
195
			throw new OCSForbiddenException();
196
		}
197
198
		$sharedSecret = $this->secureRandom->generate(32);
199
200
		$this->trustedServers->addSharedSecret($url, $sharedSecret);
201
		// reset token after the exchange of the shared secret was successful
202
		$this->dbHandler->addToken($url, '');
203
204
		return new Http\DataResponse([
205
			'sharedSecret' => $sharedSecret
206
		]);
207
	}
208
209
	protected function isValidToken($url, $token) {
210
		$storedToken = $this->dbHandler->getToken($url);
211
		return hash_equals($storedToken, $token);
212
	}
213
214
}
215