Skip to content

Commit 6f88fb4

Browse files
author
Joe Bennett
authored
#3577 moved content negotiation to before firewall (#3599)
1 parent 3a8329f commit 6f88fb4

File tree

8 files changed

+84
-12
lines changed

8 files changed

+84
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
## 2.7.0
44

5+
* **BC**: Change `api_platform.listener.request.add_format` priority from 7 to 28 to execute it before firewall (priority 8) (#3599)
56
* Doctrine: Better exception to find which resource is linked to an exception (#3965)
67
* Doctrine: Allow mixed type value for date filter (notice if invalid) (#3870)
8+
* Doctrine: Add `nulls_always_first` and `nulls_always_last` to `nulls_comparison` in order filter (#4103)
79
* MongoDB: `date_immutable` support (#3940)
810
* DataProvider: Add `TraversablePaginator` (#3783)
911
* Swagger UI: Add `swagger_ui_extra_configuration` to Swagger / OpenAPI configuration (#3731)
10-
* OrderFilter: Add `nulls_always_first` and `nulls_always_last` to `nulls_comparison` (#4103)
1112

1213
## 2.6.3
1314

features/filter/filter_validation.feature

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Feature: Validate filters based upon filter description
22

3+
Background:
4+
Given I add "Accept" header equal to "application/json"
5+
36
@createSchema
47
Scenario: Required filter should not throw an error if set
58
When I am on "/filter_validators?required=foo&required-allow-empty=&arrayRequired[foo]="
@@ -13,7 +16,7 @@ Feature: Validate filters based upon filter description
1316
Scenario: Required filter should throw an error if not set
1417
When I am on "/filter_validators"
1518
Then the response status code should be 400
16-
Then the JSON node "detail" should match '/^Query parameter "required" is required\nQuery parameter "required-allow-empty" is required$/'
19+
And the JSON node "detail" should match '/^Query parameter "required" is required\nQuery parameter "required-allow-empty" is required$/'
1720

1821
Scenario: Required filter should not throw an error if set
1922
When I am on "/array_filter_validators?arrayRequired[]=foo&indexedArrayRequired[foo]=foo"

features/main/content_negotiation.feature

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Feature: Content Negotiation support
2222
<response><description/><dummy/><dummyBoolean/><dummyDate/><dummyFloat/><dummyPrice/><relatedDummy/><relatedDummies/><jsonData/><arrayData/><name_converted/><relatedOwnedDummy/><relatedOwningDummy/><id>1</id><name>XML!</name><alias/><foo/></response>
2323
"""
2424

25-
Scenario: Retrieve a collection in XML
25+
Scenario: Retrieve a collection in XML
2626
When I add "Accept" header equal to "text/xml"
2727
And I send a "GET" request to "/dummies"
2828
Then the response status code should be 200
@@ -34,7 +34,7 @@ Feature: Content Negotiation support
3434
<response><item key="0"><description/><dummy/><dummyBoolean/><dummyDate/><dummyFloat/><dummyPrice/><relatedDummy/><relatedDummies/><jsonData/><arrayData/><name_converted/><relatedOwnedDummy/><relatedOwningDummy/><id>1</id><name>XML!</name><alias/><foo/></item></response>
3535
"""
3636

37-
Scenario: Retrieve a collection in XML using the .xml URL
37+
Scenario: Retrieve a collection in XML using the .xml URL
3838
When I send a "GET" request to "/dummies.xml"
3939
Then the response status code should be 200
4040
And the header "Content-Type" should be equal to "application/xml; charset=utf-8"
@@ -45,7 +45,7 @@ Feature: Content Negotiation support
4545
<response><item key="0"><description/><dummy/><dummyBoolean/><dummyDate/><dummyFloat/><dummyPrice/><relatedDummy/><relatedDummies/><jsonData/><arrayData/><name_converted/><relatedOwnedDummy/><relatedOwningDummy/><id>1</id><name>XML!</name><alias/><foo/></item></response>
4646
"""
4747

48-
Scenario: Retrieve a collection in JSON
48+
Scenario: Retrieve a collection in JSON
4949
When I add "Accept" header equal to "application/json"
5050
And I send a "GET" request to "/dummies"
5151
Then the response status code should be 200
@@ -155,3 +155,17 @@ Feature: Content Negotiation support
155155
id,name
156156
1,Kevin
157157
"""
158+
159+
Scenario: Get a security response in JSON
160+
Given there are 1 SecuredDummy objects
161+
And I add "Accept" header equal to "application/json"
162+
When I send a "GET" request to "/secured_dummies"
163+
Then the response status code should be 401
164+
And the header "Content-Type" should be equal to "application/json"
165+
And the response should be in JSON
166+
And the JSON should be equal to:
167+
"""
168+
{
169+
"message": "Authentication Required"
170+
}
171+
"""

src/Bridge/Symfony/Bundle/Resources/config/api.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,15 @@
150150

151151
<!-- Event listeners -->
152152

153-
<!-- kernel.request priority must be < 8 to be executed after the Firewall -->
154153
<service id="api_platform.listener.request.add_format" class="ApiPlatform\Core\EventListener\AddFormatListener">
155154
<argument type="service" id="api_platform.negotiator" />
156155
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
157156
<argument>%api_platform.formats%</argument>
158157

159-
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="7" />
158+
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="28" />
160159
</service>
161160

161+
<!-- kernel.request priority must be < 8 to be executed after the Firewall -->
162162
<service id="api_platform.listener.request.read" class="ApiPlatform\Core\EventListener\ReadListener">
163163
<argument type="service" id="api_platform.collection_data_provider" />
164164
<argument type="service" id="api_platform.item_data_provider" />

src/EventListener/AddFormatListener.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ public function __construct(Negotiator $negotiator, $resourceMetadataFactory, ar
6565
public function onKernelRequest(RequestEvent $event): void
6666
{
6767
$request = $event->getRequest();
68-
if (
69-
!($request->attributes->has('_api_resource_class')
70-
|| $request->attributes->getBoolean('_api_respond', false)
71-
|| $request->attributes->getBoolean('_graphql', false))
72-
) {
68+
if (!(
69+
$request->attributes->has('_api_resource_class')
70+
|| $request->attributes->getBoolean('_api_respond', false)
71+
|| $request->attributes->getBoolean('_graphql', false)
72+
)) {
7373
return;
7474
}
7575

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Security;
15+
16+
use Symfony\Component\HttpFoundation\JsonResponse;
17+
use Symfony\Component\HttpFoundation\RedirectResponse;
18+
use Symfony\Component\HttpFoundation\Request;
19+
use Symfony\Component\HttpFoundation\Response;
20+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
21+
use Symfony\Component\Routing\RouterInterface;
22+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
23+
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
24+
25+
final class AuthenticationEntryPoint implements AuthenticationEntryPointInterface
26+
{
27+
private $router;
28+
29+
public function __construct(RouterInterface $router)
30+
{
31+
$this->router = $router;
32+
}
33+
34+
public function start(Request $request, AuthenticationException $authException = null): Response
35+
{
36+
if ('html' === $request->getRequestFormat()) {
37+
return new RedirectResponse($this->router->generate('api_doc', [], UrlGeneratorInterface::ABSOLUTE_URL));
38+
}
39+
if ('json' === $request->getRequestFormat()) {
40+
return new JsonResponse(
41+
['message' => 'Authentication Required'],
42+
Response::HTTP_UNAUTHORIZED,
43+
['WWW-Authenticate' => 'Bearer realm="example"']
44+
);
45+
}
46+
47+
return new Response('', Response::HTTP_UNAUTHORIZED);
48+
}
49+
}

tests/Fixtures/app/AppKernel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load
168168
'http_basic' => null,
169169
'anonymous' => null,
170170
'stateless' => true,
171+
'entry_point' => 'app.security.authentication_entrypoint',
171172
],
172173
],
173174
'access_control' => [

tests/Fixtures/app/config/config_common.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,3 +359,7 @@ services:
359359
tags:
360360
- { name: 'api_platform.data_transformer' }
361361

362+
app.security.authentication_entrypoint:
363+
class: 'ApiPlatform\Core\Tests\Fixtures\TestBundle\Security\AuthenticationEntryPoint'
364+
arguments:
365+
$router: '@router'

0 commit comments

Comments
 (0)