Completed
Pull Request — master (#8)
by Peter
04:00
created

TreeHouseKeystoneExtension::replaceLegacyTokenAuthenticator()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 7
rs 9.4286
cc 3
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace TreeHouse\KeystoneBundle\DependencyInjection;
4
5
use Symfony\Component\Config\FileLocator;
6
use Symfony\Component\DependencyInjection\ContainerBuilder;
7
use Symfony\Component\DependencyInjection\Definition;
8
use Symfony\Component\DependencyInjection\DefinitionDecorator;
9
use Symfony\Component\DependencyInjection\Loader;
10
use Symfony\Component\DependencyInjection\Reference;
11
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
12
use Symfony\Component\HttpKernel\Kernel;
13
use TreeHouse\KeystoneBundle\Security\Authentication\LegacyTokenAuthenticator;
14
15
class TreeHouseKeystoneExtension extends Extension
16
{
17
    /**
18
     * @inheritdoc
19
     */
20
    public function load(array $configs, ContainerBuilder $container)
21
    {
22
        $configuration = new Configuration();
23
        $config = $this->processConfiguration($configuration, $configs);
24
25
        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
26
        $loader->load('services.yml');
27
        $loader->load('security.yml');
28
29
        $container->setParameter('tree_house.keystone.model.user.class', $config['user_class']);
30
        $container->setParameter('tree_house.keystone.user_provider.id', $config['user_provider_id']);
31
        $container->setParameter('tree_house.keystone.service_types', $config['service_types']);
32
33
        $userProviderServiceId = $container->getParameter('tree_house.keystone.user_provider.id');
34
        $container->setAlias('tree_house.keystone.user_provider', $userProviderServiceId);
35
36
        $this->loadServices($container, $config['services'], $config['service_types']);
37
        $this->replaceLegacyTokenAuthenticator($container);
38
    }
39
40
    /**
41
     * @param ContainerBuilder $container
42
     * @param array            $services
43
     * @param array            $types
44
     *
45
     * @throws \LogicException
46
     */
47
    private function loadServices(ContainerBuilder $container, array $services, array $types)
48
    {
49
        $manager = $container->getDefinition('tree_house.keystone.service_manager');
50
        $manager->addMethodCall('setTypes', [$types]);
51
52
        foreach ($services as $name => $serviceConfig) {
53
            if (!in_array($serviceConfig['type'], $types)) {
54
                throw new \LogicException(
55
                    sprintf(
56
                        'Service must be one of the registered types (%s), "%s" given',
57
                        implode(', ', $types),
58
                        $serviceConfig['type']
59
                    )
60
                );
61
            }
62
63
            $grant = null;
64
            if (!empty($serviceConfig['role'])) {
65
                $grant = $serviceConfig['role'];
66
            }
67
68
            if (!empty($serviceConfig['expression'])) {
69
                if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
70
                    throw new \LogicException(
71
                        'Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'
72
                    );
73
                }
74
75
                if (null !== $grant) {
76
                    throw new \LogicException(<<<EOT
77
You cannot set both a role and expression for a service.
78
If you want to know how you can use the expression language
79
to check for roles, consult the documentation:
80
81
http://symfony.com/doc/current/book/security.html#complex-access-controls-with-expressions
82
83
EOT
84
                    );
85
                }
86
87
                $grant = new Definition('Symfony\Component\ExpressionLanguage\Expression');
88
                $grant->setPublic(false);
89
                $grant->addArgument($serviceConfig['expression']);
90
            }
91
92
            $id = sprintf('tree_house.keystone.service.%s', $name);
93
            $service = $container->setDefinition($id, new DefinitionDecorator('tree_house.keystone.service'));
94
            $service->replaceArgument(0, $name);
95
            $service->replaceArgument(1, $serviceConfig['type']);
96
            $service->replaceArgument(2, $grant ?: 'ROLE_USER');
97
98
            foreach ($serviceConfig['endpoint'] as $endpointConfig) {
99
                $service->addMethodCall('addEndpoint', [$endpointConfig['public_url'], $endpointConfig['admin_url']]);
100
            }
101
102
            $manager->addMethodCall('addService', [new Reference($id)]);
103
        }
104
    }
105
106
    /**
107
     * Replaces token authenticator service with legacy class for older Symfony versions.
108
     *
109
     * @todo remove when Symfony 2.6 and 2.7 are no longer supported
110
     *
111
     * @param ContainerBuilder $container
112
     */
113
    private function replaceLegacyTokenAuthenticator(ContainerBuilder $container)
114
    {
115
        if (Kernel::MAJOR_VERSION === 2 && Kernel::MINOR_VERSION < 8) {
116
            $definition = $container->getDefinition('tree_house.keystone.token_authenticator');
117
            $definition->setClass(LegacyTokenAuthenticator::class);
118
        }
119
    }
120
}
121