Completed
Pull Request — develop (#149)
by
unknown
02:31 queued 12s
created

SurfnetStepupRaSamlStepupProviderExtension   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 8
dl 0
loc 199
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A load() 0 18 3
A loadProviderConfiguration() 0 48 2
A createHostedDefinitions() 0 18 1
B buildHostedEntityDefinition() 0 25 1
A createRemoteDefinition() 0 13 1
B createMetadataDefinition() 0 29 1
A createRouteConfig() 0 9 1
1
<?php
2
3
/**
4
 * Copyright 2014 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\StepupRa\SamlStepupProviderBundle\DependencyInjection;
20
21
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
22
use Symfony\Component\Config\FileLocator;
23
use Symfony\Component\DependencyInjection\ContainerBuilder;
24
use Symfony\Component\DependencyInjection\Definition;
25
use Symfony\Component\DependencyInjection\Loader;
26
use Symfony\Component\DependencyInjection\Reference;
27
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
28
29
class SurfnetStepupRaSamlStepupProviderExtension extends Extension
30
{
31
32
    const VIEW_CONFIG_TAG_NAME = 'gssp.view_config';
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function load(array $configs, ContainerBuilder $container)
38
    {
39
        $configuration = new Configuration();
40
        $config = $this->processConfiguration($configuration, $configs);
41
42
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
43
        $loader->load('services.yml');
44
45
        foreach ($config['providers'] as $provider => $providerConfiguration) {
46
            // may seem a bit strange, but this prevents casing issue when getting/setting/creating provider
47
            // service definitions etc.
48
            if ($provider !== strtolower($provider)) {
49
                throw new InvalidConfigurationException('The provider name must be completely lowercase');
50
            }
51
52
            $this->loadProviderConfiguration($provider, $providerConfiguration, $config['routes'], $container);
53
        }
54
    }
55
56
    private function loadProviderConfiguration(
57
        $provider,
58
        array $configuration,
59
        array $routes,
60
        ContainerBuilder $container
61
    ) {
62
        if ($container->has('gssp.provider.' . $provider)) {
63
            throw new InvalidConfigurationException(sprintf('Cannot create the same provider "%s" twice', $provider));
64
        }
65
66
        $this->createHostedDefinitions($provider, $configuration['hosted'], $routes, $container);
67
        $this->createMetadataDefinition($provider, $configuration['hosted'], $routes, $container);
68
        $this->createRemoteDefinition($provider, $configuration['remote'], $container);
69
70
        $stateHandlerDefinition = new Definition('Surfnet\StepupRa\SamlStepupProviderBundle\Saml\StateHandler', [
71
            new Reference('gssp.sessionbag'),
72
            $provider
73
        ]);
74
        $container->setDefinition('gssp.provider.' . $provider . '.statehandler', $stateHandlerDefinition);
75
76
        $providerDefinition = new Definition('Surfnet\StepupRa\SamlStepupProviderBundle\Provider\Provider', [
77
            $provider,
78
            new Reference('gssp.provider.' . $provider . '.hosted.sp'),
79
            new Reference('gssp.provider.' . $provider . '.remote.idp'),
80
            new Reference('gssp.provider.' . $provider . '.statehandler')
81
        ]);
82
83
        $providerDefinition->setPublic(false);
84
        $container->setDefinition('gssp.provider.' . $provider, $providerDefinition);
85
86
        $viewConfigDefinition = new Definition('Surfnet\StepupRa\SamlStepupProviderBundle\Provider\ViewConfig', [
87
            new Reference('request'),
88
            $configuration['view_config']['name'],
89
            $configuration['view_config']['page_title'],
90
            $configuration['view_config']['explanation'],
91
            $configuration['view_config']['initiate'],
92
            $configuration['view_config']['gssf_id_mismatch'],
93
        ]);
94
        $viewConfigDefinition->setScope('request');
95
        $viewConfigDefinition->setPublic(false);
96
        $viewConfigDefinition->addTag(self::VIEW_CONFIG_TAG_NAME);
97
98
        $container->setDefinition('gssp.view_config.' . $provider, $viewConfigDefinition);
99
100
        $container
101
            ->getDefinition('gssp.provider_repository')
102
            ->addMethodCall('addProvider', [new Reference('gssp.provider.' . $provider)]);
103
    }
104
105
    /**
106
     * @param string           $provider
107
     * @param array            $configuration
108
     * @param array            $routes
109
     * @param ContainerBuilder $container
110
     */
111
    private function createHostedDefinitions(
112
        $provider,
113
        array $configuration,
114
        array $routes,
115
        ContainerBuilder $container
116
    ) {
117
        $hostedDefinition = $this->buildHostedEntityDefinition($provider, $configuration, $routes);
118
        $container->setDefinition('gssp.provider.' . $provider . '.hosted_entities', $hostedDefinition);
119
120
        $hostedSpDefinition  = (new Definition())
121
            ->setClass('Surfnet\SamlBundle\Entity\ServiceProvider')
122
            ->setFactory([
123
                new Reference('gssp.provider.' . $provider . '.hosted_entities'),
124
                'getServiceProvider'
125
            ])
126
            ->setPublic(false);
127
        $container->setDefinition('gssp.provider.' . $provider . '.hosted.sp', $hostedSpDefinition);
128
    }
129
130
    /**
131
     * @param string $provider
132
     * @param array  $configuration
133
     * @param array  $routes
134
     * @return Definition
135
     */
136
    private function buildHostedEntityDefinition($provider, array $configuration, array $routes)
137
    {
138
        $entityId = ['entity_id_route' => $this->createRouteConfig($provider, $routes['metadata'])];
139
        $spAdditional = [
140
            'enabled' => true,
141
            'assertion_consumer_route' => $this->createRouteConfig($provider, $routes['consume_assertion'])
142
        ];
143
        $idpAdditional = [
144
            'enabled' => false,
145
        ];
146
147
        $serviceProvider  = array_merge($configuration['service_provider'], $spAdditional, $entityId);
148
        $identityProvider = array_merge($idpAdditional, $entityId);
149
150
        $hostedDefinition = new Definition('Surfnet\SamlBundle\Entity\HostedEntities', [
151
            new Reference('router'),
152
            new Reference('request_stack'),
153
            $serviceProvider,
154
            $identityProvider
155
        ]);
156
157
        $hostedDefinition->setPublic(false);
158
159
        return $hostedDefinition;
160
    }
161
162
    /**
163
     * @param string           $provider
164
     * @param array            $configuration
165
     * @param ContainerBuilder $container
166
     */
167
    private function createRemoteDefinition($provider, array $configuration, ContainerBuilder $container)
168
    {
169
        $definition    = new Definition('Surfnet\SamlBundle\Entity\IdentityProvider', [
170
            [
171
                'entityId'        => $configuration['entity_id'],
172
                'ssoUrl'          => $configuration['sso_url'],
173
                'certificateData' => $configuration['certificate'],
174
            ]
175
        ]);
176
177
        $definition->setPublic(false);
178
        $container->setDefinition('gssp.provider.' . $provider . '.remote.idp', $definition);
179
    }
180
181
    /**
182
     * @param string           $provider
183
     * @param array            $configuration
184
     * @param array            $routes
185
     * @param ContainerBuilder $container
186
     * @return Definition
0 ignored issues
show
Documentation introduced by
Should the return type not be Definition|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
187
     */
188
    private function createMetadataDefinition(
189
        $provider,
190
        array $configuration,
191
        array $routes,
192
        ContainerBuilder $container
193
    ) {
194
        $metadataConfiguration = new Definition('Surfnet\SamlBundle\Metadata\MetadataConfiguration');
195
196
        $propertyMap = [
197
            'entityIdRoute'          => $this->createRouteConfig($provider, $routes['metadata']),
198
            'isSp'                   => true,
199
            'assertionConsumerRoute' => $this->createRouteConfig($provider, $routes['consume_assertion']),
200
            'isIdP'                  => false,
201
            'publicKey'              => $configuration['metadata']['public_key'],
202
            'privateKey'             => $configuration['metadata']['private_key'],
203
        ];
204
205
        $metadataConfiguration->setProperties($propertyMap);
206
        $metadataConfiguration->setPublic(false);
207
        $container->setDefinition('gssp.provider.' . $provider . 'metadata.configuration', $metadataConfiguration);
208
209
        $metadataFactory = new Definition('Surfnet\SamlBundle\Metadata\MetadataFactory', [
210
            new Reference('templating'),
211
            new Reference('router'),
212
            new Reference('surfnet_saml.signing_service'),
213
            new Reference('gssp.provider.' . $provider . 'metadata.configuration')
214
        ]);
215
        $container->setDefinition('gssp.provider.' . $provider . '.metadata.factory', $metadataFactory);
216
    }
217
218
    private function createRouteConfig($provider, $routeName)
219
    {
220
        // In the future, we ought to wrap this in an object.
221
        // https://www.pivotaltracker.com/story/show/90095392
222
        return [
223
            'route'      => $routeName,
224
            'parameters' => ['provider' => $provider]
225
        ];
226
    }
227
}
228