Ldap.php 7.34 KB
Newer Older
Bertrand Gauthier's avatar
Bertrand Gauthier committed
1
2
3
<?php
namespace UnicaenAuth\Authentication\Adapter;

Bertrand Gauthier's avatar
Bertrand Gauthier committed
4
use UnicaenAuth\Options\ModuleOptions;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
5
6
use Zend\Authentication\Exception\UnexpectedValueException;
use Zend\Authentication\Result as AuthenticationResult;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
7
use Zend\Authentication\Adapter\Ldap as LdapAuthAdapter;
8
9
use Zend\Authentication\Result;
use Zend\EventManager\Event;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
10
11
12
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
13
use Zend\Ldap\Exception\LdapException;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
14
15
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
16
17
18
use ZfcUser\Authentication\Adapter\AbstractAdapter;
use ZfcUser\Authentication\Adapter\AdapterChainEvent as AuthEvent;
use ZfcUser\Authentication\Adapter\ChainableAdapter;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
19
20
21
22
23
24
25
26

/**
 * LDAP authentication adpater
 *
 * @author Bertrand GAUTHIER <bertrand.gauthier@unicaen.fr>
 */
class Ldap extends AbstractAdapter implements ServiceManagerAwareInterface, EventManagerAwareInterface
{
27
    const USURPATION_USERNAMES_SEP = '=';
28

Bertrand Gauthier's avatar
Bertrand Gauthier committed
29
30
31
32
33
34
    /**
     * @var ServiceManager
     */
    protected $serviceManager;

    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
35
     * @var EventManager
Bertrand Gauthier's avatar
Bertrand Gauthier committed
36
37
     */
    protected $eventManager;
38

Bertrand Gauthier's avatar
Bertrand Gauthier committed
39
    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
40
     * @var LdapAuthAdapter
Bertrand Gauthier's avatar
Bertrand Gauthier committed
41
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
42
    protected $ldapAuthAdapter;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
43
44

    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
45
     * @var ModuleOptions
Bertrand Gauthier's avatar
Bertrand Gauthier committed
46
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
47
    protected $options;
48

49
    /**
50
     * @var string
51
52
     */
    protected $usernameUsurpe;
53

Bertrand Gauthier's avatar
Bertrand Gauthier committed
54
    /**
55
     *
Bertrand Gauthier's avatar
Bertrand Gauthier committed
56
57
58
59
60
61
62
63
64
65
66
     * @param AuthEvent $e
     * @return boolean
     * @throws UnexpectedValueException
     * @see ChainableAdapter
     */
    public function authenticate(AuthEvent $e)
    {
        if ($this->isSatisfied()) {
            $storage = $this->getStorage()->read();
            $e->setIdentity($storage['identity'])
                    ->setCode(AuthenticationResult::SUCCESS)
67
                    ->setMessages(['Authentication successful.']);
Bertrand Gauthier's avatar
Bertrand Gauthier committed
68
69
70
            return;
        }

Bertrand Gauthier's avatar
Bertrand Gauthier committed
71
        $username   = $e->getRequest()->getPost()->get('identity');
Bertrand Gauthier's avatar
Bertrand Gauthier committed
72
73
        $credential = $e->getRequest()->getPost()->get('credential');

74
75
76
77
78
79
        if (function_exists('mb_strtolower')) {
            $username = mb_strtolower($username, 'UTF-8');
        } else {
            $username = strtolower($username);
        }

80
        $success = $this->authenticateUsername($username, $credential);
81

Bertrand Gauthier's avatar
Bertrand Gauthier committed
82
        // Failure!
83
        if (! $success) {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
84
            $e->setCode(AuthenticationResult::FAILURE)
85
              ->setMessages(['LDAP bind failed.']);
Bertrand Gauthier's avatar
Bertrand Gauthier committed
86
87
88
            $this->setSatisfied(false);
            return false;
        }
89

90
        $e->setIdentity($this->usernameUsurpe ?: $username);
Bertrand Gauthier's avatar
Bertrand Gauthier committed
91
92
93
94
95
        $this->setSatisfied(true);
        $storage = $this->getStorage()->read();
        $storage['identity'] = $e->getIdentity();
        $this->getStorage()->write($storage);
        $e->setCode(AuthenticationResult::SUCCESS)
96
97
          ->setMessages(['Authentication successful.']);

Bertrand Gauthier's avatar
Bertrand Gauthier committed
98
99
100
        $this->getEventManager()->trigger('userAuthenticated', $e);
    }

101
102
    /**
     * Authentifie l'identifiant et le mot de passe spécifiés.
103
     *
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
     * @param string $username Identifiant de connexion
     * @param string $credential Mot de passe
     * @return boolean
     */
    public function authenticateUsername($username, $credential)
    {
        // si 2 logins sont fournis, cela active l'usurpation d'identité (à n'utiliser que pour les tests) :
        // - le format attendu est "loginUsurpateur=loginUsurpé"
        // - le mot de passe attendu est celui du compte usurpateur (loginUsurpateur)
        $this->usernameUsurpe = null;
        if (strpos($username, self::USURPATION_USERNAMES_SEP) > 0) {
            list($username, $this->usernameUsurpe) = explode(self::USURPATION_USERNAMES_SEP, $username, 2);
            if (!in_array($username, $this->getOptions()->getUsurpationAllowedUsernames())) {
                $this->usernameUsurpe = null;
            }
        }

        // LDAP auth
122
123
124


        /** @var Result $result */
125
        $result  = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate();
126
127
128
129
130
131
132
133
134
135
136
137


        if ($result && count($result->getMessages())) {
            // Obtenir le message LDAP
            // $msg = preg_replace('/\[0x\d* \((.*)\):/','$1', $event->getParam('result')->getMessages()[1]);
            $eventClasse = new Event('authentication.ldap.error');
            $eventClasse->setTarget($this)->setParams([
                'result' => $result
            ]);
            $this->getEventManager()->trigger($eventClasse);
        }

138
        $success = $result->isValid();
139

140
141
        // verif existence du login usurpé
        if ($this->usernameUsurpe) {
142
            // s'il nexiste pas, échec de l'authentification
143
144
            if (!$this->getLdapAuthAdapter()->getLdap()->searchEntries("(supannAliasLogin=$this->usernameUsurpe)")) {
                $this->usernameUsurpe = null;
145
                $success              = false;
146
147
            }
        }
148

149
150
        return $success;
    }
151

Bertrand Gauthier's avatar
Bertrand Gauthier committed
152
    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
153
     * @param ModuleOptions $options
Bertrand Gauthier's avatar
Bertrand Gauthier committed
154
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
155
    public function setOptions(ModuleOptions $options)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
156
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
157
        $this->options = $options;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
158
159
160
    }

    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
161
     * @return ModuleOptions
Bertrand Gauthier's avatar
Bertrand Gauthier committed
162
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
163
    public function getOptions()
Bertrand Gauthier's avatar
Bertrand Gauthier committed
164
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
165
166
167
168
169
170
171
        if (!$this->options instanceof ModuleOptions) {
            $options = array_merge(
                    $this->getServiceManager()->get('zfcuser_module_options')->toArray(),
                    $this->getServiceManager()->get('unicaen-auth_module_options')->toArray());
            $this->setOptions(new ModuleOptions($options));
        }
        return $this->options;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
172
    }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
173

Bertrand Gauthier's avatar
Bertrand Gauthier committed
174
    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
175
     * @return \UnicaenApp\Options\ModuleOptions
Bertrand Gauthier's avatar
Bertrand Gauthier committed
176
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
177
    public function getAppModuleOptions()
Bertrand Gauthier's avatar
Bertrand Gauthier committed
178
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
179
        return $this->getServiceManager()->get('unicaen-app_module_options');
Bertrand Gauthier's avatar
Bertrand Gauthier committed
180
181
182
183
    }

    /**
     * get ldap connection adapter
184
     *
Bertrand Gauthier's avatar
Bertrand Gauthier committed
185
     * @return LdapAuthAdapter
Bertrand Gauthier's avatar
Bertrand Gauthier committed
186
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
187
    public function getLdapAuthAdapter()
Bertrand Gauthier's avatar
Bertrand Gauthier committed
188
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
189
        if (null === $this->ldapAuthAdapter) {
190
            $options = [];
Bertrand Gauthier's avatar
Bertrand Gauthier committed
191
192
193
194
195
196
            if (($config = $this->getAppModuleOptions()->getLdap())) {
                foreach ($config['connection'] as $name => $connection) {
                    $options[$name] = $connection['params'];
                }
            }
            $this->ldapAuthAdapter = new LdapAuthAdapter($options); // NB: array(array)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
197
        }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
198
        return $this->ldapAuthAdapter;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
199
200
201
202
    }

    /**
     * set ldap connection adapter
203
     *
Bertrand Gauthier's avatar
Bertrand Gauthier committed
204
     * @param LdapAuthAdapter $authAdapter
Bertrand Gauthier's avatar
Bertrand Gauthier committed
205
206
     * @return Ldap
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
207
    public function setLdapAuthAdapter(LdapAuthAdapter $authAdapter)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
208
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
209
        $this->ldapAuthAdapter = $authAdapter;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
210
211
212
213
        return $this;
    }

    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
214
215
216
     * Get service manager
     *
     * @return ServiceManager
Bertrand Gauthier's avatar
Bertrand Gauthier committed
217
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
218
    public function getServiceManager()
Bertrand Gauthier's avatar
Bertrand Gauthier committed
219
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
220
        return $this->serviceManager;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
221
222
223
    }

    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
224
225
226
227
     * Set service manager
     *
     * @param ServiceManager $serviceManager
     * @return Ldap
Bertrand Gauthier's avatar
Bertrand Gauthier committed
228
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
229
    public function setServiceManager(ServiceManager $serviceManager)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
230
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
231
232
        $this->serviceManager = $serviceManager;
        return $this;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
233
    }
234

Bertrand Gauthier's avatar
Bertrand Gauthier committed
235
    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
236
237
238
     * Retrieve EventManager instance
     *
     * @return EventManagerInterface
Bertrand Gauthier's avatar
Bertrand Gauthier committed
239
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
240
    public function getEventManager()
Bertrand Gauthier's avatar
Bertrand Gauthier committed
241
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
242
        return $this->eventManager;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
243
    }
244

Bertrand Gauthier's avatar
Bertrand Gauthier committed
245
    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
246
247
248
249
     * Inject an EventManager instance
     *
     * @param  EventManagerInterface $eventManager
     * @return Ldap
Bertrand Gauthier's avatar
Bertrand Gauthier committed
250
     */
Bertrand Gauthier's avatar
Bertrand Gauthier committed
251
    public function setEventManager(EventManagerInterface $eventManager)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
252
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
253
254
        $this->eventManager = $eventManager;
        return $this;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
255
256
    }
}