Ldap   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 75
c 0
b 0
f 0
dl 0
loc 149
rs 10
wmc 13

3 Methods

Rating   Name   Duplication   Size   Complexity  
B invokeTest() 0 72 7
A prepareConnection() 0 27 5
A __construct() 0 17 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\monitor\TestSuite\AuthSource;
6
7
use SimpleSAML\Assert\Assert;
8
use SimpleSAML\Configuration;
9
use SimpleSAML\Module\monitor\State;
10
use SimpleSAML\Module\monitor\TestConfiguration;
11
use SimpleSAML\Module\monitor\TestCase;
12
use SimpleSAML\Module\monitor\TestData;
13
use SimpleSAML\Module\monitor\TestResult;
14
15
use function array_key_exists;
16
use function array_replace;
17
use function explode;
18
use function is_null;
19
use function parse_url;
20
use function preg_match;
21
use function preg_split;
22
use function stream_context_create;
23
24
final class Ldap extends \SimpleSAML\Module\monitor\TestSuiteFactory
25
{
26
    /** @var \SimpleSAML\Configuration */
27
    private Configuration $authSourceData;
28
29
    /** @var array|null */
30
    private ?array $authSourceSpecifics;
31
32
    /** @var string[] */
33
    private array $hosts;
34
35
    /** @var integer|null */
36
    private ?int $certExpirationWarning = null;
37
38
39
    /**
40
     * @param \SimpleSAML\Module\monitor\TestConfiguration $configuration
41
     * @param \SimpleSAML\Module\monitor\TestData $testData
42
     */
43
    public function __construct(TestConfiguration $configuration, TestData $testData)
44
    {
45
        $moduleConfig = $configuration->getModuleConfig();
46
        $authSourceData = $testData->getInputItem('authSourceData');
47
        $authSourceSpecifics = $testData->getInputItem('authSourceSpecifics');
48
49
        Assert::isArray($authSourceData);
50
        Assert::nullOrIsArray($authSourceSpecifics);
51
52
        $authSourceData = Configuration::loadFromArray($authSourceData);
0 ignored issues
show
Bug introduced by
It seems like $authSourceData can also be of type null; however, parameter $config of SimpleSAML\Configuration::loadFromArray() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

52
        $authSourceData = Configuration::loadFromArray(/** @scrutinizer ignore-type */ $authSourceData);
Loading history...
53
        $this->hosts = preg_split('/\s+/', $authSourceData->getString('connection_string'), -1, PREG_SPLIT_NO_EMPTY);
54
        $this->authSourceData = $authSourceData;
55
        $this->authSourceSpecifics = $authSourceSpecifics;
56
        $this->certExpirationWarning = $moduleConfig->getOptionalValue('certExpirationWarning', 28);
57
        $this->setCategory('LDAP authentication source');
58
59
        parent::__construct($configuration);
60
    }
61
62
63
    /**
64
     * @return void
65
     */
66
    public function invokeTest(): void
67
    {
68
        // Test LDAP configuration
69
        $confTest = new TestCase\AuthSource\Ldap\Configuration(
70
            new TestData(['authSourceData' => $this->authSourceData])
71
        );
72
        $confTestResult = $confTest->getTestResult();
73
        $this->addTestResult($confTestResult);
74
75
        if ($confTestResult->getState() === State::OK) {
76
            $connection = $confTestResult->getOutput('connection');
77
78
            // Test connection for each configured LDAP-server
79
            $failure = count($this->hosts);
80
            foreach ($this->hosts as $hostname) {
81
                $preparedTestData = $this->prepareConnection($hostname);
82
                $connTest = new TestCase\Network\ConnectUri(
83
                    new TestData($preparedTestData)
84
                );
85
                $connTestResult = $connTest->getTestResult();
86
                $this->addTestResult($connTestResult);
87
88
                if ($connTestResult->getState() === State::OK) {
89
                    $certData = $connTestResult->getOutput('certData');
90
91
                    // Test certificate when available
92
                    if ($certData !== null) {
93
                        $certTest = new TestCase\Cert(
94
                            new TestData([
95
                                'certData' => $certData,
96
                                'category' => 'LDAP Server Certificate',
97
                                'certExpirationWarning' => $this->certExpirationWarning,
98
                            ])
99
                        );
100
                        $certTestResult = $certTest->getTestResult();
101
                        $this->addTestResult($certTestResult);
102
                    }
103
                    $failure--;
104
                }
105
            }
106
107
            if ($failure === 0) {
108
                // Test bind
109
                $bindTest = new TestCase\AuthSource\Ldap\Bind(
110
                    new TestData([
111
                        'authSourceData' => $this->authSourceData,
112
                        'connection' => $connection
113
                    ])
114
                );
115
                $bindTestResult = $bindTest->getTestResult();
116
                $this->addTestResult($bindTestResult);
117
118
                if ($bindTestResult->getState() === State::OK) {
119
                    // Test search
120
                    $searchTest = new TestCase\AuthSource\Ldap\Search(
121
                        new TestData([
122
                            'authSourceData' => $this->authSourceData,
123
                            'connection' => $connection
124
                        ])
125
                    );
126
                    $searchTestResult = $searchTest->getTestResult();
127
                    $this->addTestResult($searchTestResult);
128
                }
129
            }
130
            unset($connection);
131
        }
132
133
        $state = $this->calculateState();
134
135
        $testResult = new TestResult('LDAP Authentication');
136
        $testResult->setState($state);
137
        $this->setTestResult($testResult);
138
    }
139
140
141
    /**
142
     * @param string $connectString
143
     *
144
     * @return array
145
     */
146
    private function prepareConnection(string $connectString): array
147
    {
148
        $hostname = parse_url($connectString, PHP_URL_HOST);
149
        $authSourceData = $this->authSourceData;
0 ignored issues
show
Unused Code introduced by
The assignment to $authSourceData is dead and can be removed.
Loading history...
150
        $authSourceSpecifics = $this->authSourceSpecifics;
151
152
        if (preg_match('/^(ldaps:\/\/(.*))$/', $connectString, $matches)) {
153
            // The default context
154
            $sslContext = ['capture_peer_cert' => true, 'verify_peer' => true];
155
156
            // The non-default context, if configured ...
157
            if (!is_null($authSourceSpecifics) && array_key_exists('ssl', $authSourceSpecifics)) {
158
                $sslContext = array_replace($sslContext, $authSourceSpecifics['ssl']);
159
            }
160
161
            $port = parse_url($connectString, PHP_URL_PORT);
162
            $port = $port ?: 636;
163
164
            $uri = 'ssl://' .  $hostname . ':' . $port;
165
            $context = stream_context_create(['ssl' => $sslContext]);
166
        } else {
167
            $port = 389;
168
            $uri = 'tcp://' . $hostname . ':' . $port;
169
            $context = stream_context_create();
170
        }
171
172
        return ['uri' => $uri, 'context' => $context, 'timeout' => 3];
173
    }
174
}
175