Completed
Push — feature/gssp-add-through-confi... ( dd4473...1f4d21 )
by
unknown
02:53
created

createRouteConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
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\StepupSelfService\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 SurfnetStepupSelfServiceSamlStepupProviderExtension extends Extension
30
{
31
    /**
32
     * {@inheritdoc}
33
     */
34
    public function load(array $configs, ContainerBuilder $container)
35
    {
36
        $configuration = new Configuration();
37
        $config = $this->processConfiguration($configuration, $configs);
38
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
39
        $loader->load('services.yml');
40
41
        foreach ($config['providers'] as $provider => $providerConfiguration) {
42
            // may seem a bit strange, but this prevents casing issue when getting/setting/creating provider
43
            // service definitions etc.
44
            if ($provider !== strtolower($provider)) {
45
                throw new InvalidConfigurationException('The provider name must be completely lowercase');
46
            }
47
48
            $this->loadProviderConfiguration($provider, $providerConfiguration, $config['routes'], $container);
49
        }
50
    }
51
52
    private function loadProviderConfiguration(
53
        $provider,
54
        array $configuration,
55
        array $routes,
56
        ContainerBuilder $container
57
    ) {
58
59
        if ($container->has('gssp.provider.' . $provider)) {
60
            throw new InvalidConfigurationException(sprintf('Cannot create the same provider "%s" twice', $provider));
61
        }
62
63
        $this->createHostedDefinitions($provider, $configuration['hosted'], $routes, $container);
64
        $this->createMetadataDefinition($provider, $configuration['hosted'], $routes, $container);
65
        $this->createRemoteDefinition($provider, $configuration['remote'], $container);
66
67
        $stateHandlerDefinition = new Definition('Surfnet\StepupSelfService\SamlStepupProviderBundle\Saml\StateHandler', [
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
68
            new Reference('gssp.sessionbag'),
69
            $provider
70
        ]);
71
        $container->setDefinition('gssp.provider.' . $provider . '.statehandler', $stateHandlerDefinition);
72
73
        $providerDefinition = new Definition('Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\Provider', [
74
            $provider,
75
            new Reference('gssp.provider.' . $provider . '.hosted.sp'),
76
            new Reference('gssp.provider.' . $provider . '.remote.idp'),
77
            new Reference('gssp.provider.' . $provider . '.statehandler')
78
        ]);
79
80
        $providerDefinition->setPublic(false);
81
        $container->setDefinition('gssp.provider.' . $provider, $providerDefinition);
82
83
        $viewConfigDefinition = new Definition('Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ViewConfig', [
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
84
            $configuration['view_config']['loa'],
85
            $configuration['view_config']['logo'],
86
            $configuration['view_config']['alt'],
87
            $configuration['view_config']['title'],
88
            $configuration['view_config']['description'],
89
            $configuration['view_config']['button_use'],
90
            $configuration['view_config']['initiate_title'],
91
            $configuration['view_config']['initiate_button'],
92
            $configuration['view_config']['explanation'],
93
            $configuration['view_config']['authn_failed'],
94
            $configuration['view_config']['pop_failed'],
95
        ]);
96
97
        $container->setDefinition('gssp.view_config.' . $provider, $viewConfigDefinition);
98
99
        $container
100
            ->getDefinition('gssp.provider_repository')
101
            ->addMethodCall('addProvider', [new Reference('gssp.provider.' . $provider)]);
102
    }
103
104
    /**
105
     * @param string           $provider
106
     * @param array            $configuration
107
     * @param array            $routes
108
     * @param ContainerBuilder $container
109
     */
110
    private function createHostedDefinitions(
111
        $provider,
112
        array $configuration,
113
        array $routes,
114
        ContainerBuilder $container
115
    ) {
116
        $hostedDefinition = $this->buildHostedEntityDefinition($provider, $configuration, $routes);
117
        $container->setDefinition('gssp.provider.' . $provider . '.hosted_entities', $hostedDefinition);
118
119
        $hostedSpDefinition  = (new Definition())
120
            ->setClass('Surfnet\SamlBundle\Entity\ServiceProvider')
121
            ->setFactory([
122
                new Reference('gssp.provider.' . $provider . '.hosted_entities'),
123
                'getServiceProvider'
124
            ])
125
            ->setPublic(false);
126
        $container->setDefinition('gssp.provider.' . $provider . '.hosted.sp', $hostedSpDefinition);
127
    }
128
129
    /**
130
     * @param string $provider
131
     * @param array  $configuration
132
     * @param array  $routes
133
     * @return Definition
134
     */
135
    private function buildHostedEntityDefinition($provider, array $configuration, array $routes)
136
    {
137
        $entityId = ['entity_id_route' => $this->createRouteConfig($provider, $routes['metadata'])];
138
        $spAdditional = [
139
            'enabled' => true,
140
            'assertion_consumer_route' => $this->createRouteConfig($provider, $routes['consume_assertion'])
141
        ];
142
        $idpAdditional = [
143
            'enabled' => false,
144
        ];
145
146
        $serviceProvider  = array_merge($configuration['service_provider'], $spAdditional, $entityId);
147
        $identityProvider = array_merge($idpAdditional, $entityId);
148
149
        $hostedDefinition = new Definition('Surfnet\SamlBundle\Entity\HostedEntities', [
150
            new Reference('router'),
151
            new Reference('request_stack'),
152
            $serviceProvider,
153
            $identityProvider
154
        ]);
155
156
        $hostedDefinition->setPublic(false);
157
158
        return $hostedDefinition;
159
    }
160
161
    /**
162
     * @param string           $provider
163
     * @param array            $configuration
164
     * @param ContainerBuilder $container
165
     */
166
    private function createRemoteDefinition($provider, array $configuration, ContainerBuilder $container)
167
    {
168
        $definition    = new Definition('Surfnet\SamlBundle\Entity\IdentityProvider', [
169
            [
170
                'entityId'        => $configuration['entity_id'],
171
                'ssoUrl'          => $configuration['sso_url'],
172
                'certificateData' => $configuration['certificate'],
173
            ]
174
        ]);
175
176
        $definition->setPublic(false);
177
        $container->setDefinition('gssp.provider.' . $provider . '.remote.idp', $definition);
178
    }
179
180
    /**
181
     * @param string           $provider
182
     * @param array            $configuration
183
     * @param array            $routes
184
     * @param ContainerBuilder $container
185
     * @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...
186
     */
187
    private function createMetadataDefinition(
188
        $provider,
189
        array $configuration,
190
        array $routes,
191
        ContainerBuilder $container
192
    ) {
193
        $metadataConfiguration = new Definition('Surfnet\SamlBundle\Metadata\MetadataConfiguration');
194
195
        $propertyMap = [
196
            'entityIdRoute'          => $this->createRouteConfig($provider, $routes['metadata']),
197
            'isSp'                   => true,
198
            'assertionConsumerRoute' => $this->createRouteConfig($provider, $routes['consume_assertion']),
199
            'isIdP'                  => false,
200
            'publicKey'              => $configuration['metadata']['public_key'],
201
            'privateKey'             => $configuration['metadata']['private_key'],
202
        ];
203
204
        $metadataConfiguration->setProperties($propertyMap);
205
        $metadataConfiguration->setPublic(false);
206
        $container->setDefinition('gssp.provider.' . $provider . 'metadata.configuration', $metadataConfiguration);
207
208
        $metadataFactory = new Definition('Surfnet\SamlBundle\Metadata\MetadataFactory', [
209
            new Reference('templating'),
210
            new Reference('router'),
211
            new Reference('surfnet_saml.signing_service'),
212
            new Reference('gssp.provider.' . $provider . 'metadata.configuration')
213
        ]);
214
        $container->setDefinition('gssp.provider.' . $provider . '.metadata.factory', $metadataFactory);
215
    }
216
217
    private function createRouteConfig($provider, $routeName)
218
    {
219
        // In the future, we ought to wrap this in an object.
220
        // https://www.pivotaltracker.com/story/show/90095392
221
        return [
222
            'route'      => $routeName,
223
            'parameters' => ['provider' => $provider]
224
        ];
225
    }
226
}
227