SurfnetStepupSelfServiceSamlStepupProviderExtension   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 232
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 127
c 2
b 0
f 0
dl 0
loc 232
rs 10
wmc 14

8 Methods

Rating   Name   Duplication   Size   Complexity  
A createMetadataDefinition() 0 35 1
A createRemoteDefinition() 0 12 1
A createRouteConfig() 0 7 1
A createHostedDefinitions() 0 17 1
A buildHostedEntityDefinition() 0 24 1
A loadProviderConfiguration() 0 82 2
A load() 0 17 3
A validateDescriptions() 0 14 4
1
<?php
2
3
declare(strict_types = 1);
4
5
/**
6
 * Copyright 2015 SURFnet bv
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
20
21
namespace Surfnet\StepupSelfService\SamlStepupProviderBundle\DependencyInjection;
22
23
use Surfnet\SamlBundle\Entity\HostedEntities;
24
use Surfnet\SamlBundle\Entity\IdentityProvider;
25
use Surfnet\SamlBundle\Metadata\MetadataConfiguration;
26
use Surfnet\SamlBundle\Metadata\MetadataFactory;
27
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\MetadataFactoryCollection;
28
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\Provider;
29
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ViewConfig;
30
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Saml\StateHandler;
0 ignored issues
show
Bug introduced by
The type Surfnet\StepupSelfServic...undle\Saml\StateHandler was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
32
use Symfony\Component\Config\FileLocator;
33
use Symfony\Component\DependencyInjection\ContainerBuilder;
34
use Symfony\Component\DependencyInjection\Definition;
35
use Symfony\Component\DependencyInjection\Loader;
36
use Symfony\Component\DependencyInjection\Reference;
37
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
38
use Surfnet\SamlBundle\Entity\ServiceProvider;
39
40
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
41
 * @SuppressWarnings(PHPMD.LongClassName)
42
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
43
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
44
class SurfnetStepupSelfServiceSamlStepupProviderExtension extends Extension
45
{
46
47
    final public const VIEW_CONFIG_TAG_NAME = 'gssp.view_config';
48
49
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $configs should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $container should have a doc-comment as per coding-style.
Loading history...
50
     * {@inheritdoc}
51
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
52
    public function load(array $configs, ContainerBuilder $container): void
53
    {
54
        $configuration = new Configuration();
55
        $config = $this->processConfiguration($configuration, $configs);
56
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
57
        $loader->load('services.yml');
58
59
        foreach ($config['providers'] as $provider => $providerConfiguration) {
60
            // may seem a bit strange, but this prevents casing issue when getting/setting/creating provider
61
            // service definitions etc.
62
63
            assert(is_string($provider));
64
            if ($provider !== strtolower($provider)) {
65
                throw new InvalidConfigurationException('The provider name must be completely lowercase');
66
            }
67
68
            $this->loadProviderConfiguration($provider, $providerConfiguration, $config['routes'], $container);
69
        }
70
    }
71
72
    private function loadProviderConfiguration(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function loadProviderConfiguration()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::loadProviderConfiguration" must be prefixed with an underscore
Loading history...
73
        string $provider,
74
        array $configuration,
75
        array $routes,
76
        ContainerBuilder $container
77
    ): void {
78
79
        if ($container->has('gssp.provider.' . $provider)) {
80
            throw new InvalidConfigurationException(sprintf('Cannot create the same provider "%s" twice', $provider));
81
        }
82
83
        $this->createHostedDefinitions($provider, $configuration['hosted'], $routes, $container);
84
        $this->createMetadataDefinition($provider, $configuration['hosted'], $routes, $container);
85
        $this->createRemoteDefinition($provider, $configuration['remote'], $container);
86
87
        $stateHandlerDefinition = new Definition(
88
            StateHandler::class,
89
            [
90
                new Reference('request_stack'),
91
                $provider
92
            ]
93
        );
94
95
        $container->setDefinition('gssp.provider.' . $provider . '.statehandler', $stateHandlerDefinition);
96
97
        $providerDefinition = new Definition(
98
            Provider::class,
99
            [
100
                $provider,
101
                new Reference('gssp.provider.' . $provider . '.hosted.sp'),
102
                new Reference('gssp.provider.' . $provider . '.remote.idp'),
103
                new Reference('gssp.provider.' . $provider . '.statehandler')
104
            ]
105
        );
106
107
        $providerDefinition->setPublic(true);
108
        $container->setDefinition('gssp.provider.' . $provider, $providerDefinition);
109
110
        // When the android url is set, the description should contain the android play store url parameter.
111
        // The same goes for the iOs app url.
112
        $this->validateDescriptions(
113
            $configuration['view_config']['description'],
114
            $configuration['view_config']['app_android_url'],
115
            $provider,
116
            'android'
117
        );
118
119
        $this->validateDescriptions(
120
            $configuration['view_config']['description'],
121
            $configuration['view_config']['app_ios_url'],
122
            $provider,
123
            'ios'
124
        );
125
126
        $viewConfigDefinition = new Definition(
127
            ViewConfig::class,
128
            [
129
            new Reference('request_stack'),
130
            $configuration['view_config']['loa'],
131
            $configuration['view_config']['logo'],
132
            $configuration['view_config']['app_android_url'],
133
            $configuration['view_config']['app_ios_url'],
134
            $configuration['view_config']['alt'],
135
            $configuration['view_config']['title'],
136
            $configuration['view_config']['description'],
137
            $configuration['view_config']['button_use'],
138
            $configuration['view_config']['initiate_title'],
139
            $configuration['view_config']['initiate_button'],
140
            $configuration['view_config']['explanation'],
141
            $configuration['view_config']['authn_failed'],
142
            $configuration['view_config']['pop_failed'],
143
            ]
144
        );
145
        $viewConfigDefinition->addTag(self::VIEW_CONFIG_TAG_NAME);
146
        // Stop making the service public, use the ViewConfigContainer instead
147
        $viewConfigDefinition->setPublic(false);
148
149
        $container->setDefinition('gssp.view_config.' . $provider, $viewConfigDefinition);
150
151
        $container
152
            ->getDefinition('gssp.provider_repository')
153
            ->addMethodCall('addProvider', [new Reference('gssp.provider.' . $provider)]);
154
    }
155
156
    private function createHostedDefinitions(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function createHostedDefinitions()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::createHostedDefinitions" must be prefixed with an underscore
Loading history...
157
        string $provider,
158
        array $configuration,
159
        array $routes,
160
        ContainerBuilder $container
161
    ): void {
162
        $hostedDefinition = $this->buildHostedEntityDefinition($provider, $configuration, $routes);
163
        $container->setDefinition('gssp.provider.' . $provider . '.hosted_entities', $hostedDefinition);
164
165
        $hostedSpDefinition  = (new Definition())
166
            ->setClass(ServiceProvider::class)
167
            ->setFactory([
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
168
                new Reference('gssp.provider.' . $provider . '.hosted_entities'),
169
                'getServiceProvider'
170
            ])
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
171
            ->setPublic(false);
172
        $container->setDefinition('gssp.provider.' . $provider . '.hosted.sp', $hostedSpDefinition);
173
    }
174
175
    private function buildHostedEntityDefinition(string $provider, array $configuration, array $routes): Definition
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function buildHostedEntityDefinition()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::buildHostedEntityDefinition" must be prefixed with an underscore
Loading history...
176
    {
177
        $entityId = ['entity_id_route' => $this->createRouteConfig($provider, $routes['metadata'])];
178
        $spAdditional = [
179
            'enabled' => true,
180
            'assertion_consumer_route' => $this->createRouteConfig($provider, $routes['consume_assertion'])
181
        ];
182
        $idpAdditional = [
183
            'enabled' => false,
184
        ];
185
186
        $serviceProvider  = array_merge($configuration['service_provider'], $spAdditional, $entityId);
187
        $identityProvider = [...$idpAdditional, ...$entityId];
188
189
        $hostedDefinition = new Definition(HostedEntities::class, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
190
            new Reference('router'),
191
            new Reference('request_stack'),
192
            $serviceProvider,
193
            $identityProvider
194
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
195
196
        $hostedDefinition->setPublic(false);
197
198
        return $hostedDefinition;
199
    }
200
201
    private function createRemoteDefinition(string $provider, array $configuration, ContainerBuilder $container): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function createRemoteDefinition()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::createRemoteDefinition" must be prefixed with an underscore
Loading history...
202
    {
203
        $definition    = new Definition(IdentityProvider::class, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
204
            [
205
                'entityId'        => $configuration['entity_id'],
206
                'ssoUrl'          => $configuration['sso_url'],
207
                'certificateData' => $configuration['certificate'],
208
            ]
209
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
210
211
        $definition->setPublic(false);
212
        $container->setDefinition('gssp.provider.' . $provider . '.remote.idp', $definition);
213
    }
214
215
    private function createMetadataDefinition(
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function createMetadataDefinition()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::createMetadataDefinition" must be prefixed with an underscore
Loading history...
216
        string $provider,
217
        array $configuration,
218
        array $routes,
219
        ContainerBuilder $container
220
    ): void {
221
        $metadataConfiguration = new Definition(MetadataConfiguration::class);
222
223
        $propertyMap = [
224
            'entityIdRoute'          => $this->createRouteConfig($provider, $routes['metadata']),
225
            'isSp'                   => true,
226
            'assertionConsumerRoute' => $this->createRouteConfig($provider, $routes['consume_assertion']),
227
            'isIdP'                  => false,
228
            'publicKey'              => $configuration['metadata']['public_key'],
229
            'privateKey'             => $configuration['metadata']['private_key'],
230
        ];
231
232
        $metadataConfiguration->setProperties($propertyMap);
233
        $metadataConfiguration->setPublic(false);
234
        $container->setDefinition('gssp.provider.' . $provider . 'metadata.configuration', $metadataConfiguration);
235
236
        $metadataFactory = new Definition(MetadataFactory::class, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
237
            new Reference('twig'),
238
            new Reference('router'),
239
            new Reference('surfnet_saml.signing_service'),
240
            new Reference('gssp.provider.' . $provider . 'metadata.configuration')
241
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
242
        $metadataFactoryServiceId = 'gssp.provider.' . $provider . '.metadata.factory';
243
        $container->setDefinition($metadataFactoryServiceId, $metadataFactory);
244
        // Should not be read from container directly, use MetadataFactoryCollection instead
245
        // @deprecated: this service should not be used anymore
246
        $metadataFactory->setPublic(false);
247
248
        $container = $container->getDefinition(MetadataFactoryCollection::class);
249
        $container->addMethodCall('add', [$provider, new Reference($metadataFactoryServiceId)]);
250
    }
251
252
    private function createRouteConfig(string $provider, $routeName): array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function createRouteConfig()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::createRouteConfig" must be prefixed with an underscore
Loading history...
253
    {
254
        // In the future, we ought to wrap this in an object.
255
        // https://www.pivotaltracker.com/story/show/90095392
256
        return [
257
            'route'      => $routeName,
258
            'parameters' => ['provider' => $provider]
259
        ];
260
    }
261
262
    private function validateDescriptions($descriptions, $appUrl, string $provider, string $type): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function validateDescriptions()
Loading history...
Coding Style introduced by
Private method name "SurfnetStepupSelfServiceSamlStepupProviderExtension::validateDescriptions" must be prefixed with an underscore
Loading history...
263
    {
264
        $regex ="/%%{$type}_link_start%%[a-zA-Z0-9 ]+%%{$type}_link_end%%/";
265
        foreach ($descriptions as $lang => $description) {
266
            if ($appUrl !== false && preg_match($regex, (string) $description) === 0) {
267
                throw new InvalidConfigurationException(
268
                    sprintf(
269
                        'You have configured a GSSP provider with app URL\'s but the description is not ' .
270
                        'configured correctly yet. Missing "%%%1$s_link_start%%" or "%%%1$s_link_end%%" in ' .
271
                        'GSSP description for language "%2$s" in "providers.%3$s.view_config.description" of '.
272
                        'samlstepupproviders.yml',
273
                        $type,
274
                        $lang,
275
                        $provider
276
                    )
277
                );
278
            }
279
        }
280
    }
281
}
282