Skip to content

Commit c9ffbd4

Browse files
committed
[REMOVE TMP DEPENDENCY] IBX-8482: Fixed lack of JWT stateless calls recognition
1 parent a8e980c commit c9ffbd4

File tree

8 files changed

+96
-34
lines changed

8 files changed

+96
-34
lines changed

dependencies.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"recipesEndpoint": "https://api.github.com/repos/ibexa/recipes-dev/contents/index.json?ref=flex/pull-125",
3+
"packages": []
4+
}

src/bundle/Resources/config/security.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ services:
1111
arguments:
1212
$headerName: '%ibexa.rest.authorization_header_name%'
1313

14+
Ibexa\Rest\Security\JWTTokenCreationRESTRequestMatcher: ~
15+
1416
Ibexa\Rest\Server\Security\CsrfTokenManager:
1517
arguments:
1618
- '@?security.csrf.token_generator'

src/lib/Security/AuthorizationHeaderRESTRequestMatcher.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public function __construct(
3434
int $port = null
3535
) {
3636
parent::__construct($path, $host, $methods, $ips, $attributes, $schemes, $port);
37+
3738
$this->headerName = $headerName;
3839
}
3940

@@ -43,10 +44,7 @@ public function matches(Request $request): bool
4344
return false;
4445
}
4546

46-
if (
47-
$request->attributes->get('_route') === 'ibexa.rest.create_token'
48-
|| !empty($request->headers->get($this->headerName ?? 'Authorization'))
49-
) {
47+
if (!empty($request->headers->get($this->headerName ?? 'Authorization'))) {
5048
return parent::matches($request);
5149
}
5250

src/lib/Security/EventListener/JWT/AuthenticationSuccessSubscriber.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
namespace Ibexa\Rest\Security\EventListener\JWT;
1010

11-
use Ibexa\Contracts\Core\Repository\PermissionResolver;
12-
use Ibexa\Core\MVC\Symfony\Security\UserInterface as IbexaUser;
1311
use Ibexa\Rest\Server\Exceptions\BadResponseException;
1412
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
1513
use Lexik\Bundle\JWTAuthenticationBundle\Events;
@@ -19,7 +17,6 @@
1917
final readonly class AuthenticationSuccessSubscriber implements EventSubscriberInterface
2018
{
2119
public function __construct(
22-
private PermissionResolver $permissionResolver,
2320
private RequestStack $requestStack,
2421
) {
2522
}
@@ -42,11 +39,6 @@ public function onAuthenticationSuccess(AuthenticationSuccessEvent $event): void
4239
return;
4340
}
4441

45-
$user = $event->getUser();
46-
if ($user instanceof IbexaUser) {
47-
$this->permissionResolver->setCurrentUserReference($user->getAPIUser());
48-
}
49-
5042
$this->normalizeResponseToRest($event);
5143
}
5244

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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\Rest\Security;
10+
11+
use Symfony\Component\HttpFoundation\Request;
12+
use Symfony\Component\HttpFoundation\RequestMatcher;
13+
14+
/**
15+
* @internal
16+
*
17+
* This class is mandatory for JWT REST calls recognition. It's used within security.firewalls.ibexa_jwt_rest.request_matcher configuration key.
18+
*/
19+
final class JWTTokenCreationRESTRequestMatcher extends RequestMatcher
20+
{
21+
public function matches(Request $request): bool
22+
{
23+
if ($request->attributes->get('is_rest_request', false) !== true) {
24+
return false;
25+
}
26+
27+
if ($request->attributes->get('_route') === 'ibexa.rest.create_token') {
28+
return parent::matches($request);
29+
}
30+
31+
return false;
32+
}
33+
}

tests/contracts/Security/AuthorizationHeaderRESTRequestMatcherTest.php

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,6 @@ public function testMatchesRestRequestsWithCustomHeader(): void
5858
self::assertTrue($matcher->matches($request));
5959
}
6060

61-
public function testMatchesRestJwtCreationEndpoint(): void
62-
{
63-
$matcher = new AuthorizationHeaderRESTRequestMatcher();
64-
65-
$request = $this->createRequest([
66-
'is_rest_request' => true,
67-
'_route' => 'ibexa.rest.create_token',
68-
]);
69-
70-
self::assertTrue($matcher->matches($request));
71-
}
72-
7361
/**
7462
* @param array<string, mixed> $attributes
7563
* @param array<string, array<string>|string> $server
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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\Tests\Contracts\Rest\Security;
10+
11+
use Ibexa\Rest\Security\JWTTokenCreationRESTRequestMatcher;
12+
use PHPUnit\Framework\TestCase;
13+
use Symfony\Component\HttpFoundation\Request;
14+
15+
final class JWTTokenCreationRESTRequestMatcherTest extends TestCase
16+
{
17+
public function testDoesNotMatchNonRestRequests(): void
18+
{
19+
$matcher = new JWTTokenCreationRESTRequestMatcher();
20+
21+
self::assertFalse($matcher->matches(new Request()));
22+
}
23+
24+
public function testDoesNotMatchRestRequestsWithoutHeader(): void
25+
{
26+
$matcher = new JWTTokenCreationRESTRequestMatcher();
27+
28+
$request = $this->createRequest([
29+
'is_rest_request' => true,
30+
]);
31+
32+
self::assertFalse($matcher->matches($request));
33+
}
34+
35+
public function testMatchesRestJwtCreationEndpoint(): void
36+
{
37+
$matcher = new JWTTokenCreationRESTRequestMatcher();
38+
39+
$request = $this->createRequest([
40+
'is_rest_request' => true,
41+
'_route' => 'ibexa.rest.create_token',
42+
]);
43+
44+
self::assertTrue($matcher->matches($request));
45+
}
46+
47+
/**
48+
* @param array<string, mixed> $attributes
49+
* @param array<string, array<string>|string> $server
50+
*/
51+
private function createRequest(array $attributes = [], array $server = []): Request
52+
{
53+
return new Request([], [], $attributes, [], [], $server);
54+
}
55+
}

tests/lib/Security/EventListener/JWT/AuthenticationSuccessSubscriberTest.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
namespace Ibexa\Tests\Rest\Security\EventListener\JWT;
1010

11-
use Ibexa\Contracts\Core\Repository\PermissionResolver;
1211
use Ibexa\Core\MVC\Symfony\Security\User;
1312
use Ibexa\Core\Repository\Values\User\User as ApiUser;
1413
use Ibexa\Rest\Security\EventListener\JWT\AuthenticationSuccessSubscriber;
@@ -27,7 +26,6 @@ final class AuthenticationSuccessSubscriberTest extends TestCase
2726
public function testGetSubscribedEvents(): void
2827
{
2928
$subscriber = new AuthenticationSuccessSubscriber(
30-
$this->createMock(PermissionResolver::class),
3129
$this->getRequestStackMock()
3230
);
3331

@@ -46,15 +44,9 @@ public function testOnAuthenticationSuccess(
4644
UserInterface $user,
4745
bool $isPermissionResolverInvoked
4846
): void {
49-
$permissionResolver = $this->createMock(PermissionResolver::class);
50-
$permissionResolver
51-
->expects($isPermissionResolverInvoked === true ? self::once() : self::never())
52-
->method('setCurrentUserReference');
53-
5447
$event = new AuthenticationSuccessEvent(['token' => 'foo_token'], $user, new Response());
5548

5649
$subscriber = new AuthenticationSuccessSubscriber(
57-
$permissionResolver,
5850
$this->getRequestStackMock()
5951
);
6052

@@ -91,7 +83,6 @@ public function dataProviderForTestOnAuthenticationSuccess(): iterable
9183
public function testResponseIsMissingJwtToken(): void
9284
{
9385
$subscriber = new AuthenticationSuccessSubscriber(
94-
$this->createMock(PermissionResolver::class),
9586
$this->getRequestStackMock()
9687
);
9788

@@ -113,7 +104,6 @@ public function testResponseIsMissingJwtToken(): void
113104
public function testSkippingResponseNormalizingForNonRestRequest(): void
114105
{
115106
$subscriber = new AuthenticationSuccessSubscriber(
116-
$this->createMock(PermissionResolver::class),
117107
$this->getRequestStackMock(false)
118108
);
119109

0 commit comments

Comments
 (0)