Skip to content

Commit 5e7e8c8

Browse files
authored
IBX-5985: Added ability to check user against "X-Expected-User" header
1 parent 2a80395 commit 5e7e8c8

File tree

4 files changed

+113
-0
lines changed

4 files changed

+113
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Bundle\Rest\EventListener;
10+
11+
use Ibexa\Bundle\Rest\Exception\UnexpectedUserException;
12+
use Ibexa\Contracts\Core\Repository\PermissionResolver;
13+
use Psr\Log\LoggerAwareInterface;
14+
use Psr\Log\LoggerAwareTrait;
15+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\HttpKernel\Event\RequestEvent;
18+
use Symfony\Component\HttpKernel\KernelEvents;
19+
use Symfony\Component\Security\Core\Security;
20+
21+
final class UserCheckRequestListener implements EventSubscriberInterface, LoggerAwareInterface
22+
{
23+
use LoggerAwareTrait;
24+
25+
private PermissionResolver $permissionResolver;
26+
27+
private Security $security;
28+
29+
public function __construct(PermissionResolver $permissionResolver, Security $security)
30+
{
31+
$this->permissionResolver = $permissionResolver;
32+
$this->security = $security;
33+
}
34+
35+
public static function getSubscribedEvents(): array
36+
{
37+
return [
38+
KernelEvents::REQUEST => [
39+
['checkUser'],
40+
],
41+
];
42+
}
43+
44+
public function checkUser(RequestEvent $event): void
45+
{
46+
if (!$event->isMainRequest()) {
47+
return;
48+
}
49+
50+
if (!$event->getRequest()->attributes->get('is_rest_request')) {
51+
return;
52+
}
53+
54+
$request = $event->getRequest();
55+
$expectedUserIdentifier = $request->headers->get('X-Expected-User');
56+
if (empty($expectedUserIdentifier)) {
57+
return;
58+
}
59+
60+
$user = $this->security->getUser();
61+
if ($user === null || $expectedUserIdentifier !== $user->getUsername()) {
62+
throw new UnexpectedUserException('Expectation failed. User changed.', Response::HTTP_UNAUTHORIZED);
63+
}
64+
}
65+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Bundle\Rest\Exception;
10+
11+
use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
12+
13+
final class UnexpectedUserException extends UnauthorizedException
14+
{
15+
}

src/bundle/Resources/config/services.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@ services:
214214
tags:
215215
- { name: kernel.event_subscriber }
216216

217+
Ibexa\Bundle\Rest\EventListener\UserCheckRequestListener:
218+
arguments:
219+
$permissionResolver: '@Ibexa\Contracts\Core\Repository\PermissionResolver'
220+
$security: '@security.helper'
221+
calls:
222+
- [setLogger, ['@logger']]
223+
tags:
224+
- { name: kernel.event_subscriber }
225+
- { name: monolog.logger, channel: request }
226+
217227
Ibexa\Rest\Server\Controller\Options:
218228
parent: Ibexa\Rest\Server\Controller
219229
tags: [controller.service_arguments]

tests/bundle/Functional/RootTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,29 @@ public function testLoadRootResource()
2626
return $response->getBody();
2727
}
2828

29+
public function testExpectedUser(): void
30+
{
31+
$request = $this->createHttpRequest('GET', '/api/ibexa/v2/');
32+
$request = $request->withHeader('Accept', 'application/json');
33+
$request = $request->withHeader('X-Expected-User', '');
34+
$response = $this->sendHttpRequest($request);
35+
36+
self::assertHttpResponseCodeEquals($response, 200);
37+
38+
$request = $request->withHeader('X-Expected-User', 'admin');
39+
$response = $this->sendHttpRequest($request);
40+
41+
self::assertHttpResponseCodeEquals($response, 200);
42+
43+
$request = $request->withHeader('X-Expected-User', 'foo');
44+
$response = $this->sendHttpRequest($request);
45+
46+
self::assertHttpResponseCodeEquals($response, 401);
47+
$responseArray = json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
48+
self::assertArrayHasKey('ErrorMessage', $responseArray);
49+
self::assertSame('Expectation failed. User changed.', $responseArray['ErrorMessage']['errorDescription']);
50+
}
51+
2952
/**
3053
* @dataProvider getRandomUriSet
3154
* Covers GET /<wrongUri>

0 commit comments

Comments
 (0)