SurfnetStepupGatewaySamlStepupProviderExtension   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 217
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 107
dl 0
loc 217
rs 10
c 3
b 0
f 0
wmc 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A createMetadataDefinition() 0 30 1
A createHostedDefinitions() 0 20 1
A buildHostedEntityDefinition() 0 25 1
A createRouteConfig() 0 5 1
A createRemoteDefinition() 0 12 1
A load() 0 19 3
A loadProviderConfiguration() 0 62 2
1
<?php
2
3
/**
4
 * Copyright 2015 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupGateway\SamlStepupProviderBundle\DependencyInjection;
20
21
use Surfnet\StepupGateway\GatewayBundle\Saml\AssertionSigningService;
22
use Surfnet\StepupGateway\SamlStepupProviderBundle\Provider\Provider;
23
use Surfnet\StepupGateway\SamlStepupProviderBundle\Saml\StateHandler;
24
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
25
use Symfony\Component\Config\FileLocator;
26
use Symfony\Component\DependencyInjection\ContainerBuilder;
27
use Symfony\Component\DependencyInjection\Definition;
28
use Symfony\Component\DependencyInjection\Loader;
29
use Symfony\Component\DependencyInjection\Reference;
30
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
31
32
/**
33
 * @SuppressWarnings(PHPMD.LongClassName)
34
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
35
 */
36
class SurfnetStepupGatewaySamlStepupProviderExtension extends Extension
37
{
38
    public const VIEW_CONFIG_TAG_NAME = 'gssp.view_config';
39
40
    /**
41
     * {@inheritdoc}
42
     */
43
    public function load(array $configs, ContainerBuilder $container): void
44
    {
45
        $configuration = new Configuration();
46
        $config = $this->processConfiguration($configuration, $configs);
47
48
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
49
        $loader->load('services.yml');
50
51
        $connectedServiceProviders = $container->getDefinition('gssp.allowed_sps');
52
        $connectedServiceProviders->replaceArgument(0, $config['allowed_sps']);
53
54
        foreach ($config['providers'] as $provider => $providerConfiguration) {
55
            // may seem a bit strange, but this prevents casing issue when getting/setting/creating provider
56
            // service definitions etc.
57
            if ($provider !== strtolower($provider)) {
58
                throw new InvalidConfigurationException('The provider name must be completely lowercase');
59
            }
60
61
            $this->loadProviderConfiguration($provider, $providerConfiguration, $config['routes'], $container);
62
        }
63
    }
64
65
    private function loadProviderConfiguration(
66
        $provider,
67
        array $configuration,
68
        array $routes,
69
        ContainerBuilder $container
70
    ): void {
71
        if ($container->has('gssp.provider.' . $provider)) {
72
            throw new InvalidConfigurationException(sprintf('Cannot create the same provider "%s" twice', $provider));
73
        }
74
75
        $this->createHostedDefinitions($provider, $configuration['hosted'], $routes, $container);
76
        $this->createMetadataDefinition($provider, $configuration['hosted'], $routes, $container);
77
        $this->createRemoteDefinition($provider, $configuration['remote'], $container);
78
79
        $stateHandlerDefinition = new Definition(StateHandler::class, [
80
            new Reference('request_stack'),
81
            $provider
82
        ]);
83
        $container->setDefinition('gssp.provider.' . $provider . '.statehandler', $stateHandlerDefinition);
84
85
        $providerDefinition = new Definition(Provider::class, [
86
            $provider,
87
            new Reference('gssp.provider.' . $provider . '.hosted.idp'),
88
            new Reference('gssp.provider.' . $provider . '.hosted.sp'),
89
            new Reference('gssp.provider.' . $provider . '.remote.idp'),
90
            new Reference('gssp.provider.' . $provider . '.statehandler')
91
        ]);
92
93
        $providerDefinition->setPublic(false);
94
        $container->setDefinition('gssp.provider.' . $provider, $providerDefinition);
95
96
        $assertionSigningService = new Definition(AssertionSigningService::class, [
97
            new Reference('gssp.provider.' . $provider . '.hosted.idp')
98
        ]);
99
        $assertionSigningService->setPublic('false');
0 ignored issues
show
Bug introduced by
'false' of type string is incompatible with the type boolean expected by parameter $boolean of Symfony\Component\Depend...Definition::setPublic(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

99
        $assertionSigningService->setPublic(/** @scrutinizer ignore-type */ 'false');
Loading history...
100
        $container->setDefinition('gssp.provider.' . $provider . '.assertion_signing', $assertionSigningService);
101
102
        $proxyResponseFactory = new Definition(
103
            \Surfnet\StepupGateway\SamlStepupProviderBundle\Saml\ProxyResponseFactory::class,
104
            [
105
                new Reference('logger'),
106
                new Reference('gssp.provider.' . $provider . '.hosted.idp'),
107
                new Reference('gssp.provider.' . $provider . '.statehandler'),
108
                new Reference('gssp.provider.' . $provider . '.assertion_signing')
109
            ]
110
        );
111
        $proxyResponseFactory->setPublic(true);
112
        $container->setDefinition('gssp.provider.' . $provider . '.response_proxy', $proxyResponseFactory);
113
114
        $container
115
            ->getDefinition('gssp.provider_repository')
116
            ->addMethodCall('addProvider', [new Reference('gssp.provider.' . $provider)])
117
            ->setPublic(true);
118
119
        $viewConfigDefinition = new Definition(\Surfnet\StepupGateway\SamlStepupProviderBundle\Provider\ViewConfig::class, [
120
            new Reference('request_stack'),
121
            $configuration['view_config']['logo'],
122
            $configuration['view_config']['title'],
123
        ]);
124
        $viewConfigDefinition->addTag(self::VIEW_CONFIG_TAG_NAME);
125
126
        $container->setDefinition('gssp.view_config.' . $provider, $viewConfigDefinition);
127
    }
128
129
    /**
130
     * @param string           $provider
131
     * @param array            $configuration
132
     * @param array            $routes
133
     * @param ContainerBuilder $container
134
     */
135
    private function createHostedDefinitions(
136
        $provider,
137
        array $configuration,
138
        array $routes,
139
        ContainerBuilder $container
140
    ): void {
141
        $hostedDefinition = $this->buildHostedEntityDefinition($provider, $configuration, $routes);
142
        $container->setDefinition('gssp.provider.' . $provider . '.hosted_entities', $hostedDefinition);
143
144
        $hostedSpDefinition  = (new Definition())
145
            ->setClass(\Surfnet\SamlBundle\Entity\ServiceProvider::class)
146
            ->setFactory([new Reference('gssp.provider.' . $provider . '.hosted_entities'), 'getServiceProvider'])
147
            ->setPublic(false);
148
        $container->setDefinition('gssp.provider.' . $provider . '.hosted.sp', $hostedSpDefinition);
149
150
        $hostedIdPDefinition = (new Definition())
151
            ->setClass(\Surfnet\SamlBundle\Entity\IdentityProvider::class)
152
            ->setFactory([new Reference('gssp.provider.' . $provider . '.hosted_entities'), 'getIdentityProvider'])
153
            ->setPublic(false);
154
        $container->setDefinition('gssp.provider.' . $provider . '.hosted.idp', $hostedIdPDefinition);
155
    }
156
157
    /**
158
     * @param string $provider
159
     * @param array  $configuration
160
     * @param array  $routes
161
     * @return Definition
162
     */
163
    private function buildHostedEntityDefinition($provider, array $configuration, array $routes)
164
    {
165
        $entityId = ['entity_id_route' => $this->createRouteConfig($provider, $routes['metadata'])];
166
        $spAdditional = [
167
            'enabled' => true,
168
            'assertion_consumer_route' => $this->createRouteConfig($provider, $routes['consume_assertion'])
169
        ];
170
        $idpAdditional = [
171
            'enabled' => true,
172
            'sso_route' => $this->createRouteConfig($provider, $routes['sso'])
173
        ];
174
175
        $serviceProvider  = array_merge($configuration['service_provider'], $spAdditional, $entityId);
176
        $identityProvider = array_merge($configuration['identity_provider'], $idpAdditional, $entityId);
177
178
        $hostedDefinition = new Definition(\Surfnet\SamlBundle\Entity\HostedEntities::class, [
179
            new Reference('router'),
180
            new Reference('request_stack'),
181
            $serviceProvider,
182
            $identityProvider
183
        ]);
184
185
        $hostedDefinition->setPublic(false);
186
187
        return $hostedDefinition;
188
    }
189
190
    /**
191
     * @param string           $provider
192
     * @param array            $configuration
193
     * @param ContainerBuilder $container
194
     */
195
    private function createRemoteDefinition($provider, array $configuration, ContainerBuilder $container): void
196
    {
197
        $definition    = new Definition(\Surfnet\SamlBundle\Entity\IdentityProvider::class, [
198
            [
199
                'entityId'        => $configuration['entity_id'],
200
                'ssoUrl'          => $configuration['sso_url'],
201
                'certificateData' => $configuration['certificate'],
202
            ]
203
        ]);
204
205
        $definition->setPublic(false);
206
        $container->setDefinition('gssp.provider.' . $provider . '.remote.idp', $definition);
207
    }
208
209
    /**
210
     * @param string           $provider
211
     * @param array            $configuration
212
     * @param array            $routes
213
     * @param ContainerBuilder $container
214
     * @return Definition
215
     */
216
    private function createMetadataDefinition(
217
        $provider,
218
        array $configuration,
219
        array $routes,
220
        ContainerBuilder $container
221
    ): void {
222
        $metadataConfiguration = new Definition(\Surfnet\SamlBundle\Metadata\MetadataConfiguration::class);
223
224
        $propertyMap = [
225
            'entityIdRoute'          => $this->createRouteConfig($provider, $routes['metadata']),
226
            'isSp'                   => true,
227
            'assertionConsumerRoute' => $this->createRouteConfig($provider, $routes['consume_assertion']),
228
            'isIdP'                  => true,
229
            'ssoRoute'               => $this->createRouteConfig($provider, $routes['sso']),
230
            'publicKey'              => $configuration['metadata']['public_key'],
231
            'privateKey'             => $configuration['metadata']['private_key'],
232
        ];
233
234
        $metadataConfiguration->setProperties($propertyMap);
235
        $metadataConfiguration->setPublic(false);
236
        $container->setDefinition('gssp.provider.' . $provider . 'metadata.configuration', $metadataConfiguration);
237
238
        $metadataFactory = new Definition(\Surfnet\SamlBundle\Metadata\MetadataFactory::class, [
239
            new Reference('twig'),
240
            new Reference('router'),
241
            new Reference('surfnet_saml.signing_service'),
242
            new Reference('gssp.provider.' . $provider . 'metadata.configuration')
243
        ]);
244
        $metadataFactory->setPublic(true);
245
        $container->setDefinition('gssp.provider.' . $provider . '.metadata.factory', $metadataFactory);
246
    }
247
248
    private function createRouteConfig($provider, $routeName)
249
    {
250
        return [
251
            'route'      => $routeName,
252
            'parameters' => ['provider' => $provider]
253
        ];
254
    }
255
}
256