Issues (263)

lib/Middleware/EnvCheckMiddleware.php (14 issues)

1
<?php
2
/**
3
 * Nextcloud - Gallery
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Olivier Paroz <[email protected]>
9
 * @author Bernhard Posselt <[email protected]>
10
 * @author Authors of \OCA\Files_Sharing\Helper
11
 *
12
 * @copyright Olivier Paroz 2017
13
 * @copyright Bernhard Posselt 2017
14
 * @copyright Authors of \OCA\Files_Sharing\Helper 2017
15
 */
16
17
namespace OCA\Gallery\Middleware;
18
19
use OCP\Constants;
0 ignored issues
show
The type OCP\Constants was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use OCP\IRequest;
0 ignored issues
show
The type OCP\IRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use OCP\IURLGenerator;
0 ignored issues
show
The type OCP\IURLGenerator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use OCP\ISession;
0 ignored issues
show
The type OCP\ISession was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use OCP\ILogger;
0 ignored issues
show
The type OCP\ILogger was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use OCP\Share;
0 ignored issues
show
The type OCP\Share was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use OCP\Share\IShare;
0 ignored issues
show
The type OCP\Share\IShare was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use OCP\Share\Exceptions\ShareNotFound;
0 ignored issues
show
The type OCP\Share\Exceptions\ShareNotFound was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use OCP\Security\IHasher;
0 ignored issues
show
The type OCP\Security\IHasher was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
29
use OCP\AppFramework\Http;
0 ignored issues
show
The type OCP\AppFramework\Http was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use OCP\AppFramework\Utility\IControllerMethodReflector;
0 ignored issues
show
The type OCP\AppFramework\Utility...ntrollerMethodReflector was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
32
use OCA\Gallery\Environment\Environment;
33
use OCP\Share\IManager;
0 ignored issues
show
The type OCP\Share\IManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
35
/**
36
 * Checks that we have a valid token linked to a valid resource and that the
37
 * user is authorised to access it
38
 *
39
 * Once all checks have been passed, the environment is ready to use
40
 *
41
 * @package OCA\Gallery\Middleware
42
 */
43
class EnvCheckMiddleware extends CheckMiddleware {
44
45
	/** @var IHasher */
46
	private $hasher;
47
	/** @var ISession */
48
	private $session;
49
	/** @var Environment */
50
	private $environment;
51
	/** @var IControllerMethodReflector */
52
	protected $reflector;
53
	/** @var IManager */
54
	protected $shareManager;
55
56
	/***
57
	 * Constructor
58
	 *
59
	 * @param string $appName
60
	 * @param IRequest $request
61
	 * @param IHasher $hasher
62
	 * @param ISession $session
63
	 * @param Environment $environment
64
	 * @param IControllerMethodReflector $reflector
65
	 * @param IURLGenerator $urlGenerator
66
	 * @param ILogger $logger
67
	 * @param IManager $shareManager
68
	 */
69
	public function __construct(
70
		$appName,
71
		IRequest $request,
72
		IHasher $hasher,
73
		ISession $session,
74
		Environment $environment,
75
		IControllerMethodReflector $reflector,
76
		IURLGenerator $urlGenerator,
77
		IManager $shareManager,
78
		ILogger $logger
79
	) {
80
		parent::__construct(
81
			$appName,
82
			$request,
83
			$urlGenerator,
84
			$logger
85
		);
86
87
		$this->hasher = $hasher;
88
		$this->session = $session;
89
		$this->environment = $environment;
90
		$this->reflector = $reflector;
91
		$this->shareManager = $shareManager;
92
	}
93
94
	/**
95
	 * Checks that we have a valid token linked to a valid resource and that the
96
	 * user is authorised to access it
97
	 *
98
	 * Inspects the controller method annotations and if PublicPage is found
99
	 * it checks that we have a token and an optional password giving access to a valid resource.
100
	 * Once that's done, the environment is setup so that our services can find the resources they
101
	 * need.
102
	 *
103
	 * The checks are not performed on "guest" pages and the environment is not setup. Typical
104
	 * guest pages are anonymous error ages
105
	 *
106
	 * @inheritDoc
107
	 */
108
	public function beforeController($controller, $methodName) {
109
		if ($this->reflector->hasAnnotation('Guest')) {
110
			return;
111
		}
112
		$isPublicPage = $this->reflector->hasAnnotation('PublicPage');
113
		if ($isPublicPage) {
114
			$this->validateAndSetTokenBasedEnv();
115
		} else {
116
			$this->environment->setStandardEnv();
117
		}
118
	}
119
120
	/**
121
	 * Checks that we have a token and an optional password giving access to a
122
	 * valid resource. Sets the token based environment after that
123
	 *
124
	 * @throws CheckException
125
	 */
126
	private function validateAndSetTokenBasedEnv() {
127
		$token = $this->request->getParam('token');
128
		if (!$token) {
129
			throw new CheckException(
130
				"Can't access a public resource without a token", Http::STATUS_NOT_FOUND
131
			);
132
		} else {
133
			$share = $this->getShare($token);
134
135
			if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
136
				throw new CheckException(
137
					"Can't access a public resource that is upload only", Http::STATUS_NOT_FOUND
138
				);
139
			}
140
141
			$password = $this->request->getParam('password');
142
			// Let's see if the user needs to provide a password
143
			$this->checkAuthorisation($share, $password);
144
145
			$this->environment->setTokenBasedEnv($share);
146
		}
147
	}
148
149
	/**
150
	 * Validates a token to make sure its linked to a valid resource
151
	 *
152
	 * Uses Share 2.0
153
	 *
154
	 * @fixme setIncognitoMode in 8.1 https://github.com/owncloud/core/pull/12912
155
	 *
156
	 * @param string $token
157
	 *
158
	 * @throws CheckException
159
	 * @return IShare
160
	 */
161
	private function getShare($token) {
162
		// Allows a logged in user to access public links
163
		\OC_User::setIncognitoMode(true);
0 ignored issues
show
The type OC_User was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
164
165
		try {
166
			$share = $this->shareManager->getShareByToken($token);
167
		} catch (ShareNotFound $e) {
168
			throw new CheckException($e->getMessage(), Http::STATUS_NOT_FOUND);
169
		}
170
171
		$this->checkShareIsValid($share, $token);
172
		$this->checkItemType($share);
173
174
		return $share;
175
	}
176
177
	/**
178
	 * Makes sure that the token contains all the information that we need
179
	 *
180
	 * @param IShare $share
181
	 * @param string $token
182
	 *
183
	 * @throws CheckException
184
	 */
185
	private function checkShareIsValid($share, $token) {
186
		if ($share->getShareOwner() === null
187
			|| $share->getTarget() === null
188
		) {
189
			$message =
190
				'Passed token seems to be valid, but it does not contain all necessary information . ("'
191
				. $token . '")';
192
			throw new CheckException($message, Http::STATUS_NOT_FOUND);
193
		}
194
	}
195
196
	/**
197
	 * Makes sure an item type was set for that token
198
	 *
199
	 * @param IShare $share
200
	 *
201
	 * @throws CheckException
202
	 */
203
	private function checkItemType($share) {
204
		if ($share->getNodeType() === null) {
205
			$message = 'No item type set for share id: ' . $share->getId();
206
			throw new CheckException($message, Http::STATUS_NOT_FOUND);
207
		}
208
	}
209
210
211
	/**
212
	 * Checks if a password is required or if the one supplied is working
213
	 *
214
	 * @param IShare $share
215
	 * @param string|null $password optional password
216
	 *
217
	 * @throws CheckException
218
	 */
219
	private function checkAuthorisation($share, $password) {
220
		$passwordRequired = $share->getPassword();
221
222
		if (isset($passwordRequired)) {
223
			if ($password !== null) {
224
				$this->authenticate($share, $password);
225
			} else {
226
				$this->checkSession($share);
227
			}
228
		}
229
	}
230
231
	/**
232
	 * Authenticate link item with the given password
233
	 * or with the session if no password was given.
234
	 *
235
	 * @param IShare $share
236
	 * @param string $password
237
	 *
238
	 * @return bool true if authorized, an exception is raised otherwise
239
	 *
240
	 * @throws CheckException
241
	 */
242
	private function authenticate($share, $password) {
243
		if ((int)$share->getShareType() === Share::SHARE_TYPE_LINK) {
244
			$this->checkPassword($share, $password);
245
		} else {
246
			throw new CheckException(
247
				'Unknown share type ' . $share->getShareType() . ' for share id '
248
				. $share->getId(), Http::STATUS_NOT_FOUND
249
			);
250
		}
251
252
		return true;
253
	}
254
255
	/**
256
	 * Validates the given password
257
	 *
258
	 * @fixme @LukasReschke says: Migrate old hashes to new hash format
259
	 * Due to the fact that there is no reasonable functionality to update the password
260
	 * of an existing share no migration is yet performed there.
261
	 * The only possibility is to update the existing share which will result in a new
262
	 * share ID and is a major hack.
263
	 *
264
	 * In the future the migration should be performed once there is a proper method
265
	 * to update the share's password. (for example `$share->updatePassword($password)`
266
	 *
267
	 * @link https://github.com/owncloud/core/issues/10671
268
	 *
269
	 * @param IShare $share
270
	 * @param string $password
271
	 *
272
	 * @throws CheckException
273
	 */
274
	private function checkPassword($share, $password) {
275
		$newHash = '';
276
		if ($this->shareManager->checkPassword($share, $password)) {
277
			// Save item id in session for future requests
278
			$this->session->set('public_link_authenticated', (string)$share->getId());
279
			// @codeCoverageIgnoreStart
280
			if (!empty($newHash)) {
0 ignored issues
show
The condition empty($newHash) is always true.
Loading history...
281
				// For future use
282
			}
283
			// @codeCoverageIgnoreEnd
284
		} else {
285
			throw new CheckException("Wrong password", Http::STATUS_UNAUTHORIZED);
286
		}
287
	}
288
289
	/**
290
	 * Makes sure the user is already properly authenticated when a password is required and none
291
	 * was provided
292
	 *
293
	 * @param IShare $share
294
	 *
295
	 * @throws CheckException
296
	 */
297
	private function checkSession($share) {
298
		// Not authenticated ?
299
		if (!$this->session->exists('public_link_authenticated')
300
			|| $this->session->get('public_link_authenticated') !== (string)$share->getId()
301
		) {
302
			throw new CheckException("Missing password", Http::STATUS_UNAUTHORIZED);
303
		}
304
	}
305
306
}
307