Completed
Pull Request — develop (#120)
by Nic
05:32 queued 02:41
created

DependencyInjection/Configuration.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\StepupSelfService\SelfServiceBundle\DependencyInjection;
20
21
use Surfnet\StepupBundle\Exception\DomainException;
22
use Surfnet\StepupBundle\Exception\InvalidArgumentException;
23
use Surfnet\StepupBundle\Value\SecondFactorType;
24
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
25
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
26
use Symfony\Component\Config\Definition\ConfigurationInterface;
27
28
class Configuration implements ConfigurationInterface
29
{
30
    public function getConfigTreeBuilder()
31
    {
32
        $treeBuilder = new TreeBuilder();
33
        $rootNode = $treeBuilder->root('surfnet_stepup_self_service_self_service');
34
35
        $childNodes = $rootNode->children();
36
        $this->appendEnabledSecondFactorTypesConfiguration($childNodes);
37
        $this->appendSecondFactorTestIdentityProvider($childNodes);
38
        $this->appendSessionConfiguration($childNodes);
39
40
        return $treeBuilder;
41
    }
42
43
    /**
44
     * @param NodeBuilder $childNodes
45
     */
46
    private function appendSessionConfiguration(NodeBuilder $childNodes)
47
    {
48
        $childNodes
49
            ->arrayNode('session_lifetimes')
50
                ->isRequired()
51
                ->children()
52
                    ->integerNode('max_absolute_lifetime')
53
                        ->isRequired()
54
                        ->defaultValue(3600)
55
                        ->info('The maximum lifetime of a session regardless of interaction by the user, in seconds.')
56
                        ->example('3600 -> 1 hour * 60 minutes * 60 seconds')
57
                        ->validate()
58
                            ->ifTrue(
59
                                function ($lifetime) {
60
                                    return !is_int($lifetime);
61
                                }
62
                            )
63
                            ->thenInvalid('max_absolute_lifetime must be an integer')
64
                        ->end()
65
                    ->end()
66
                    ->integerNode('max_relative_lifetime')
67
                        ->isRequired()
68
                        ->defaultValue(600)
69
                        ->info(
70
                            'The maximum relative lifetime of a session; the maximum allowed time between two '
71
                            . 'interactions by the user'
72
                        )
73
                        ->example('600 -> 10 minutes * 60 seconds')
74
                        ->validate()
75
                            ->ifTrue(
76
                                function ($lifetime) {
77
                                    return !is_int($lifetime);
78
                                }
79
                            )
80
                            ->thenInvalid('max_relative_lifetime must be an integer')
81
                        ->end()
82
                    ->end()
83
                ->end()
84
            ->end();
85
    }
86
87
    private function appendSecondFactorTestIdentityProvider(NodeBuilder $childNodes)
88
    {
89
        $childNodes
0 ignored issues
show
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...
90
            ->arrayNode('second_factor_test_identity_provider')
91
                ->isRequired()
92
                ->children()
93
                    ->scalarNode('entity_id')
94
                        ->isRequired()
95
                        ->info('The EntityID of the remote identity provider')
96
                    ->end()
97
                    ->scalarNode('sso_url')
98
                        ->isRequired()
99
                        ->info('The name of the route to generate the SSO URL')
100
                    ->end()
101
                    ->scalarNode('certificate')
102
                        ->info('The contents of the certificate used to sign the AuthnResponse with')
103
                    ->end()
104
                    ->scalarNode('certificate_file')
105
                        ->info('A file containing the certificate used to sign the AuthnResponse with')
106
                    ->end()
107
                ->end()
108
            ->end();
109
    }
110
111
    /**
112
     * @param NodeBuilder $childNodes
113
     */
114
    private function appendEnabledSecondFactorTypesConfiguration(NodeBuilder $childNodes)
115
    {
116
        $childNodes
117
            ->arrayNode('enabled_second_factors')
118
                ->isRequired()
119
                ->prototype('scalar')
120
                    ->validate()
121
                        ->ifTrue(
122
                            function ($type) {
123
                                try {
124
                                    new SecondFactorType($type);
125
                                } catch (InvalidArgumentException $e) {
126
                                    return true;
127
                                } catch (DomainException $e) {
128
                                    return true;
129
                                }
130
                            }
131
                        )
132
                        ->thenInvalid(
133
                            'Enabled second factor type "%s" is not one of the valid types. See SecondFactorType'
134
                        )
135
                    ->end()
136
                ->end()
137
            ->end();
138
    }
139
}
140