BaseFilter::parseAuthSourceConfig()   F
last analyzed

Complexity

Conditions 23
Paths 10562

Size

Total Lines 91
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 49
dl 0
loc 91
rs 0
c 0
b 0
f 0
cc 23
nc 10562
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This base LDAP filter class can be extended to enable real filter classes direct access
5
 * access to the authsource ldap config and connects to the ldap server.
6
 *
7
 * @package simplesamlphp/simplesamlphp-module-ldap
8
 */
9
10
declare(strict_types=1);
11
12
namespace SimpleSAML\Module\ldap\Auth\Process;
13
14
use SimpleSAML\{Auth, Configuration, Error, Logger};
15
use SimpleSAML\Module\ldap\ConnectorFactory;
16
use SimpleSAML\Module\ldap\ConnectorInterface;
17
18
abstract class BaseFilter extends Auth\ProcessingFilter
19
{
20
    /**
21
     * TODO: Support ldap:LDAPMulti, if possible
22
     *
23
     * @var string[]
24
     */
25
    protected static array $ldapsources = ['ldap:Ldap', 'authX509:X509userCert'];
26
27
    /**
28
     * List of attribute "alias's" linked to the real attribute
29
     * name. Used for abstraction / configuration of the LDAP
30
     * attribute names, which may change between dir service.
31
     *
32
     * @var array<mixed>
33
     */
34
    protected array $attribute_map;
35
36
    /**
37
     * The base DN of the LDAP connection. Used when searching the LDAP server.
38
     *
39
     * @var array<mixed>
40
     */
41
    protected array $searchBase;
42
43
    /**
44
     * The construct method will change the filter config into
45
     * a \SimpleSAML\Configuration object and store it here for
46
     * later use, if needed.
47
     *
48
     * @var \SimpleSAML\Configuration
49
     */
50
    protected Configuration $config;
51
52
    /**
53
     * Array of LDAP connection objects. Stored here to be accessed later during processing.
54
     *
55
     * @var \SimpleSAML\Module\ldap\ConnectorInterface
56
     */
57
    protected ConnectorInterface $connector;
58
59
    /**
60
     * The class "title" used in logging and exception messages.
61
     * This should be prepended to the beginning of the message.
62
     *
63
     * @var string
64
     */
65
    protected string $title = 'ldap:BaseFilter';
66
67
    /**
68
     * List of LDAP object types, used to determine the type of
69
     * object that a DN references.
70
     *
71
     * @var array<mixed>
72
     */
73
    protected array $type_map;
74
75
76
    /**
77
     * Checks the authsource, if defined, for configuration values
78
     * to the LDAP server. Then sets up the LDAP connection for the
79
     * instance/object and stores everything in class members.
80
     *
81
     * @throws \SimpleSAML\Error\Exception
82
     * @param array<mixed> &$config
83
     * @param mixed $reserved
84
     */
85
    public function __construct(array &$config, $reserved)
86
    {
87
        parent::__construct($config, $reserved);
88
89
        // Change the class $title to match it's true name
90
        // This way if the class is extended the proper name is used
91
        $classname = explode('_', get_class($this));
92
        $classname = end($classname);
93
        $this->title = 'ldap:' . $classname;
94
95
        // Log the construction
96
        Logger::debug(sprintf('%s : Creating and configuring the filter.', $this->title));
97
98
        // If an authsource was defined (an not empty string)...
99
        if (isset($config['authsource']) && $config['authsource'] !== '') {
100
            $authconfig = $this->parseAuthSourceConfig($config['authsource']);
101
102
            // Merge the authsource config with the filter config,
103
            // but have the filter config override the authsource config
104
            $config = array_merge($authconfig, $config);
105
106
            // Authsource complete
107
            Logger::debug(sprintf(
108
                '%s : Retrieved authsource [%s] configuration values: %s',
109
                $this->title,
110
                $config['authsource'],
111
                $this->varExport($authconfig),
112
            ));
113
        }
114
115
        // Convert the config array to a config class,
116
        // that way we can verify type and define defaults.
117
        // Store in the instance in-case needed later, by a child class.
118
        $this->config = Configuration::loadFromArray($config, 'ldap:AuthProcess');
119
120
        // Initialize the Ldap-object
121
        $this->connector = ConnectorFactory::fromAuthSource($config['authsource']);
122
123
        // Set all the filter values, setting defaults if needed
124
        $this->searchBase = $this->config->getOptionalArray('search.base', []);
125
126
        // Log the member values retrieved above
127
        Logger::debug(sprintf(
128
            '%s : Configuration values retrieved; BaseDN: %s',
129
            $this->title,
130
            $this->varExport($this->searchBase),
131
        ));
132
133
        // Setup the attribute map which will be used to search LDAP
134
        $this->attribute_map = [
135
            'dn'       => $this->config->getOptionalString('attribute.dn', 'distinguishedName'),
136
            'groups'   => $this->config->getOptionalString('attribute.groups', 'groups'),
137
            'member'   => $this->config->getOptionalString('attribute.member', 'member'),
138
            'memberOf' => $this->config->getOptionalString('attribute.memberOf', 'memberOf'),
139
            'name'     => $this->config->getOptionalString('attribute.groupname', 'name'),
140
            'return'   => $this->config->getOptionalString('attribute.return', 'distinguishedName'),
141
            'type'     => $this->config->getOptionalString('attribute.type', 'objectClass'),
142
            'username' => $this->config->getOptionalString('attribute.username', 'sAMAccountName'),
143
        ];
144
145
        // Log the attribute map
146
        Logger::debug(sprintf(
147
            '%s : Attribute map created: %s',
148
            $this->title,
149
            $this->varExport($this->attribute_map),
150
        ));
151
152
        // Setup the object type map which is used to determine a DNs' type
153
        $this->type_map = [
154
            'group' => $this->config->getOptionalString('type.group', 'group'),
155
            'user'  => $this->config->getOptionalString('type.user', 'user'),
156
        ];
157
158
        // Log the type map
159
        Logger::debug(sprintf(
160
            '%s : Type map created: %s',
161
            $this->title,
162
            $this->varExport($this->type_map),
163
        ));
164
    }
165
166
167
    /**
168
     * Parse authsource config
169
     *
170
     * @param string $as The name of the authsource
171
     * @return array<mixed>
172
     */
173
    private function parseAuthSourceConfig(string $as): array
174
    {
175
        // Log the authsource request
176
        Logger::debug(sprintf(
177
            '%s : Attempting to get configuration values from authsource [%s]',
178
            $this->title,
179
            $as,
180
        ));
181
182
        // Get the authsources file, which should contain the config
183
        $authsources = Configuration::getConfig('authsources.php');
184
185
        // Verify that the authsource config exists
186
        if (!$authsources->hasValue($as)) {
187
            throw new Error\Exception(sprintf(
188
                '%s : Authsource [%s] defined in filter parameters not found in authsources.php',
189
                $this->title,
190
                $as,
191
            ));
192
        }
193
194
        // Get just the specified authsource config values
195
        $authsource = $authsources->getArray($as);
196
197
        // Make sure it is an ldap source
198
        if (isset($authsource[0]) && !in_array($authsource[0], self::$ldapsources)) {
199
            throw new Error\Exception(sprintf(
200
                '%s : Authsource [%s] specified in filter parameters is not an ldap:LDAP type',
201
                $this->title,
202
                $as,
203
            ));
204
        }
205
206
        // Build the authsource config
207
        $authconfig = [];
208
        if (isset($authsource['connection_string'])) {
209
            $authconfig['connection_string'] = $authsource['connection_string'];
210
        }
211
        if (isset($authsource['encryption'])) {
212
            $authconfig['encryption'] = $authsource['encryption'];
213
        }
214
        if (isset($authsource['version'])) {
215
            $authconfig['version'] = $authsource['version'];
216
        }
217
        if (isset($authsource['timeout'])) {
218
            $authconfig['timeout'] = $authsource['timeout'];
219
        }
220
        if (isset($authsource['debug'])) {
221
            $authconfig['debug']      = $authsource['debug'];
222
        }
223
        if (isset($authsource['referrals'])) {
224
            $authconfig['referrals']  = $authsource['referrals'];
225
        }
226
227
        // only set when search.enabled = true
228
        if (isset($authsource['search.enable']) && ($authsource['search.enable'] === true)) {
229
            if (isset($authsource['search.base'])) {
230
                $authconfig['search.base'] = $authsource['search.base'];
231
            }
232
            if (isset($authsource['search.scope'])) {
233
                $authconfig['search.scope'] = $authsource['search.scope'];
234
            }
235
236
            if (isset($authsource['search.username'])) {
237
                $authconfig['search.username']   = $authsource['search.username'];
238
            }
239
            if (isset($authsource['search.password'])) {
240
                $authconfig['search.password']   = $authsource['search.password'];
241
            }
242
243
            // Only set the username attribute if the authsource specifies one attribute
244
            if (
245
                isset($authsource['search.attributes'])
246
                && is_array($authsource['search.attributes'])
247
                && count($authsource['search.attributes']) == 1
248
            ) {
249
                $authconfig['attribute.username'] = reset($authsource['search.attributes']);
250
            }
251
        }
252
253
        // only set when priv.read = true
254
        if (isset($authsource['priv.read']) && $authsource['priv.read']) {
255
            if (isset($authsource['priv.username'])) {
256
                $authconfig['priv.username'] = $authsource['priv.username'];
257
            }
258
            if (isset($authsource['priv.password'])) {
259
                $authconfig['priv.password'] = $authsource['priv.password'];
260
            }
261
        }
262
263
        return $authconfig;
264
    }
265
266
267
    /**
268
     * Local utility function to get details about a variable,
269
     * basically converting it to a string to be used in a log
270
     * message. The var_export() function returns several lines
271
     * so this will remove the new lines and trim each line.
272
     *
273
     * @param mixed $value
274
     * @return string
275
     */
276
    protected function varExport($value): string
277
    {
278
        if (is_array($value)) {
279
            // remove sensitive data
280
            foreach ($value as $key => &$val) {
281
                if ($key === 'search.password' || $key === 'priv.password') {
282
                    $val = empty($val) ? '' : '********';
283
                }
284
            }
285
            unset($val);
286
        }
287
288
        $export = var_export($value, true);
289
        $lines = explode("\n", $export);
290
        foreach ($lines as &$line) {
291
            $line = trim($line);
292
        }
293
        return implode(' ', $lines);
294
    }
295
}
296