Passed
Pull Request — master (#16)
by Tim
03:07
created

AttributeAddFromLDAP::process()   D

Complexity

Conditions 18
Paths 129

Size

Total Lines 89
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 18
eloc 53
c 1
b 0
f 0
nc 129
nop 1
dl 0
loc 89
rs 4.625

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
 * Filter to add attributes to the identity by executing a query against an LDAP directory
5
 *
6
 * @package simplesamlphp/simplesamlphp-module-ldap
7
 */
8
9
declare(strict_types=1);
10
11
namespace SimpleSAML\Module\ldap\Auth\Process;
12
13
use Exception;
14
use SimpleSAML\Assert\Assert;
15
use SimpleSAML\Logger;
16
use Symfony\Component\Ldap\Adapter\ExtLdap\Query;
17
18
class AttributeAddFromLDAP extends BaseFilter
19
{
20
    /**
21
     * LDAP attributes to add to the request attributes
22
     *
23
     * @var array
24
     */
25
    protected array $searchAttributes;
26
27
    /**
28
     * LDAP attributes to base64 encode
29
     *
30
     * @var array
31
     */
32
    protected array $binaryAttributes;
33
34
    /**
35
     * LDAP search filter to use in the LDAP query
36
     *
37
     * @var string
38
     */
39
    protected string $searchFilter;
40
41
    /**
42
     * What to do with attributes when the target already exists. Either replace, merge or add.
43
     *
44
     * @var string
45
     */
46
    protected string $attrPolicy;
47
48
    /** @var string */
49
    protected string $searchUsername;
50
51
    /** @var string */
52
    protected string $searchPassword;
53
54
    /**
55
     * Initialize this filter.
56
     *
57
     * @param array $config Configuration information about this filter.
58
     * @param mixed $reserved For future use.
59
     */
60
    public function __construct(array $config, $reserved)
61
    {
62
        parent::__construct($config, $reserved);
63
64
        // Get filter specific config options
65
        $this->binaryAttributes = $this->config->getOptionalArray('attributes.binary', []);
66
        $this->searchAttributes = $this->config->getOptionalArrayize('attributes', []);
67
        if (empty($this->searchAttributes)) {
68
            $new_attribute = $this->config->getString('attribute.new');
69
            $this->searchAttributes[$new_attribute] = $this->config->getString('search.attribute');
70
        }
71
        $this->searchFilter = $this->config->getString('search.filter');
72
73
        // get the attribute policy
74
        $this->attrPolicy = $this->config->getOptionalString('attribute.policy', 'merge');
75
        Assert::oneOf($this->attrPolicy, ['merge', 'replace', 'add']);
76
77
        $this->searchUsername = $this->config->getString('search.username');
78
        $this->searchPassword = $this->config->getOptionalString('search.password', null);
79
    }
80
81
82
    /**
83
     * Add attributes from an LDAP server.
84
     *
85
     * @param array &$state The current request
86
     */
87
    public function process(array &$state): void
88
    {
89
        Assert::keyExists($state, 'Attributes');
90
        $attributes = &$state['Attributes'];
91
92
        // perform a merge on the ldap_search_filter
93
        // loop over the attributes and build the search and replace arrays
94
        $arrSearch = $arrReplace = [];
95
        foreach ($attributes as $attr => $val) {
96
            $arrSearch[] = '%' . $attr . '%';
97
98
            if (is_array($val) && count($val) > 0 && strlen($val[0]) > 0) {
99
                $arrReplace[] = $this->connector->escapeFilterValue($val[0], true);
0 ignored issues
show
Bug introduced by
The method escapeFilterValue() does not exist on SimpleSAML\Module\ldap\ConnectorInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to SimpleSAML\Module\ldap\ConnectorInterface. ( Ignorable by Annotation )

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

99
                /** @scrutinizer ignore-call */ 
100
                $arrReplace[] = $this->connector->escapeFilterValue($val[0], true);
Loading history...
100
            } else {
101
                $arrReplace[] = '';
102
            }
103
        }
104
105
        // merge the attributes into the ldap_search_filter
106
        /** @psalm-var string[] $arrReplace */
107
        $filter = str_replace($arrSearch, $arrReplace, $this->searchFilter);
108
        if (strpos($filter, '%') !== false) {
109
            Logger::info(sprintf(
110
                '%s: There are non-existing attributes in the search filter. (%s)',
111
                $this->title,
112
                $filter
113
            ));
114
            return;
115
        }
116
117
        $this->connector->bind($this->searchUsername, $this->searchPassword);
118
119
        $options = [
120
            'scope' => $this->config->getOptionalString('search.scope', Query::SCOPE_SUB),
121
            'timeout' => $this->config->getOptionalInteger('timeout', 3),
122
        ];
123
124
        $entries = $this->connector->searchForMultiple(
125
            $this->searchBase,
126
            $filter,
127
            $options,
128
            true
129
        );
130
131
        $results = [];
132
        foreach ($entries as $entry) {
133
            $tmp = array_intersect_key(
134
                $entry->getAttributes(),
135
                array_fill_keys(array_values($this->searchAttributes), null)
136
            );
137
138
            $binaries = array_intersect(
139
                array_keys($tmp),
140
                $this->binaryAttributes,
141
            );
142
            foreach ($binaries as $binary) {
143
                /** @psalm-var array $attr */
144
                $attr = $entry->getAttribute($binary);
145
                $tmp[$binary] = array_map('base64_encode', $attr);
0 ignored issues
show
Bug introduced by
It seems like $attr can also be of type null; however, parameter $array of array_map() 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

145
                $tmp[$binary] = array_map('base64_encode', /** @scrutinizer ignore-type */ $attr);
Loading history...
146
            }
147
148
            $results[] = $tmp;
149
        }
150
151
        // handle [multiple] values
152
        foreach ($results as $result) {
153
            foreach ($this->searchAttributes as $target => $name) {
154
                // If there is no mapping defined, just use the name of the LDAP-attribute as a target
155
                if (is_int($target)) {
156
                    $target = $name;
157
                }
158
159
                if (isset($attributes[$target]) && $this->attrPolicy === 'replace') {
160
                    unset($attributes[$target]);
161
                }
162
163
                if (isset($result[$name])) {
164
                    if (isset($attributes[$target])) {
165
                        foreach (array_values($result[$name]) as $value) {
166
                            if ($this->attrPolicy === 'merge') {
167
                                if (!in_array($value, $attributes[$target], true)) {
168
                                    $attributes[$target][] = $value;
169
                                }
170
                            } else {
171
                                $attributes[$target][] = $value;
172
                            }
173
                        }
174
                    } else {
175
                        $attributes[$target] = array_values($result[$name]);
176
                    }
177
                }
178
            }
179
        }
180
    }
181
}
182