Passed
Push — master ( a717b5...dd05c8 )
by Florian
03:07 queued 01:19
created

LdapIdentifier::handleLdapError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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