Completed
Push — master ( a84fba...e8b4d4 )
by Thomas
11:12
created

OCSAuthAPIController::getSharedSecret()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 15

Duplication

Lines 4
Ratio 16 %

Importance

Changes 0
Metric Value
cc 3
eloc 15
nc 3
nop 2
dl 4
loc 25
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Björn Schießle <[email protected]>
4
 * @author Lukas Reschke <[email protected]>
5
 * @author Robin Appelman <[email protected]>
6
 * @author Roeland Jago Douma <[email protected]>
7
 * @author Thomas Müller <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2016, 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 OCA\Federation\Controller;
27
28
use OCA\Federation\DbHandler;
29
use OCA\Federation\TrustedServers;
30
use OCP\AppFramework\Http;
31
use OCP\AppFramework\OCSController;
32
use OCP\BackgroundJob\IJobList;
33
use OCP\ILogger;
34
use OCP\IRequest;
35
use OCP\Security\ISecureRandom;
36
37
/**
38
 * Class OCSAuthAPIController
39
 *
40
 * OCS API end-points to exchange shared secret between two connected ownClouds
41
 *
42
 * @package OCA\Federation\Controller
43
 */
44
class OCSAuthAPIController extends OCSController  {
45
46
	/** @var ISecureRandom  */
47
	private $secureRandom;
48
49
	/** @var IJobList */
50
	private $jobList;
51
52
	/** @var TrustedServers */
53
	private $trustedServers;
54
55
	/** @var DbHandler */
56
	private $dbHandler;
57
58
	/** @var ILogger */
59
	private $logger;
60
61
	/**
62
	 * OCSAuthAPI constructor.
63
	 *
64
	 * @param string $appName
65
	 * @param IRequest $request
66
	 * @param ISecureRandom $secureRandom
67
	 * @param IJobList $jobList
68
	 * @param TrustedServers $trustedServers
69
	 * @param DbHandler $dbHandler
70
	 * @param ILogger $logger
71
	 */
72
	public function __construct(
73
		$appName,
74
		IRequest $request,
75
		ISecureRandom $secureRandom,
76
		IJobList $jobList,
77
		TrustedServers $trustedServers,
78
		DbHandler $dbHandler,
79
		ILogger $logger
80
	) {
81
		parent::__construct($appName, $request);
82
83
		$this->secureRandom = $secureRandom;
84
		$this->jobList = $jobList;
85
		$this->trustedServers = $trustedServers;
86
		$this->dbHandler = $dbHandler;
87
		$this->logger = $logger;
88
	}
89
90
	/**
91
	 * @NoCSRFRequired
92
	 * @PublicPage
93
	 *
94
	 * request received to ask remote server for a shared secret
95
	 *
96
	 * @param string $url
97
	 * @param string $token
98
	 * @return array()
0 ignored issues
show
Documentation introduced by
The doc-type array() could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
99
	 */
100
	public function requestSharedSecret($url, $token) {
101
102 View Code Duplication
		if ($this->trustedServers->isTrustedServer($url) === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
103
			$this->logger->error('remote server not trusted (' . $url . ') while requesting shared secret', ['app' => 'federation']);
104
			return ['statuscode' => Http::STATUS_FORBIDDEN];
105
		}
106
107
		// if both server initiated the exchange of the shared secret the greater
108
		// token wins
109
		$localToken = $this->dbHandler->getToken($url);
110 View Code Duplication
		if (strcmp($localToken, $token) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
111
			$this->logger->info(
112
				'remote server (' . $url . ') presented lower token. We will initiate the exchange of the shared secret.',
113
				['app' => 'federation']
114
			);
115
			return ['statuscode' => Http::STATUS_FORBIDDEN];
116
		}
117
118
		// we ask for the shared secret so we no longer have to ask the other server
119
		// to request the shared secret
120
		$this->jobList->remove('OCA\Federation\BackgroundJob\RequestSharedSecret',
121
			[
122
				'url' => $url,
123
				'token' => $localToken
124
			]
125
		);
126
127
		$this->jobList->add(
128
			'OCA\Federation\BackgroundJob\GetSharedSecret',
129
			[
130
				'url' => $url,
131
				'token' => $token,
132
			]
133
		);
134
135
		return ['statuscode' => Http::STATUS_OK];
136
	}
137
138
	/**
139
	 * @NoCSRFRequired
140
	 * @PublicPage
141
	 *
142
	 * create shared secret and return it
143
	 *
144
	 * @param string $url
145
	 * @param string $token
146
	 * @return array
147
	 */
148
	public function getSharedSecret($url, $token) {
149
150 View Code Duplication
		if ($this->trustedServers->isTrustedServer($url) === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
151
			$this->logger->error('remote server not trusted (' . $url . ') while getting shared secret', ['app' => 'federation']);
152
			return ['statuscode' => Http::STATUS_FORBIDDEN];
153
		}
154
155
		if ($this->isValidToken($url, $token) === false) {
156
			$expectedToken = $this->dbHandler->getToken($url);
157
			$this->logger->error(
158
				'remote server (' . $url . ') didn\'t send a valid token (got "' . $token . '" but expected "'. $expectedToken . '") while getting shared secret',
159
				['app' => 'federation']
160
			);
161
			return ['statuscode' => Http::STATUS_FORBIDDEN];
162
		}
163
164
		$sharedSecret = $this->secureRandom->generate(32);
165
166
		$this->trustedServers->addSharedSecret($url, $sharedSecret);
167
		// reset token after the exchange of the shared secret was successful
168
		$this->dbHandler->addToken($url, '');
169
170
		return ['statuscode' => Http::STATUS_OK,
171
			'data' => ['sharedSecret' => $sharedSecret]];
172
	}
173
174
	protected function isValidToken($url, $token) {
175
		$storedToken = $this->dbHandler->getToken($url);
176
		return hash_equals($storedToken, $token);
177
	}
178
179
}
180