Completed
Push — master ( 8d84a0...460d3f )
by Chad
01:57
created

Configuration   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 245
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 3
dl 0
loc 245
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getConfigTreeBuilder() 0 12 1
A addMainSection() 0 7 1
B addDoctrineSection() 0 25 1
B addGeneralSection() 0 24 1
A addLdapDomainsSection() 0 60 1
B addSecuritySection() 0 78 1
1
<?php
2
/**
3
 * This file is part of the LdapToolsBundle package.
4
 *
5
 * (c) Chad Sikorra <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LdapTools\Bundle\LdapToolsBundle\DependencyInjection;
12
13
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
14
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
15
use Symfony\Component\Config\Definition\ConfigurationInterface;
16
17
/**
18
 * LdapToolsBundle configuration options.
19
 *
20
 * @author Chad Sikorra <[email protected]>
21
 */
22
class Configuration implements ConfigurationInterface
23
{
24
    /**
25
     * @var bool Whether or not debug mode is in use.
26
     */
27
    protected $debug;
28
29
    /**
30
     * @param bool $debug
31
     */
32
    public function __construct($debug)
33
    {
34
        $this->debug = (bool) $debug;
35
    }
36
37
    /**
38
     * {@inheritDoc}
39
     */
40
    public function getConfigTreeBuilder()
41
    {
42
        $treeBuilder = new TreeBuilder();
43
        $rootNode = $treeBuilder->root('ldap_tools');
44
        $this->addMainSection($rootNode);
45
        $this->addDoctrineSection($rootNode);
46
        $this->addGeneralSection($rootNode);
47
        $this->addLdapDomainsSection($rootNode);
48
        $this->addSecuritySection($rootNode);
49
50
        return $treeBuilder;
51
    }
52
53
    /**
54
     * @param ArrayNodeDefinition $node
55
     */
56
    protected function addMainSection(ArrayNodeDefinition $node)
57
    {
58
        $node->children()
59
            ->booleanNode('logging')->defaultValue($this->debug)->end()
60
            ->booleanNode('profiling')->defaultValue($this->debug)->end()
61
            ->end();
62
    }
63
64
    /**
65
     * @param ArrayNodeDefinition $node
66
     */
67
    protected function addDoctrineSection(ArrayNodeDefinition $node)
68
    {
69
        $node
70
            ->children()
71
            ->arrayNode('doctrine')
72
                ->addDefaultsIfNotSet()
73
                ->children()
74
                    ->booleanNode('integration_enabled')->defaultTrue()
75
                        ->info('Whether or not Doctrine integration should be used (adds a subscriber for lifecycle events)')->end()
76
                    ->arrayNode('connections')
77
                        ->info('Only use doctrine integration on a specific connection name(s)')
78
                        ->beforeNormalization()
79
                            ->ifTrue(function ($v) {
80
                                return !is_array($v);
81
                            })
82
                            ->then(function ($v) {
83
                                return [$v];
84
                            })
85
                            ->end()
86
                        ->prototype('scalar')->end()
87
                        ->end()
88
                    ->end()
89
                ->end()
90
            ->end();
91
    }
92
93
    /**
94
     * @param ArrayNodeDefinition $node
95
     */
96
    private function addGeneralSection(ArrayNodeDefinition $node)
97
    {
98
        $node
99
            ->children()
100
            ->arrayNode('general')
101
                ->addDefaultsIfNotSet()
102
                ->children()
103
                    ->scalarNode('default_domain')
104
                        ->info('If more than one domain is defined, explicitly set which is the default context for the LdapManager (by domain_name)')->end()
105
                    ->scalarNode('schema_format')->end()
106
                    ->scalarNode('schema_folder')->end()
107
                    ->scalarNode('cache_type')->defaultValue('doctrine')->end()
108
                    ->arrayNode('cache_options')
109
                        ->addDefaultsIfNotSet()
110
                        ->children()
111
                            ->scalarNode('cache_folder')->defaultValue('%kernel.cache_dir%/ldaptools')->end()
112
                            ->booleanNode('cache_auto_refresh')->defaultFalse()->end()
113
                            ->end()
114
                        ->end()
115
                    ->arrayNode('attribute_converters')->end()
116
                    ->end()
117
                ->end()
118
            ->end();
119
    }
120
121
    /**
122
     * @param ArrayNodeDefinition $node
123
     */
124
    private function addLdapDomainsSection(ArrayNodeDefinition $node)
125
    {
126
        $node
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method children() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
127
            ->children()
128
                ->arrayNode('domains')
129
                ->prototype('array')
130
                ->children()
131
                    ->scalarNode('domain_name')->isRequired()
132
                        ->info('The FQDN (ie. example.com)')->end()
133
                    ->scalarNode('username')->isRequired()
134
                        ->info('The username/DN/SID/GUID to used to connect to LDAP.')->end()
135
                    ->scalarNode('password')->isRequired()
136
                        ->info('The password for the username used to connect to LDAP.')->end()
137
                    ->scalarNode('base_dn')
138
                        ->info('The base DN used for searches (ie. dc=example,dc=com). This is queried from the RootDSE if not provided.')->end()
139
                    ->integerNode('port')
140
                        ->info('The default port number to connect to LDAP on.')->end()
141
                    ->booleanNode('use_paging')
142
                        ->info('Whether or not search results should be paged')->end()
143
                    ->integerNode('page_size')
144
                        ->info('The size for paged result searches.')->end()
145
                    ->booleanNode('use_tls')
146
                        ->info('Encrypt the connection with TLS. This is required when modifying LDAP passwords.')->end()
147
                    ->booleanNode('use_ssl')
148
                        ->info('Encrypt the connection with SSL. Typically you want to use "use_tls" and not this option.')->end()
149
                    ->scalarNode('ldap_type')
150
                        ->info('The LDAP type for this domain. Choices are ad or openldap.')->end()
151
                    ->arrayNode('servers')
152
                        ->info('The LDAP servers to connect to. This is queried from DNS if not provided.')
153
                        ->beforeNormalization()
154
                            ->ifTrue(function ($v) {
155
                                return !is_array($v);
156
                            })
157
                            ->then(function ($v) {
158
                                return [$v];
159
                            })
160
                            ->end()
161
                        ->prototype('scalar')->end()
162
                        ->end()
163
                    ->booleanNode('lazy_bind')
164
                        ->info('If set to true, then the connection will not automatically connect and bind when first created.')->end()
165
                    ->integerNode('idle_reconnect')
166
                        ->info('The elapsed time (in seconds) when an idle connection will attempt to reconnect to LDAP.')->end()
167
                    ->integerNode('connect_timeout')
168
                        ->info('The elapsed time (in seconds) to wait while attempting the initial connection to LDAP.')->end()
169
                    ->scalarNode('server_selection')
170
                        ->info('Determines how the LDAP server is selected. Can be "order" or "random".')->end()
171
                    ->scalarNode('encoding')->end()
172
                    ->scalarNode('schema_name')
173
                        ->info('The schema name to use for this domain')->end()
174
                    ->scalarNode('bind_format')
175
                        ->info('Set to a string that determines where the username is placed in a bind attempt: %%username%%,ou=users,dc=foo,dc=bar')->end()
176
                    ->arrayNode('ldap_options')
177
                        ->info('Set specific LDAP_OPT_* constants to use. Specify them using their string name as keys along with their values.')
178
                        ->useAttributeAsKey('name')
179
                        ->prototype('variable')
180
                        ->end()
181
                ->end()
182
        ->end();
183
    }
184
185
    /**
186
     * @param ArrayNodeDefinition $node
187
     */
188
    protected function addSecuritySection(ArrayNodeDefinition $node)
189
    {
190
        $node
191
            ->children()
192
                ->arrayNode('security')
193
                    ->addDefaultsIfNotSet()
194
                    ->children()
195
                    ->scalarNode('search_base')
196
                        ->info('The default DN to start the user search from.')->end()
197
                    ->scalarNode('ldap_object_type')->defaultValue('user')
198
                        ->info('The LdapTools object type for the user provider to search for.')->end()
199
                    ->scalarNode('default_role')->defaultValue('ROLE_USER')
200
                        ->info('Regardless of group membership this role will be assigned to the loaded user. Set it to null for no roles to be assigned by default.')->end()
201
                    ->booleanNode('check_groups_recursively')
202
                        ->info('If set to true then group membership will contain all groups, and nested groups, the user belongs to.')->defaultTrue()->end()
203
                    ->scalarNode('user')->defaultValue('\LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUser')
204
                        ->info('The user class that the LDAP user provider will instantiate. If you change this the class must extend the default one.')->end()
205
                    ->arrayNode('default_attributes')
206
                        ->info('Set the default LDAP attributes mapped for the LDAP user provider class.')
207
                        ->addDefaultsIfNotSet()
208
                        ->children()
209
                            ->scalarNode('username')->defaultValue('username')->end()
210
                            ->scalarNode('accountNonLocked')->defaultValue('locked')->end()
211
                            ->scalarNode('accountNonExpired')->defaultValue('accountExpirationDate')->end()
212
                            ->scalarNode('enabled')->defaultValue('disabled')->end()
213
                            ->scalarNode('credentialsNonExpired')->defaultValue('passwordMustChange')->end()
214
                            ->scalarNode('groups')->defaultValue('groups')->end()
215
                            ->scalarNode('guid')->defaultValue('guid')->end()
216
                            ->scalarNode('stringRepresentation')->defaultValue('username')->end()
217
                            ->end()
218
                        ->end()
219
                    ->arrayNode('guard')
220
                        ->info('Guard specific configuration options.')
221
                        ->addDefaultsIfNotSet()
222
                        ->children()
223
                            ->scalarNode('start_path')->defaultValue('login')
224
                                ->info('The default entry point/starting path as a route name.')->end()
225
                        ->end()
226
                    ->end()
227
                    ->arrayNode('additional_attributes')
228
                        ->info('Any additional attribute values that should be available when the user is loaded.')
229
                        ->prototype('scalar')->end()
230
                        ->end()
231
                    ->arrayNode('roles')
232
                        ->info('Map LDAP group names to specific roles. If a user is a member of the group they will get the role mapped to it.')
233
                        ->useAttributeAsKey('name')
234
                        ->prototype('array')
235
                        ->beforeNormalization()
236
                            ->ifTrue(function ($v) {
237
                                return !is_array($v);
238
                            })
239
                            ->then(function ($v) {
240
                                return [$v];
241
                            })
242
                            ->end()
243
                        ->prototype('scalar')->end()
244
                        ->end()
245
                        ->end()
246
                    ->scalarNode('role_ldap_type')->defaultValue('group')
247
                        ->info('The LdapTools object type for the groups used to check for roles.')->end()
248
                    ->arrayNode('role_attributes')
249
                        ->info('When searching for groups/roles for a user, map to these attributes for GUID, SID, members, or name.')
250
                        ->addDefaultsIfNotSet()
251
                        ->children()
252
                            ->scalarNode('name')->defaultValue('name')->end()
253
                            ->scalarNode('sid')->defaultValue('sid')->end()
254
                            ->scalarNode('guid')->defaultValue('guid')->end()
255
                            ->scalarNode('members')->defaultValue('members')->end()
256
                            ->end()
257
                        ->end()
258
                    ->booleanNode('refresh_user_attributes')
259
                        ->info('Set this to true if you want user attributes re-queried on a user refresh.')->defaultFalse()->end()
260
                    ->booleanNode('refresh_user_roles')
261
                        ->info('Set this to true if you want user roles re-queried on a user refresh.')->defaultFalse()->end()
262
                    ->end()
263
                ->end()
264
            ->end();
265
    }
266
}
267