Passed
Pull Request — master (#62)
by
unknown
05:35
created

Ldap::whoami()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\ldap\Connector;
6
7
use SimpleSAML\Assert\Assert;
8
use SimpleSAML\Error;
9
use SimpleSAML\Logger;
10
use SimpleSAML\Module\ldap\ConnectorInterface;
11
use Symfony\Component\Ldap\Adapter\AdapterInterface;
12
use Symfony\Component\Ldap\Adapter\ExtLdap\Adapter;
13
use Symfony\Component\Ldap\Entry;
14
use Symfony\Component\Ldap\Exception\InvalidCredentialsException;
15
use Symfony\Component\Ldap\Exception\LdapException;
16
use Symfony\Component\Ldap\Ldap as LdapObject;
17
18
use function array_merge;
19
use function array_pop;
20
use function explode;
21
use function implode;
22
use function ini_get;
23
use function sprintf;
24
use function var_export;
25
26
class Ldap implements ConnectorInterface
27
{
28
    use LdapHelpers;
29
30
    /**
31
     * @var \Symfony\Component\Ldap\Adapter\AdapterInterface
32
     */
33
    protected AdapterInterface $adapter;
34
35
    /**
36
     * @var \Symfony\Component\Ldap\Ldap
37
     */
38
    protected LdapObject $connection;
39
40
41
    /**
42
     * @param string $connection_strings
43
     * @param string $encryption
44
     * @param int $version
45
     * @param string $extension
46
     * @param bool $debug
47
     * @param array $options
48
     */
49
    public function __construct(
50
        string $connection_strings,
51
        string $encryption = 'ssl',
52
        int $version = 3,
53
        string $extension = 'ext_ldap',
0 ignored issues
show
Unused Code introduced by
The parameter $extension is not used and could be removed. ( Ignorable by Annotation )

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

53
        /** @scrutinizer ignore-unused */ string $extension = 'ext_ldap',

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
54
        bool $debug = false,
55
        array $options = ['referrals' => false, 'network_timeout' => 3],
56
    ) {
57
        foreach (explode(' ', $connection_strings) as $connection_string) {
58
            Assert::regex($connection_string, '#^ldap[s]?:\/\/#');
59
        }
60
61
        Logger::debug(sprintf(
62
            "Setting up LDAP connection: host='%s', encryption=%s, version=%d, debug=%s, timeout=%d, referrals=%s.",
63
            $connection_strings,
64
            $encryption,
65
            $version,
66
            var_export($debug, true),
67
            $options['timeout'] ?? ini_get('default_socket_timeout'),
68
            var_export($options['referrals'] ?? false, true),
69
        ));
70
71
        $this->adapter = new Adapter(
72
            [
73
                'connection_string' => $connection_strings,
74
                'encryption'        => $encryption,
75
                'version'           => $version,
76
                'debug'             => $debug,
77
                'options'           => $options,
78
            ],
79
        );
80
81
        $this->connection = new LdapObject($this->adapter);
82
    }
83
84
85
    /**
86
     * @return \Symfony\Component\Ldap\Adapter\AdapterInterface
87
     */
88
    public function getAdapter(): AdapterInterface
89
    {
90
        return $this->adapter;
91
    }
92
93
94
    /**
95
     * @inheritDoc
96
     */
97
    public function bind(?string $username, #[\SensitiveParameter]?string $password): void
98
    {
99
        try {
100
            $this->connection->bind($username, strval($password));
101
        } catch (InvalidCredentialsException $e) {
102
            throw new Error\Error($this->resolveBindError($e));
103
        }
104
105
        if ($username === null) {
106
            Logger::debug("LDAP bind(): Anonymous bind succesful.");
107
        } else {
108
            Logger::debug(sprintf("LDAP bind(): Bind successful for DN '%s'.", $username));
109
        }
110
    }
111
112
    /**
113
     * @inheritDoc
114
     */
115
    public function saslBind(?string $username, #[\SensitiveParameter]?string $password, ?string $mech, ?string $realm, ?string $authcId, ?string $authzId, ?string $props): void
116
117
    {
118
        if (!method_exists($this->connection, 'saslBind'))
119
            throw new Error\Error("SASL not implemented");
120
121
        try {
122
            $this->connection->saslBind($username, strval($password), $mech, $realm, $authcId, $authzId, $props);
0 ignored issues
show
Bug introduced by
The method saslBind() does not exist on Symfony\Component\Ldap\Ldap. ( Ignorable by Annotation )

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

122
            $this->connection->/** @scrutinizer ignore-call */ 
123
                               saslBind($username, strval($password), $mech, $realm, $authcId, $authzId, $props);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
123
        } catch (InvalidCredentialsException $e) {
124
            throw new Error\Error($this->resolveBindError($e));
125
        }
126
127
        if ($username === null) {
128
            Logger::debug("LDAP bind(): Anonymous bind succesful.");
129
        } else {
130
            Logger::debug(sprintf("LDAP bind(): Bind successful for DN '%s'.", $username));
131
        }
132
    }
133
134
    /**
135
     * @inheritDoc
136
     */
137
    public function whoami(): string
138
    {
139
        if (!method_exists($this->connection, 'whoami'))
140
            throw new Error\Error("SASL not implemented");
141
142
        return $this->connection->whoami();
0 ignored issues
show
Bug introduced by
The method whoami() does not exist on Symfony\Component\Ldap\Ldap. ( Ignorable by Annotation )

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

142
        return $this->connection->/** @scrutinizer ignore-call */ whoami();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
143
    }
144
145
    /**
146
     * @inheritDoc
147
     */
148
    public function search(
149
        array $searchBase,
150
        string $filter,
151
        array $options,
152
        bool $allowMissing,
153
    ): ?Entry {
154
        $entry = null;
155
156
        foreach ($searchBase as $base) {
157
            $query  = $this->connection->query($base, $filter, $options);
158
            $result = $query->execute()->toArray();
159
160
            if (count($result) > 1) {
161
                throw new Error\Exception(sprintf(
162
                    "LDAP search(): Found %d entries searching base '%s' for '%s'",
163
                    count($result),
164
                    $base,
165
                    $filter,
166
                ));
167
            } elseif (count($result) === 1) {
168
                $entry = array_pop($result);
169
                break;
170
            } else {
171
                Logger::debug(sprintf(
172
                    "LDAP search(): Found no entries searching base '%s' for '%s'",
173
                    $base,
174
                    $filter,
175
                ));
176
            }
177
        }
178
179
        if ($entry === null && $allowMissing === false) {
180
            throw new Error\Exception(sprintf(
181
                "Object not found using search base [%s] and filter '%s'",
182
                implode(', ', $searchBase),
183
                $filter,
184
            ));
185
        }
186
187
        return $entry;
188
    }
189
190
191
    /**
192
     * @inheritDoc
193
     */
194
    public function searchForMultiple(
195
        array $searchBase,
196
        string $filter,
197
        array $options,
198
        bool $allowMissing,
199
    ): array {
200
        $results = [];
201
202
        foreach ($searchBase as $base) {
203
            $query   = $this->connection->query($base, $filter, $options);
204
            $result  = $query->execute()->toArray();
205
            $results = array_merge($results, $result);
206
207
            Logger::debug(sprintf(
208
                "Library - LDAP search(): Found %d entries searching base '%s' for '%s'",
209
                count($result),
210
                $base,
211
                $filter,
212
            ));
213
        }
214
215
        if (empty($results) && ($allowMissing === false)) {
216
            throw new Error\Exception(sprintf(
217
                "No Objects found using search base [%s] and filter '%s'",
218
                implode(', ', $searchBase),
219
                $filter,
220
            ));
221
        }
222
223
        return $results;
224
    }
225
226
227
    /**
228
     * Resolve the message to a UI exception
229
     *
230
     * @param InvalidCredentialsException $e
231
     * @return string
232
     */
233
    protected function resolveBindError(InvalidCredentialsException $e): string
0 ignored issues
show
Unused Code introduced by
The parameter $e is not used and could be removed. ( Ignorable by Annotation )

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

233
    protected function resolveBindError(/** @scrutinizer ignore-unused */ InvalidCredentialsException $e): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
234
    {
235
        return self::ERR_WRONG_PASS;
236
    }
237
238
239
    /**
240
     * @param \Symfony\Component\Ldap\Entry $entry
241
     * @return bool
242
     */
243
    public function updateEntry(Entry $entry): bool
244
    {
245
        try {
246
            $this->adapter->getEntryManager()->update($entry);
247
            return true;
248
        } catch (LdapException $e) {
249
            Logger::warning($e->getMessage());
250
            return false;
251
        }
252
    }
253
}
254