LdapIdentifier::bindUser()   A
last analyzed

Complexity

Conditions 3
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 11
c 0
b 0
f 0
dl 0
loc 18
ccs 6
cts 6
cp 1
rs 9.9
cc 3
nc 5
nop 2
crap 3
1
<?php
2
3
/**
4
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
5
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
6
 *
7
 * Licensed under The MIT License
8
 * For full copyright and license information, please see the LICENSE.txt
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
12
 * @link          https://cakephp.org CakePHP(tm) Project
13
 * @since         1.0.0
14
 * @license       https://opensource.org/licenses/mit-license.php MIT License
15
 */
16
17
declare(strict_types=1);
18
19
namespace Phauthentic\Authentication\Identifier;
20
21
use ArrayAccess;
22
use ArrayObject;
23
use Phauthentic\Authentication\Identifier\Ldap\AdapterInterface;
24
use ErrorException;
25
26
/**
27
 * LDAP Identifier
28
 *
29
 * Identifies authentication credentials using LDAP.
30
 *
31
 * ```
32
 *  $identifier = (new LadapIdentifier($ldapAdapter, 'ldap.example.com', function($username) {
33
 *         return $username; //transform into a rdn or dn
34
 *     })
35
 *      ->setOptions([
36
 *         LDAP_OPT_PROTOCOL_VERSION => 3
37
 *     ]);
38
 * ```
39
 *
40
 * @link https://github.com/QueenCityCodeFactory/LDAP
41
 */
42
class LdapIdentifier extends AbstractIdentifier
43
{
44
    /**
45
     * Credential fields
46
     *
47
     * @var array<string, string>
48
     */
49
    protected array $credentialFields = [
50
        self::CREDENTIAL_USERNAME => 'username',
51
        self::CREDENTIAL_PASSWORD => 'password'
52
    ];
53
54
    /**
55
     * Host
56
     *
57
     * @var string
58
     */
59
    protected string $host = '';
60
61
    /**
62
     * Bind DN
63
     *
64
     * @var callable
65
     */
66
    protected $bindDN;
67
68
    /**
69
     * Port
70
     *
71
     * @var int
72
     */
73
    protected int $port = 389;
74
75
    /**
76
     * Adapter Options
77
     *
78
     * @var array<int, bool|int|string>
79
     */
80
    protected array $ldapOptions = [];
81
82
    /**
83
     * List of errors
84
     *
85
     * @var array<int, string>
86
     */
87
    protected array $errors = [];
88
89
    /**
90
     * LDAP connection object
91
     *
92
     * @var \Phauthentic\Authentication\Identifier\Ldap\AdapterInterface
93
     */
94
    protected AdapterInterface $ldap;
95
96 16
    /**
97
     * {}
98 16
     * @param \Phauthentic\Authentication\Identifier\Ldap\AdapterInterface $ldapAdapter
99 16
     * @param string $host
100 16
     * @param callable $bindDN
101 16
     * @param int $port
102 16
     */
103
    public function __construct(AdapterInterface $ldapAdapter, string $host, callable $bindDN, int $port = 389)
104
    {
105
        $this->ldap = $ldapAdapter;
106
        $this->bindDN = $bindDN;
107
        $this->host = $host;
108
        $this->port = $port;
109
    }
110
111
    /**
112
     * Set the fields used to to get the credentials from
113
     *
114
     * @param string $username Username field
115
     * @param string $password Password field
116
     * @return $this
117
     */
118
    public function setCredentialFields(string $username, string $password): self
119
    {
120
        $this->credentialFields[self::CREDENTIAL_USERNAME] = $username;
121
        $this->credentialFields[self::CREDENTIAL_PASSWORD] = $password;
122
123
        return $this;
124
    }
125 4
126
    /**
127 4
     * Sets LDAP options
128
     *
129 4
     * @param array<int, bool|int|string> $options LDAP Options array
130
     * @return $this
131
     */
132
    public function setLdapOptions(array $options): self
133
    {
134
        $this->ldapOptions = $options;
135 12
136
        return $this;
137 12
    }
138 12
139
    /**
140 12
     * {@inheritDoc}
141 12
     */
142
    public function identify(array $data): ?ArrayAccess
143
    {
144 4
        $this->connectLdap();
145
        $fields = $this->credentialFields;
146
147
        if (isset($data[$fields[self::CREDENTIAL_USERNAME]]) && isset($data[$fields[self::CREDENTIAL_PASSWORD]])) {
148
            return $this->bindUser($data[$fields[self::CREDENTIAL_USERNAME]], $data[$fields[self::CREDENTIAL_PASSWORD]]);
149
        }
150
151
        return null;
152 4
    }
153
154 4
    /**
155
     * Returns configured LDAP adapter.
156
     *
157
     * @return \Phauthentic\Authentication\Identifier\Ldap\AdapterInterface
158
     */
159
    public function getAdapter(): AdapterInterface
160
    {
161
        return $this->ldap;
162 12
    }
163
164 12
    /**
165 12
     * Initializes the LDAP connection
166 12
     *
167 12
     * @return void
168
     */
169 12
    protected function connectLdap()
170
    {
171
        $this->ldap->connect(
172
            $this->host,
173
            $this->port,
174
            $this->ldapOptions
175
        );
176
    }
177
178 12
    /**
179
     * Try to bind the given user to the LDAP server
180
     *
181 12
     * @param string $username The username
182 12
     * @param string $password The password
183 8
     * @return \ArrayAccess|null
184 4
     */
185
    protected function bindUser($username, $password)
186 4
    {
187 8
        try {
188
            $callable = $this->bindDN;
189
            $ldapBind = $this->ldap->bind($callable($username), $password);
190 4
            if ($ldapBind === true) {
191 4
                $this->ldap->unbind();
192
193 8
                return new ArrayObject([
194
                    $this->credentialFields[self::CREDENTIAL_USERNAME] => $username
195 8
                ]);
196
            }
197
        } catch (ErrorException $e) {
198
            $this->handleLdapError($e->getMessage());
199
        }
200
        $this->ldap->unbind();
201
202
        return null;
203
    }
204 4
205
    /**
206 4
     * Handles an LDAP error
207 4
     *
208 4
     * @param string $message Exception message
209
     * @return void
210 4
     */
211 4
    protected function handleLdapError($message)
212
    {
213
        $extendedError = $this->ldap->getDiagnosticMessage();
214
        if (!is_null($extendedError)) {
215
            $this->errors[] = $extendedError;
216
        }
217
        $this->errors[] = $message;
218
    }
219
}
220