|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace DoL\LdapBundle\Driver; |
|
4
|
|
|
|
|
5
|
|
|
use Zend\Ldap\Ldap; |
|
6
|
|
|
use Zend\Ldap\Exception\LdapException as ZendLdapException; |
|
7
|
|
|
use DoL\LdapBundle\Model\LdapUserInterface; |
|
8
|
|
|
use Psr\Log\LoggerInterface; |
|
9
|
|
|
use Symfony\Component\Security\Core\User\UserInterface; |
|
10
|
|
|
|
|
11
|
|
|
/** |
|
12
|
|
|
* This class adapt ldap calls to Zend Framework Ldap library functions. |
|
13
|
|
|
* Also prevent information disclosure catching Zend Ldap Exceptions and passing |
|
14
|
|
|
* them to the logger. |
|
15
|
|
|
* |
|
16
|
|
|
* @since v2.0.0 |
|
17
|
|
|
* |
|
18
|
|
|
* @author DarwinOnLine |
|
19
|
|
|
* @author Maks3w |
|
20
|
|
|
* |
|
21
|
|
|
* @see https://github.com/DarwinOnLine/DoLLdapBundle |
|
22
|
|
|
*/ |
|
23
|
|
|
class ZendLdapDriver implements LdapDriverInterface |
|
24
|
|
|
{ |
|
25
|
|
|
/** |
|
26
|
|
|
* @var Ldap |
|
27
|
|
|
*/ |
|
28
|
|
|
private $driver; |
|
29
|
|
|
|
|
30
|
|
|
/** |
|
31
|
|
|
* @var LoggerInterface |
|
32
|
|
|
*/ |
|
33
|
|
|
private $logger; |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* @param Ldap $driver Initialized Zend::Ldap Object |
|
37
|
|
|
* @param LoggerInterface $logger optional logger for write debug messages |
|
38
|
|
|
*/ |
|
39
|
8 |
|
public function __construct(Ldap $driver, LoggerInterface $logger = null) |
|
40
|
|
|
{ |
|
41
|
8 |
|
$this->driver = $driver; |
|
42
|
8 |
|
$this->logger = $logger; |
|
43
|
8 |
|
} |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* {@inheritdoc} |
|
47
|
|
|
*/ |
|
48
|
|
|
public function init(array $options) |
|
49
|
|
|
{ |
|
50
|
|
|
$this->driver->disconnect()->setOptions($options); |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* {@inheritdoc} |
|
55
|
|
|
*/ |
|
56
|
1 |
|
public function search($baseDn, $filter, array $attributes = array()) |
|
57
|
|
|
{ |
|
58
|
1 |
|
$this->logDebug('{action}({base_dn}, {filter}, {attributes})', [ |
|
59
|
1 |
|
'action' => 'ldap_search', |
|
60
|
1 |
|
'base_dn' => $baseDn, |
|
61
|
1 |
|
'filter' => $filter, |
|
62
|
1 |
|
'attributes' => $attributes, |
|
63
|
1 |
|
]); |
|
64
|
|
|
|
|
65
|
|
|
try { |
|
66
|
1 |
|
$entries = $this->driver->searchEntries($filter, $baseDn, Ldap::SEARCH_SCOPE_SUB, $attributes); |
|
67
|
|
|
// searchEntries don't return 'count' key as specified by php native |
|
68
|
|
|
// function ldap_get_entries() |
|
|
|
|
|
|
69
|
1 |
|
$entries['count'] = count($entries); |
|
70
|
1 |
|
} catch (ZendLdapException $exception) { |
|
71
|
|
|
$this->zendExceptionHandler($exception); |
|
72
|
|
|
|
|
73
|
|
|
throw new LdapDriverException('An error occur with the search operation.'); |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
1 |
|
return $entries; |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
/** |
|
80
|
|
|
* {@inheritdoc} |
|
81
|
|
|
*/ |
|
82
|
6 |
|
public function bind(UserInterface $user, $password) |
|
83
|
|
|
{ |
|
84
|
6 |
|
if ($user instanceof LdapUserInterface && $user->getDn()) { |
|
85
|
3 |
|
$bind_rdn = $user->getDn(); |
|
86
|
3 |
|
} else { |
|
87
|
3 |
|
$bind_rdn = $user->getUsername(); |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
try { |
|
91
|
6 |
|
$this->logDebug('{action}({bind_rdn}, ****)', [ |
|
92
|
6 |
|
'action' => 'ldap_bind', |
|
93
|
6 |
|
'bind_rdn' => $bind_rdn, |
|
94
|
6 |
|
]); |
|
95
|
6 |
|
$bind = $this->driver->bind($bind_rdn, $password); |
|
96
|
|
|
|
|
97
|
2 |
|
return $bind instanceof Ldap; |
|
98
|
4 |
|
} catch (ZendLdapException $exception) { |
|
99
|
4 |
|
$this->zendExceptionHandler($exception); |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
4 |
|
return false; |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
/** |
|
106
|
|
|
* Treat a Zend Ldap Exception. |
|
107
|
|
|
* |
|
108
|
|
|
* @param ZendLdapException $exception |
|
109
|
|
|
*/ |
|
110
|
4 |
|
protected function zendExceptionHandler(ZendLdapException $exception) |
|
111
|
|
|
{ |
|
112
|
4 |
|
switch ($exception->getCode()) { |
|
113
|
|
|
// Error level codes |
|
114
|
4 |
|
case ZendLdapException::LDAP_SERVER_DOWN: |
|
115
|
|
|
if ($this->logger) { |
|
116
|
|
|
$this->logger->error('{exception}', ['exception' => $exception]); |
|
117
|
|
|
} |
|
118
|
|
|
break; |
|
119
|
|
|
|
|
120
|
|
|
// Other level codes |
|
121
|
4 |
|
default: |
|
122
|
4 |
|
$this->logDebug('{exception}', ['exception' => $exception]); |
|
123
|
4 |
|
break; |
|
124
|
4 |
|
} |
|
125
|
4 |
|
} |
|
126
|
|
|
|
|
127
|
|
|
/** |
|
128
|
|
|
* Log debug messages if the logger is set. |
|
129
|
|
|
* |
|
130
|
|
|
* @param string $message |
|
131
|
|
|
* @param array $context |
|
132
|
|
|
*/ |
|
133
|
7 |
|
private function logDebug($message, array $context = []) |
|
134
|
|
|
{ |
|
135
|
7 |
|
if ($this->logger) { |
|
136
|
7 |
|
$this->logger->debug($message, $context); |
|
137
|
7 |
|
} |
|
138
|
7 |
|
} |
|
139
|
|
|
} |
|
140
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.