Skip to content

Commit 3a1dc42

Browse files
authored
IBX-5243: Respect header setting for AuthorizationHeaderRESTRequestMatcher
1 parent 2149507 commit 3a1dc42

File tree

5 files changed

+79
-6
lines changed

5 files changed

+79
-6
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\DependencyInjection\Compiler;
10+
11+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
12+
use Symfony\Component\DependencyInjection\ContainerBuilder;
13+
14+
final class LexikAuthorizationHeaderBridgePass implements CompilerPassInterface
15+
{
16+
public function process(ContainerBuilder $container): void
17+
{
18+
if (!$container->hasDefinition('lexik_jwt_authentication.extractor.authorization_header_extractor')) {
19+
return;
20+
}
21+
22+
$definition = $container->getDefinition('lexik_jwt_authentication.extractor.authorization_header_extractor');
23+
$headerName = $definition->getArgument(1);
24+
25+
$container->setParameter('ibexa.rest.authorization_header_name', $headerName);
26+
}
27+
}

src/bundle/IbexaRestBundle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ public function build(ContainerBuilder $container)
2525
/** @var \Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension $securityExtension */
2626
$securityExtension = $container->getExtension('security');
2727
$securityExtension->addSecurityListenerFactory(new RestSessionBasedFactory());
28+
29+
if ($container->hasExtension('lexik_jwt_authentication')) {
30+
$container->addCompilerPass(new Compiler\LexikAuthorizationHeaderBridgePass());
31+
}
2832
}
2933
}
3034

src/bundle/Resources/config/security.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
parameters:
2+
ibexa.rest.authorization_header_name: ~
3+
24
services:
35
# Following service will be aliased at compile time to "ezpublish_rest.session_authenticator" by the Security factory.
46
ibexa.rest.security.authentication.listener.session:
@@ -12,7 +14,9 @@ services:
1214
- "@?logger"
1315
abstract: true
1416

15-
Ibexa\Contracts\Rest\Security\AuthorizationHeaderRESTRequestMatcher: ~
17+
Ibexa\Contracts\Rest\Security\AuthorizationHeaderRESTRequestMatcher:
18+
arguments:
19+
$headerName: '%ibexa.rest.authorization_header_name%'
1620

1721
Ibexa\Rest\Server\Security\RestLogoutHandler:
1822
arguments:

src/contracts/Security/AuthorizationHeaderRESTRequestMatcher.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@
1313

1414
final class AuthorizationHeaderRESTRequestMatcher extends RequestMatcher
1515
{
16+
private ?string $headerName;
17+
18+
public function __construct(
19+
?string $headerName = null,
20+
string $path = null,
21+
string $host = null,
22+
$methods = null,
23+
$ips = null,
24+
array $attributes = [],
25+
$schemes = null,
26+
int $port = null
27+
) {
28+
parent::__construct($path, $host, $methods, $ips, $attributes, $schemes, $port);
29+
$this->headerName = $headerName;
30+
}
31+
1632
public function matches(Request $request): bool
1733
{
1834
if ($request->attributes->get('is_rest_request', false) !== true) {
@@ -21,7 +37,7 @@ public function matches(Request $request): bool
2137

2238
if (
2339
$request->attributes->get('_route') === 'ibexa.rest.create_token'
24-
|| !empty($request->headers->get('Authorization'))
40+
|| !empty($request->headers->get($this->headerName ?? 'Authorization'))
2541
) {
2642
return parent::matches($request);
2743
}

tests/contracts/Security/AuthorizationHeaderRESTRequestMatcherTest.php

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public function testDoesNotMatchRestRequestsWithoutHeader(): void
2525
{
2626
$matcher = new AuthorizationHeaderRESTRequestMatcher();
2727

28-
$request = new Request([], [], [
28+
$request = $this->createRequest([
2929
'is_rest_request' => true,
3030
]);
3131

@@ -36,24 +36,46 @@ public function testMatchesRestRequestsWithHeader(): void
3636
{
3737
$matcher = new AuthorizationHeaderRESTRequestMatcher();
3838

39-
$request = new Request([], [], [
39+
$request = $this->createRequest([
4040
'is_rest_request' => true,
41-
], [], [], [
41+
], [
4242
'HTTP_AUTHORIZATION' => 'Bearer foo',
4343
]);
4444

4545
self::assertTrue($matcher->matches($request));
4646
}
4747

48+
public function testMatchesRestRequestsWithCustomHeader(): void
49+
{
50+
$matcher = new AuthorizationHeaderRESTRequestMatcher('X-Foo');
51+
52+
$request = $this->createRequest([
53+
'is_rest_request' => true,
54+
], [
55+
'HTTP_X-FOO' => 'Bearer foo',
56+
]);
57+
58+
self::assertTrue($matcher->matches($request));
59+
}
60+
4861
public function testMatchesRestJwtCreationEndpoint(): void
4962
{
5063
$matcher = new AuthorizationHeaderRESTRequestMatcher();
5164

52-
$request = new Request([], [], [
65+
$request = $this->createRequest([
5366
'is_rest_request' => true,
5467
'_route' => 'ibexa.rest.create_token',
5568
]);
5669

5770
self::assertTrue($matcher->matches($request));
5871
}
72+
73+
/**
74+
* @param array<string, mixed> $attributes
75+
* @param array<string, array<string>|string> $server
76+
*/
77+
private function createRequest(array $attributes = [], array $server = []): Request
78+
{
79+
return new Request([], [], $attributes, [], [], $server);
80+
}
5981
}

0 commit comments

Comments
 (0)