Completed
Push — master ( c35dba...764289 )
by Christopher
06:12 queued 04:17
created

Connection::auth()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 2
1
<?php
2
/**
3
 * @link      https://github.com/chrmorandi/yii2-ldap for the canonical source repository
4
 * @package   yii2-ldap
5
 * @author    Christopher Mota <[email protected]>
6
 * @license   MIT License - view the LICENSE file that was distributed with this source code.
7
 */
8
9
namespace chrmorandi\ldap;
10
11
use yii\base\Component;
12
13
/**
14
 * @property resource $resource
15
 * @property boolean  $bount
16
 * @property int      $errNo Error number of the last command
17
 * @property string   $lastError Error message of the last command
18
 *
19
 * @author Christopher Mota <[email protected]>
20
 * @since 1.0
21
 */
22
class Connection extends Component
23
{
24
    /**
25
     * LDAP protocol string.
26
     * @var string
27
     */
28
    const PROTOCOL = 'ldap://';
29
30
    /**
31
     * LDAP port number.
32
     * @var string
33
     */
34
    const PORT = '389';
35
36
    /**
37
     * @event Event an event that is triggered after a DB connection is established
38
     */
39
    const EVENT_AFTER_OPEN = 'afterOpen';
40
41
    /**
42
     * @var string the LDAP base dn.
43
     */
44
    public $baseDn;
45
46
    /**
47
     * https://msdn.microsoft.com/en-us/library/ms677913(v=vs.85).aspx
48
     * @var bool the integer to instruct the LDAP connection whether or not to follow referrals.
49
     */
50
    public $followReferrals = false;
51
52
    /**
53
     * @var string The LDAP port to use when connecting to the domain controllers.
54
     */
55
    public $port = self::PORT;
56
57
    /**
58
     * @var bool Determines whether or not to use TLS with the current LDAP connection.
59
     */
60
    public $useTLS = true;
61
62
    /**
63
     * @var array the domain controllers to connect to.
64
     */
65
    public $dc = [];
66
    
67
    /**
68
     * @var string the username for establishing LDAP connection. Defaults to `null` meaning no username to use.
69
     */
70
    public $username;
71
72
    /**
73
     * @var string the password for establishing DB connection. Defaults to `null` meaning no password to use.
74
     */
75
    public $password;
76
    
77
    /**
78
     * @var int The page size for the paging operation.
79
     */
80
    public $pageSize = -1;
81
    
82
    /**
83
     * @var integer zero-based offset from where the records are to be returned. If not set or
84
     * less than 1, it means not filter values.
85
     */
86
    public $offset = -1;
87
    
88
    /**
89
     * @var boolean whether to enable caching.
90
     * Note that in order to enable truly caching, a valid cache component as specified
91
     * by [[cache]] must be enabled and [[enableCache]] must be set true.
92
     * @see cacheDuration
93
     * @see cache
94
     */
95
    public $enableCache = false;
96
    
97
    /**
98
     * @var integer number of seconds that table metadata can remain valid in cache.
99
     * Use 0 to indicate that the cached data will never expire.
100
     * @see enableCache
101
     */
102
    public $cacheDuration = 3600;
103
104
    /**
105
     * @var Cache|string the cache object or the ID of the cache application component that
106
     * is used to cache result query.
107
     * @see enableCache
108
     */
109
    public $cache = 'cache';
110
    
111
    /**
112
     * @var string the attribute for authentication
113
     */    
114
    public $loginAttribute = "sAMAccountName";
115
116
    /**
117
     * @var string the LDAP account suffix.
118
     */
119
    protected $accountSuffix;
120
121
    /**
122
     * @var string the LDAP account prefix.
123
     */
124
    protected $accountPrefix;
125
126
    /**
127
     * @var bool stores the bool whether or not the current connection is bound.
128
     */
129
    protected $_bound = false;
130
131
    /**
132
     * @var resource|false
133
     */
134
    protected $resource;
135
    
136
    
137
    # Create AD password (Microsoft Active Directory password format)
138
    protected static function makeAdPassword($password) {
139
        $password = "\"" . $password . "\"";
140
        $adpassword = mb_convert_encoding($password, "UTF-16LE", "UTF-8");
141
        return $adpassword;
142
    }
143
144
    /**
145
     * Connects and Binds to the Domain Controller with a administrator credentials.
146
     * @return void
147
     */
148
    protected function open($anonymous = false)
149
    {
150
        // Connect to the LDAP server.
151
        $this->connect($this->dc, $this->port);
152
153
        if ($anonymous) {               
154
            $this->_bound = ldap_bind($this->resource);
155
        } else {
156
            $this->_bound = ldap_bind($this->resource, $this->username, $this->password);
157
        }
158
    }
159
160
    /**
161
     * Connection.
162
     * @param string|array $hostname
163
     * @param type $port
164
     * @return void
165
     */
166
    public function connect($hostname = [], $port = '389')
167
    {
168
        if (is_array($hostname)) {
169
            $hostname = self::PROTOCOL.implode(' '.self::PROTOCOL, $hostname);
170
        }
171
        
172
        $this->close();
173
        $this->resource = ldap_connect($hostname, $port);
174
175
        // Set the LDAP options.     
176
        $this->setOption(LDAP_OPT_PROTOCOL_VERSION, 3);
177
        $this->setOption(LDAP_OPT_REFERRALS, $this->followReferrals);
178
        if ($this->useTLS) {
179
            $this->startTLS();
180
        }
181
182
        $this->trigger(self::EVENT_AFTER_OPEN);
183
    }
184
    
185
    /**
186
     * Authenticate user
187
     * @param string $username
188
     * @param string $password
189
     * @return int indicate occurrence of error. 
190
     */
191
    public function auth($username, $password)
192
    {
193
        // Open connection with manager
194
        $this->open();
195
        # Search for user and get user DN
196
        $searchResult = ldap_search($this->resource, $this->baseDn, "(&(objectClass=person)($this->loginAttribute=$username))", [$this->loginAttribute]);
197
        $entry = $this->getFirstEntry($searchResult);
198
        $userdn = $this->getDn($entry);        
199
        
200
        // Connect to the LDAP server.
201
        $this->connect($this->dc, $this->port);
202
        // Authenticate user
203
        $result = ldap_bind($this->resource, $userdn, $password);
204
        
205
        return $result;
206
    }
207
    
208
    /**
209
     * Closes the current connection.
210
     *
211
     * @return boolean
212
     */
213
    public function close()
214
    {
215
        if (is_resource($this->resource)) {
216
            ldap_close($this->resource);
217
        }
218
        return true;
219
    }
220
221
    /**
222
     * Execute ldap functions like.
223
     *
224
     * http://php.net/manual/en/ref.ldap.php
225
     *
226
     * @param  string $function php LDAP function
227
     * @param  array $params params for execute ldap function
228
     * @return bool|DataReader
229
     */
230
    public function executeQuery($function, $params)
231
    {
232
        $this->open();
233
        $results = [];
234
        $cookie = '';
235
        
236
        do {
237
            $this->setControlPagedResult($cookie);
238
239
            $result = call_user_func($function, $this->resource, ...$params);
240
241
            $this->setControlPagedResultResponse($result, $cookie);
242
            $results[] = $result;            
243
        } while ($cookie !== null && $cookie != '');        
244
245
        if($this->offset > 0){
246
            $results = $results[intval($this->offset/$this->pageSize -1)];
247
        }
248
        
249
        return new DataReader($this, $results);
250
    }
251
    
252
    /**
253
     * Returns true/false if the current connection is bound.
254
     * @return bool
255
     */
256
    public function getBound()
257
    {
258
        return $this->_bound;
259
    }
260
    
261
    /**
262
     * Get the current resource of connection.
263
     * @return resource
264
     */
265
    public function getResource()
266
    {
267
        return $this->resource;
268
    }
269
    
270
    /**
271
     * Sorts an AD search result by the specified attribute.
272
     * @param resource $result
273
     * @param string   $attribute
274
     * @return bool
275
     */
276
    public function sort($result, $attribute)
277
    {
278
        return ldap_sort($this->resource, $result, $attribute);
279
    }
280
281
    /**
282
     * Adds an entry to the current connection.
283
     * @param string $dn
284
     * @param array  $entry
285
     * @return bool
286
     */
287
    public function add($dn, array $entry)
288
    {
289
        return ldap_add($this->resource, $dn, $entry);
290
    }
291
292
    /**
293
     * Deletes an entry on the current connection.
294
     * @param string $dn
295
     * @return bool
296
     */
297
    public function delete($dn)
298
    {
299
        return ldap_delete($this->resource, $dn);
300
    }
301
302
    /**
303
     * Modify the name of an entry on the current connection.
304
     *
305
     * @param string $dn
306
     * @param string $newRdn
307
     * @param string $newParent
308
     * @param bool   $deleteOldRdn
309
     * @return bool
310
     */
311
    public function rename($dn, $newRdn, $newParent, $deleteOldRdn = false)
312
    {
313
        return ldap_rename($this->resource, $dn, $newRdn, $newParent, $deleteOldRdn);
314
    }
315
316
    /**
317
     * Batch modifies an existing entry on the current connection.
318
     * The types of modifications:
319
     *      LDAP_MODIFY_BATCH_ADD - Each value specified through values is added.
320
     *      LDAP_MODIFY_BATCH_REMOVE - Each value specified through values is removed. 
321
     *          Any value of the attribute not contained in the values array will remain untouched.
322
     *      LDAP_MODIFY_BATCH_REMOVE_ALL - All values are removed from the attribute named by attrib.
323
     *      LDAP_MODIFY_BATCH_REPLACE - All current values are replaced by new one.
324
     * @param string $dn
325
     * @param array  $values array associative with three keys: "attrib", "modtype" and "values".
326
     * ```php
327
     * [
328
     *     "attrib"  => "attribute",
329
     *     "modtype" => LDAP_MODIFY_BATCH_ADD,
330
     *     "values"  => ["attribute value one"],
331
     * ],
332
     * ```
333
     * @return mixed
334
     */
335
    public function modify($dn, array $values)
336
    {
337
        return ldap_modify_batch($this->resource, $dn, $values);
338
    }    
339
    
340
    /**
341
     * Retrieve the entries from a search result.
342
     * @param resource $searchResult
343
     * @return array|boolean
344
     */
345
    public function getEntries($searchResult)
346
    {
347
        return ldap_get_entries($this->resource, $searchResult);
348
    }
349
    
350
    /**
351
     * Retrieves the number of entries from a search result.
352
     * @param resource $searchResult
353
     * @return int
354
     */
355
    public function countEntries($searchResult)
356
    {
357
        return ldap_count_entries($this->resource, $searchResult);
358
    }
359
360
    /**
361
     * Retrieves the first entry from a search result.
362
     * @param resource $searchResult
363
     * @return resource link identifier
364
     */
365
    public function getFirstEntry($searchResult)
366
    {
367
        return ldap_first_entry($this->resource, $searchResult);
368
    }
369
370
    /**
371
     * Retrieves the next entry from a search result.
372
     * @param resource $entry link identifier
373
     * @return resource
374
     */
375
    public function getNextEntry($entry)
376
    {
377
        return ldap_next_entry($this->resource, $entry);
378
    }
379
    
380
    /**
381
     * Retrieves the ldap first entry attribute.
382
     * @param resource $entry
383
     * @return string
384
     */
385
    public function getFirstAttribute($entry)
386
    {
387
        return ldap_first_attribute($this->resource, $entry);
388
    }
389
    
390
    /**
391
     * Retrieves the ldap next entry attribute.
392
     * @param resource $entry
393
     * @return string
394
     */
395
    public function getNextAttribute($entry)
396
    {
397
        return ldap_next_attribute($this->resource, $entry);
398
    }
399
400
    /**
401
     * Retrieves the ldap entry's attributes.
402
     * @param resource $entry
403
     * @return array
404
     */
405
    public function getAttributes($entry)
406
    {
407
        return ldap_get_attributes($this->resource, $entry);
408
    }
409
    
410
    /**
411
     * Retrieves all binary values from a result entry.
412
     * @param resource $entry link identifier
413
     * @param string $attribute name of attribute
414
     * @return array
415
     */
416
    public function getValuesLen($entry, $attribute)
417
    {
418
        return ldap_get_values_len($this->resource, $entry, $attribute);
419
    }
420
    
421
    /**
422
     * Retrieves the DN of a result entry.
423
     * @param resource $entry
424
     * @return string
425
     */
426
    public function getDn($entry)
427
    {
428
        return ldap_get_dn($this->resource, $entry);
429
    }
430
431
    /**
432
     * Free result memory.
433
     * @param resource $searchResult
434
     * @return bool
435
     */
436
    public function freeResult($searchResult)
437
    {
438
        return ldap_free_result($searchResult);
439
    }
440
441
    /**
442
     * Sets an option on the current connection.
443
     * @param int   $option
444
     * @param mixed $value
445
     * @return boolean
446
     */
447
    public function setOption($option, $value)
448
    {
449
        return ldap_set_option($this->resource, $option, $value);
450
    }
451
452
    /**
453
     * Starts a connection using TLS.
454
     * @return bool
455
     */
456
    public function startTLS()
457
    {
458
        return ldap_start_tls($this->resource);
459
    }
460
    
461
    /**
462
     * Send LDAP pagination control.
463
     * @param int    $pageSize
0 ignored issues
show
Bug introduced by
There is no parameter named $pageSize. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
464
     * @param bool   $isCritical
0 ignored issues
show
Bug introduced by
There is no parameter named $isCritical. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
465
     * @param string $cookie
466
     * @return bool
467
     */
468
    public function setControlPagedResult($cookie)
469
    {
470
        return ldap_control_paged_result($this->resource, $this->pageSize, false, $cookie);
471
    }
472
473
    /**
474
     * Retrieve a paginated result response.
475
     * @param resource $result
476
     * @param string $cookie
477
     * @return bool
478
     */
479
    public function setControlPagedResultResponse($result, &$cookie)
480
    {
481
        return ldap_control_paged_result_response($this->resource, $result, $cookie);
482
    }
483
       
484
    /**
485
     * Retrieve the last error on the current connection.
486
     * @return string
487
     */
488
    public function getLastError()
489
    {
490
        return ldap_error($this->resource);
491
    }
492
    
493
    /**
494
     * Returns the number of the last error on the current connection.
495
     * @return int
496
     */
497
    public function getErrNo()
498
    {
499
        return ldap_errno($this->resource);
500
    }
501
502
    /**
503
     * Returns the error string of the specified error number.
504
     * @param int $number
505
     * @return string
506
     */
507
    public function err2Str($number)
508
    {
509
        return ldap_err2str($number);
510
    }
511
}
512