Cas.php 8.66 KB
Newer Older
Bertrand Gauthier's avatar
Bertrand Gauthier committed
1
<?php
2

Bertrand Gauthier's avatar
Bertrand Gauthier committed
3
4
namespace UnicaenAuth\Authentication\Adapter;

5
use Exception;
6
use phpCAS;
7
use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
8
use UnicaenAuth\Options\ModuleOptions;
9
use UnicaenAuth\Service\User;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
10
11
use Zend\Authentication\Exception\UnexpectedValueException;
use Zend\Authentication\Result as AuthenticationResult;
12
use Zend\EventManager\Event;
13
use Zend\EventManager\EventInterface;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
14
15
16
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
17
18
use Zend\Router\RouteInterface;
use Zend\Router\RouteStackInterface;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
19
20
use ZfcUser\Authentication\Adapter\AbstractAdapter;
use ZfcUser\Authentication\Adapter\ChainableAdapter;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
21
22
23
24
25
26

/**
 * CAS authentication adpater
 *
 * @author Bertrand GAUTHIER <bertrand.gauthier@unicaen.fr>
 */
27
class Cas extends AbstractAdapter implements EventManagerAwareInterface
Bertrand Gauthier's avatar
Bertrand Gauthier committed
28
{
Bertrand Gauthier's avatar
Bertrand Gauthier committed
29
30
31
32
    /**
     * @var EventManager
     */
    protected $eventManager;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
33

Bertrand Gauthier's avatar
Bertrand Gauthier committed
34
35
36
37
    /**
     * @var ModuleOptions
     */
    protected $options;
38
39
40
41
42
43
44
45
46
47

    /**
     * @var array
     */
    protected $casOptions;

    /**
     * @var phpCAS
     */
    protected $casClient;
48

49
50
51
52
53
    /**
     * @var LdapPeopleMapper
     */
    protected $ldapPeopleMapper;

54
55
56
57
58
59
60
61
62
63
64
65
66
67
    /**
     * @var User
     */
    private $userService;

    /**
     * @param User $userService
     */
    public function setUserService(User $userService)
    {
        $this->userService = $userService;
    }

    /**
68
     * @var RouteInterface
69
70
71
72
     */
    private $router;

    /**
73
     * @param RouteInterface $router
74
     */
75
    public function setRouter(RouteInterface $router)
76
77
78
79
    {
        $this->router = $router;
    }

Bertrand Gauthier's avatar
Bertrand Gauthier committed
80
    /**
81
     * Réalise l'authentification.
82
     *
83
     * @param EventInterface $e
Bertrand Gauthier's avatar
Bertrand Gauthier committed
84
85
86
     * @throws UnexpectedValueException
     * @see ChainableAdapter
     */
87
    public function authenticate(EventInterface $e)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
88
    {
89
90
91
92
93
        // NB: Dans la version 3.0.0 de zf-commons/zfc-user, cette méthode prend un EventInterface.
        // Mais dans la branche 3.x, c'est un AdapterChainEvent !
        // Si un jour c'est un AdapterChainEvent qui est attendu, plus besoin de faire $e->getTarget().
        $e = $e->getTarget();

94
95
96
97
98
99
100
101
//        if ($e->getIdentity()) {
//            return;
//        }
	/* DS : modification liée à une boucle infinie lors de l'authentification CAS */
	if ($this->isSatisfied()) {
            $storage = $this->getStorage()->read();
            $e->setIdentity($storage['identity'])
                    ->setCode(AuthenticationResult::SUCCESS)
102
                    ->setMessages(['Authentication successful.']);
103
104
            return;
        }
105

Bertrand Gauthier's avatar
Bertrand Gauthier committed
106
107
108
109
        $config = $this->getOptions()->getCas();
        if (!$config) {
            return; // NB: l'authentification CAS est désactivée ssi le tableau des options est vide
        }
110

Bertrand Gauthier's avatar
Bertrand Gauthier committed
111
112
        error_reporting($oldErrorReporting = error_reporting() & ~E_NOTICE);

113
        $this->getCasClient()->forceAuthentication();
Bertrand Gauthier's avatar
Bertrand Gauthier committed
114
115
116
117

        // at this step, the user has been authenticated by the CAS server
        // and the user's login name can be read with phpCAS::getUser().

118
        $identity = $this->getCasClient(false)->getUser();
119

Bertrand Gauthier's avatar
Bertrand Gauthier committed
120
        error_reporting($oldErrorReporting);
121

Bertrand Gauthier's avatar
Bertrand Gauthier committed
122
123
124
125
126
127
        $e->setIdentity($identity);
        $this->setSatisfied(true);
        $storage = $this->getStorage()->read();
        $storage['identity'] = $e->getIdentity();
        $this->getStorage()->write($storage);
        $e->setCode(AuthenticationResult::SUCCESS)
128
129
          ->setMessages(['Authentication successful.']);

130
131
132
133
        // recherche de l'individu dans l'annuaire LDAP (il existe forcément puisque l'auth CAS a réussi)
        $ldapPeople = $this->getLdapPeopleMapper()->findOneByUsername($identity);

        /* @var $userService User */
134
        $this->userService->userAuthenticated($ldapPeople);
Bertrand Gauthier's avatar
Bertrand Gauthier committed
135
    }
136

137
    /**
138
     *
139
     * @param Event $e
140
141
     * @see ChainableAdapter
     */
142
    public function logout(Event $e)
143
144
145
146
    {
        if (!$this->getOptions()->getCas()) {
            return; // NB: l'authentification CAS est désactivée ssi le tableau des options est vide
        }
147

148
        $returnUrl = $this->router->getRequestUri()->setPath($this->router->getBaseUrl())->toString();
149
        $this->getCasClient()->logoutWithRedirectService($returnUrl);
150
    }
151

152
    /**
153
     * Retourne le client CAS.
154
     *
155
156
157
     * @param boolean $initClient
     * @return phpCAS
     * @throws Exception
158
     */
159
    public function getCasClient($initClient = true)
160
    {
161
162
        if (null === $this->casClient) {
            $this->casClient = new phpCAS();
163
        }
164

165
166
167
        if (!$initClient) {
            return $this->casClient;
        }
168

169
170
171
172
173
174
175
        if (null === $this->casOptions) {
            $config = $this->getOptions()->getCas();
            if (!isset($config['connection']['default']['params']) || !$config['connection']['default']['params']) {
                throw new Exception("Les paramètres de connexion au serveur CAS sont invalides.");
            }
            $this->casOptions = $config['connection']['default']['params'];
        }
176

177
        $options = $this->casOptions;
178

179
        if (array_key_exists('debug', $options) && (bool) $options['debug']) {
180
            $this->casClient->setDebug();
181
        }
182

183
        // initialize phpCAS
184
        $this->casClient->client($options['version'], $options['hostname'], $options['port'], $options['uri'], true);
185
        // no SSL validation for the CAS server
186
        $this->casClient->setNoCasServerValidation();
187

188
189
        return $this->casClient;
    }
190

191
192
    /**
     * Spécifie le client CAS.
193
     *
194
195
196
197
198
199
200
     * @param phpCAS $casClient
     * @return self
     */
    public function setCasClient(phpCAS $casClient)
    {
        $this->casClient = $casClient;
        return $this;
201
    }
202

Bertrand Gauthier's avatar
Bertrand Gauthier committed
203
204
205
206
207
208
209
210
211
212
213
214
215
    /**
     * @param ModuleOptions $options
     */
    public function setOptions(ModuleOptions $options)
    {
        $this->options = $options;
    }

    /**
     * @return ModuleOptions
     */
    public function getOptions()
    {
216
217
218
219
220
221
//        if (!$this->options instanceof ModuleOptions) {
//            $options = array_merge(
//                    $this->serviceLocator->get('zfcuser_module_options')->toArray(),
//                    $this->serviceLocator->get('unicaen-auth_module_options')->toArray());
//            $this->setOptions(new ModuleOptions($options));
//        }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
222
223
224
        return $this->options;
    }

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    /**
     * get ldap people mapper
     *
     * @return LdapPeopleMapper
     */
    public function getLdapPeopleMapper()
    {
        return $this->ldapPeopleMapper;
    }

    /**
     * set ldap people mapper
     *
     * @param LdapPeopleMapper $mapper
     * @return self
     */
    public function setLdapPeopleMapper(LdapPeopleMapper $mapper)
    {
        $this->ldapPeopleMapper = $mapper;
244

245
246
247
        return $this;
    }

Bertrand Gauthier's avatar
Bertrand Gauthier committed
248
249
250
251
252
253
254
255
256
    /**
     * Retrieve EventManager instance
     *
     * @return EventManagerInterface
     */
    public function getEventManager()
    {
        return $this->eventManager;
    }
257

Bertrand Gauthier's avatar
Bertrand Gauthier committed
258
    /**
259
     * {@inheritdoc}
Bertrand Gauthier's avatar
Bertrand Gauthier committed
260
261
262
263
264
265
     */
    public function setEventManager(EventManagerInterface $eventManager)
    {
        $this->eventManager = $eventManager;
        return $this;
    }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
266
267

    /**
268
     * @param RouteInterface $router
Bertrand Gauthier's avatar
Bertrand Gauthier committed
269
     */
270
    public function reconfigureRoutesForCasAuth(RouteInterface $router)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
271
    {
272
273
274
275
        if(!$router instanceof RouteStackInterface) {
            return;
        }

Bertrand Gauthier's avatar
Bertrand Gauthier committed
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
        $router->addRoutes([
            // remplace les routes existantes (cf. config du module)
            'zfcuser' => [
                'type'          => 'Literal',
                'priority'      => 1000,
                'options'       => [
                    'route'    => '/auth',
                    'defaults' => [
                        'controller' => 'zfcuser',
                        'action'     => 'index',
                    ],
                ],
                'may_terminate' => true,
                'child_routes'  => [
                    'login'  => [
                        'type'    => 'Literal',
                        'options' => [
                            'route'    => '/connexion',
                            'defaults' => [
                                'controller' => 'zfcuser',
                                'action'     => 'authenticate', // zappe l'action 'login'
                            ],
                        ],
                    ],
                    'logout' => [
                        'type'    => 'Literal',
                        'options' => [
                            'route'    => '/deconnexion',
                            'defaults' => [
                                'controller' => 'zfcuser',
                                'action'     => 'logout',
                            ],
                        ],
                    ],
                ],
            ],
        ]);
    }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
314
}