Issues (48)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

DependencyInjection/FOSRestExtension.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
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
namespace FOS\RestBundle\DependencyInjection;
13
14
use FOS\RestBundle\ErrorRenderer\SerializerErrorRenderer;
15
use FOS\RestBundle\EventListener\ResponseStatusCodeListener;
16
use FOS\RestBundle\View\ViewHandler;
17
use Symfony\Component\Config\FileLocator;
18
use Symfony\Component\DependencyInjection\Alias;
19
use Symfony\Component\DependencyInjection\ChildDefinition;
20
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
21
use Symfony\Component\DependencyInjection\ContainerBuilder;
22
use Symfony\Component\DependencyInjection\ContainerInterface;
23
use Symfony\Component\DependencyInjection\Definition;
24
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
25
use Symfony\Component\DependencyInjection\Reference;
26
use Symfony\Component\Form\Extension\Core\Type\FormType;
27
use Symfony\Component\HttpFoundation\Response;
28
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
29
use Symfony\Component\Validator\Constraint;
30
31
/**
32
 * @internal
33
 */
34
class FOSRestExtension extends Extension
35
{
36
    /**
37
     * {@inheritdoc}
38
     */
39 14
    public function getConfiguration(array $config, ContainerBuilder $container): Configuration
40
    {
41 14
        return new Configuration($container->getParameter('kernel.debug'));
42
    }
43
44 49
    public function load(array $configs, ContainerBuilder $container): void
45
    {
46 49
        $configuration = new Configuration($container->getParameter('kernel.debug'));
47 49
        $config = $this->processConfiguration($configuration, $configs);
48
49 44
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
50 44
        $loader->load('view.xml');
51 44
        $loader->load('request.xml');
52 44
        $loader->load('serializer.xml');
53
54 44
        foreach ($config['service'] as $key => $service) {
55 44
            if ('validator' === $service && empty($config['body_converter']['validate'])) {
56 43
                continue;
57
            }
58
59 44
            if (null !== $service) {
60 44
                if ('view_handler' === $key) {
61 44
                    $container->setAlias('fos_rest.'.$key, new Alias($service, true));
62
                } else {
63 1
                    $container->setAlias('fos_rest.'.$key, $service);
64
                }
65
            }
66
        }
67
68 44
        $this->loadForm($config, $loader, $container);
69 44
        $this->loadException($config, $loader, $container);
70 44
        $this->loadBodyConverter($config, $loader, $container);
71 44
        $this->loadView($config, $loader, $container);
72
73 44
        $this->loadBodyListener($config, $loader, $container);
74 44
        $this->loadFormatListener($config, $loader, $container);
75 44
        $this->loadVersioning($config, $loader, $container);
76 44
        $this->loadParamFetcherListener($config, $loader, $container);
77 44
        $this->loadAllowedMethodsListener($config, $loader, $container);
78 44
        $this->loadZoneMatcherListener($config, $loader, $container);
79
80
        // Needs RequestBodyParamConverter and View Handler loaded.
81 44
        $this->loadSerializer($config, $container);
82 44
    }
83
84 44
    private function loadForm(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
85
    {
86 44
        if (!empty($config['disable_csrf_role'])) {
87
            $loader->load('forms.xml');
88
89
            $definition = $container->getDefinition('fos_rest.form.extension.csrf_disable');
90
            $definition->replaceArgument(1, $config['disable_csrf_role']);
91
            $definition->addTag('form.type_extension', ['extended_type' => FormType::class]);
92
        }
93 44
    }
94
95 44
    private function loadAllowedMethodsListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
96
    {
97 44
        if ($config['allowed_methods_listener']['enabled']) {
98 1
            if (!empty($config['allowed_methods_listener']['service'])) {
99
                $service = $container->getDefinition('fos_rest.allowed_methods_listener');
100
                $service->clearTag('kernel.event_listener');
101
            }
102
103 1
            $loader->load('allowed_methods_listener.xml');
104
105 1
            $container->getDefinition('fos_rest.allowed_methods_loader')->replaceArgument(1, $config['cache_dir']);
106
        }
107 44
    }
108
109 44
    private function loadBodyListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
110
    {
111 44
        if ($config['body_listener']['enabled']) {
112 5
            $loader->load('body_listener.xml');
113
114 5
            $service = $container->getDefinition('fos_rest.body_listener');
115
116 5
            if (!empty($config['body_listener']['service'])) {
117
                $service->clearTag('kernel.event_listener');
118
            }
119
120 5
            $service->replaceArgument(1, $config['body_listener']['throw_exception_on_unsupported_content_type']);
121 5
            $service->addMethodCall('setDefaultFormat', array($config['body_listener']['default_format']));
122
123 5
            $container->getDefinition('fos_rest.decoder_provider')->replaceArgument(1, $config['body_listener']['decoders']);
124
125 5
            $decoderServicesMap = array();
126
127 5
            foreach ($config['body_listener']['decoders'] as $id) {
128 5
                $decoderServicesMap[$id] = new Reference($id);
129
            }
130
131 5
            $decodersServiceLocator = ServiceLocatorTagPass::register($container, $decoderServicesMap);
132 5
            $container->getDefinition('fos_rest.decoder_provider')->replaceArgument(0, $decodersServiceLocator);
133
134 5
            $arrayNormalizer = $config['body_listener']['array_normalizer'];
135
136 5
            if (null !== $arrayNormalizer['service']) {
137 3
                $bodyListener = $container->getDefinition('fos_rest.body_listener');
138 3
                $bodyListener->addArgument(new Reference($arrayNormalizer['service']));
139 3
                $bodyListener->addArgument($arrayNormalizer['forms']);
140
            }
141
        }
142 44
    }
143
144 44
    private function loadFormatListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
145
    {
146 44
        if ($config['format_listener']['enabled'] && !empty($config['format_listener']['rules'])) {
147 3
            $loader->load('format_listener.xml');
148
149 3
            if (!empty($config['format_listener']['service'])) {
150
                $service = $container->getDefinition('fos_rest.format_listener');
151
                $service->clearTag('kernel.event_listener');
152
            }
153
154 3
            $container->setParameter(
155 3
                'fos_rest.format_listener.rules',
156 3
                $config['format_listener']['rules']
157
            );
158
        }
159 44
    }
160
161 44
    private function loadVersioning(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
162
    {
163 44
        if (!empty($config['versioning']['enabled'])) {
164
            $loader->load('versioning.xml');
165
166
            $versionListener = $container->getDefinition('fos_rest.versioning.listener');
167
            $versionListener->replaceArgument(1, $config['versioning']['default_version']);
168
169
            $resolvers = [];
170
            if ($config['versioning']['resolvers']['query']['enabled']) {
171
                $resolvers['query'] = $container->getDefinition('fos_rest.versioning.query_parameter_resolver');
172
                $resolvers['query']->replaceArgument(0, $config['versioning']['resolvers']['query']['parameter_name']);
173
            }
174
            if ($config['versioning']['resolvers']['custom_header']['enabled']) {
175
                $resolvers['custom_header'] = $container->getDefinition('fos_rest.versioning.header_resolver');
176
                $resolvers['custom_header']->replaceArgument(0, $config['versioning']['resolvers']['custom_header']['header_name']);
177
            }
178
            if ($config['versioning']['resolvers']['media_type']['enabled']) {
179
                $resolvers['media_type'] = $container->getDefinition('fos_rest.versioning.media_type_resolver');
180
                $resolvers['media_type']->replaceArgument(0, $config['versioning']['resolvers']['media_type']['regex']);
181
            }
182
183
            $chainResolver = $container->getDefinition('fos_rest.versioning.chain_resolver');
184
            foreach ($config['versioning']['guessing_order'] as $resolver) {
185
                if (isset($resolvers[$resolver])) {
186
                    $chainResolver->addMethodCall('addResolver', [$resolvers[$resolver]]);
187
                }
188
            }
189
        }
190 44
    }
191
192 44
    private function loadParamFetcherListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
193
    {
194 44
        if ($config['param_fetcher_listener']['enabled']) {
195 3
            if (!class_exists(Constraint::class)) {
196
                throw new \LogicException('Enabling the fos_rest.param_fetcher_listener option when the Symfony Validator component is not installed is not supported. Try installing the symfony/validator package.');
197
            }
198
199 3
            $loader->load('param_fetcher_listener.xml');
200
201 3
            if (!empty($config['param_fetcher_listener']['service'])) {
202
                $service = $container->getDefinition('fos_rest.param_fetcher_listener');
203
                $service->clearTag('kernel.event_listener');
204
            }
205
206 3
            if ($config['param_fetcher_listener']['force']) {
207 1
                $container->getDefinition('fos_rest.param_fetcher_listener')->replaceArgument(1, true);
208
            }
209
        }
210 44
    }
211
212 44
    private function loadBodyConverter(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
213
    {
214 44
        if (!$this->isConfigEnabled($container, $config['body_converter'])) {
215 40
            return;
216
        }
217
218 4
        $loader->load('request_body_param_converter.xml');
219
220 4
        if (!empty($config['body_converter']['validation_errors_argument'])) {
221 4
            $container->getDefinition('fos_rest.converter.request_body')->replaceArgument(4, $config['body_converter']['validation_errors_argument']);
222
        }
223 4
    }
224
225 44
    private function loadView(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
226
    {
227 44
        if (!empty($config['view']['jsonp_handler'])) {
228 1
            $handler = new ChildDefinition($config['service']['view_handler']);
229 1
            $handler->setPublic(true);
230
231 1
            $jsonpHandler = new Reference('fos_rest.view_handler.jsonp');
232 1
            $handler->addMethodCall('registerHandler', ['jsonp', [$jsonpHandler, 'createResponse']]);
233 1
            $container->setDefinition('fos_rest.view_handler', $handler);
234
235 1
            $container->getDefinition('fos_rest.view_handler.jsonp')->replaceArgument(0, $config['view']['jsonp_handler']['callback_param']);
236
237 1
            if (empty($config['view']['mime_types']['jsonp'])) {
238 1
                $config['view']['mime_types']['jsonp'] = $config['view']['jsonp_handler']['mime_type'];
239
            }
240
        }
241
242 44
        if ($config['view']['mime_types']['enabled']) {
243 1
            $loader->load('mime_type_listener.xml');
244
245 1
            if (!empty($config['mime_type_listener']['service'])) {
246
                $service = $container->getDefinition('fos_rest.mime_type_listener');
247
                $service->clearTag('kernel.event_listener');
248
            }
249
250 1
            $container->getDefinition('fos_rest.mime_type_listener')->replaceArgument(0, $config['view']['mime_types']['formats']);
251
        }
252
253 44
        if ($config['view']['view_response_listener']['enabled']) {
254 5
            $loader->load('view_response_listener.xml');
255 5
            $service = $container->getDefinition('fos_rest.view_response_listener');
256
257 5
            if (!empty($config['view_response_listener']['service'])) {
258
                $service->clearTag('kernel.event_listener');
259
            }
260
261 5
            $service->replaceArgument(1, $config['view']['view_response_listener']['force']);
262
        }
263
264 44
        $formats = [];
265 44
        foreach ($config['view']['formats'] as $format => $enabled) {
266 44
            if ($enabled) {
267 44
                $formats[$format] = false;
268
            }
269
        }
270
271 44
        if (!is_numeric($config['view']['failed_validation'])) {
272
            $config['view']['failed_validation'] = constant(sprintf('%s::%s', Response::class, $config['view']['failed_validation']));
273
        }
274
275 44
        if (!is_numeric($config['view']['empty_content'])) {
276
            $config['view']['empty_content'] = constant(sprintf('%s::%s', Response::class, $config['view']['empty_content']));
277
        }
278
279 44
        $defaultViewHandler = $container->getDefinition('fos_rest.view_handler.default');
280 44
        $defaultViewHandler->setFactory([ViewHandler::class, 'create']);
281 44
        $defaultViewHandler->setArguments([
282 44
            new Reference('router'),
283 44
            new Reference('fos_rest.serializer'),
284 44
            new Reference('request_stack'),
285 44
            $formats,
286 44
            $config['view']['failed_validation'],
287 44
            $config['view']['empty_content'],
288 44
            $config['view']['serialize_null'],
289
        ]);
290 44
    }
291
292 44
    private function loadException(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
293
    {
294 44
        if ($config['exception']['enabled']) {
295 11
            $loader->load('exception.xml');
296
297 11
            if ($config['exception']['map_exception_codes']) {
298 1
                $container->register('fos_rest.exception.response_status_code_listener', ResponseStatusCodeListener::class)
299 1
                    ->setArguments([
300 1
                        new Reference('fos_rest.exception.codes_map'),
301
                    ])
302 1
                    ->addTag('kernel.event_subscriber');
303
            }
304
305 11
            $container->getDefinition('fos_rest.exception.codes_map')
306 11
                ->replaceArgument(0, $config['exception']['codes']);
307 11
            $container->getDefinition('fos_rest.exception.messages_map')
308 11
                ->replaceArgument(0, $config['exception']['messages']);
309
310 11
            $container->getDefinition('fos_rest.serializer.flatten_exception_handler')
311 11
                ->replaceArgument(1, $config['exception']['debug']);
312 11
            $container->getDefinition('fos_rest.serializer.flatten_exception_handler')
313 11
                ->replaceArgument(2, 'rfc7807' === $config['exception']['flatten_exception_format']);
314 11
            $container->getDefinition('fos_rest.serializer.flatten_exception_normalizer')
315 11
                ->replaceArgument(1, $config['exception']['debug']);
316 11
            $container->getDefinition('fos_rest.serializer.flatten_exception_normalizer')
317 11
                ->replaceArgument(2, 'rfc7807' === $config['exception']['flatten_exception_format']);
318
319 11
            if ($config['exception']['serializer_error_renderer']) {
320 3
                $format = new Definition();
321 3
                $format->setFactory([SerializerErrorRenderer::class, 'getPreferredFormat']);
322 3
                $format->setArguments([
323 3
                    new Reference('request_stack'),
324
                ]);
325 3
                $debug = new Definition();
326 3
                $debug->setFactory([SerializerErrorRenderer::class, 'isDebug']);
327 3
                $debug->setArguments([
328 3
                    new Reference('request_stack'),
329 3
                    '%kernel.debug%',
330
                ]);
331 3
                $container->register('fos_rest.error_renderer.serializer', SerializerErrorRenderer::class)
332 3
                    ->setArguments([
333 3
                        new Reference('fos_rest.serializer'),
334 3
                        $format,
335 3
                        new Reference('error_renderer.html', ContainerInterface::NULL_ON_INVALID_REFERENCE),
336 3
                        $debug,
337
                    ]);
338 3
                $container->setAlias('error_renderer', 'fos_rest.error_renderer.serializer');
339
            }
340
        }
341 44
    }
342
343 44
    private function loadSerializer(array $config, ContainerBuilder $container): void
344
    {
345 44
        $bodyConverter = $container->hasDefinition('fos_rest.converter.request_body') ? $container->getDefinition('fos_rest.converter.request_body') : null;
346 44
        $viewHandler = $container->getDefinition('fos_rest.view_handler.default');
347 44
        $options = array();
348
349 44
        if (!empty($config['serializer']['version'])) {
350 1
            if ($bodyConverter) {
351
                $bodyConverter->replaceArgument(2, $config['serializer']['version']);
352
            }
353 1
            $options['exclusionStrategyVersion'] = $config['serializer']['version'];
354
        }
355
356 44
        if (!empty($config['serializer']['groups'])) {
357 1
            if ($bodyConverter) {
358
                $bodyConverter->replaceArgument(1, $config['serializer']['groups']);
359
            }
360 1
            $options['exclusionStrategyGroups'] = $config['serializer']['groups'];
361
        }
362
363 44
        $options['serializeNullStrategy'] = $config['serializer']['serialize_null'];
364 44
        $viewHandler->addArgument($options);
365 44
    }
366
367 44
    private function loadZoneMatcherListener(array $config, XmlFileLoader $loader, ContainerBuilder $container): void
368
    {
369 44
        if (!empty($config['zone'])) {
370 1
            $loader->load('zone_matcher_listener.xml');
371 1
            $zoneMatcherListener = $container->getDefinition('fos_rest.zone_matcher_listener');
372
373 1
            foreach ($config['zone'] as $zone) {
374 1
                $matcher = $this->createZoneRequestMatcher(
375 1
                    $container,
376 1
                    $zone['path'],
377 1
                    $zone['host'],
378 1
                    $zone['methods'],
379 1
                    $zone['ips']
380
                );
381
382 1
                $zoneMatcherListener->addMethodCall('addRequestMatcher', array($matcher));
383
            }
384
        }
385 44
    }
386
387 1
    private function createZoneRequestMatcher(ContainerBuilder $container, ?string $path = null, ?string $host = null, array $methods = array(), array $ips = null): Reference
388
    {
389 1
        if ($methods) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $methods of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
390
            $methods = array_map('strtoupper', (array) $methods);
391
        }
392
393 1
        $serialized = serialize(array($path, $host, $methods, $ips));
394 1
        $id = 'fos_rest.zone_request_matcher.'.md5($serialized).sha1($serialized);
395
396
        // only add arguments that are necessary
397 1
        $arguments = array($path, $host, $methods, $ips);
398 1
        while (count($arguments) > 0 && !end($arguments)) {
399 1
            array_pop($arguments);
400
        }
401
402
        $container
403 1
            ->setDefinition($id, new ChildDefinition('fos_rest.zone_request_matcher'))
404 1
            ->setArguments($arguments)
405
        ;
406
407 1
        return new Reference($id);
408
    }
409
}
410