Cas.php 8.53 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 phpCAS;
6
use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
7
use UnicaenAuth\Options\ModuleOptions;
8
use UnicaenAuth\Service\User;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
9 10
use Zend\Authentication\Exception\UnexpectedValueException;
use Zend\Authentication\Result as AuthenticationResult;
11
use Zend\EventManager\Event;
12
use Zend\EventManager\EventInterface;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
13 14 15
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
16
use Zend\Router\Http\TreeRouteStack;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
17 18
use ZfcUser\Authentication\Adapter\AbstractAdapter;
use ZfcUser\Authentication\Adapter\ChainableAdapter;
Bertrand Gauthier's avatar
Bertrand Gauthier committed
19 20 21 22 23 24

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

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

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

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

47 48 49 50 51
    /**
     * @var LdapPeopleMapper
     */
    protected $ldapPeopleMapper;

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    /**
     * @var User
     */
    private $userService;

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

    /**
     * @var TreeRouteStack
     */
    private $router;

    /**
     * @param TreeRouteStack $router
     */
    public function setRouter(TreeRouteStack $router)
    {
        $this->router = $router;
    }

Bertrand Gauthier's avatar
Bertrand Gauthier committed
78
    /**
79
     * Réalise l'authentification.
80
     *
81
     * @param EventInterface $e
Bertrand Gauthier's avatar
Bertrand Gauthier committed
82 83 84
     * @throws UnexpectedValueException
     * @see ChainableAdapter
     */
85
    public function authenticate(EventInterface $e)
Bertrand Gauthier's avatar
Bertrand Gauthier committed
86
    {
87 88 89 90 91
        // 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();

92 93 94 95 96 97 98 99
//        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)
100
                    ->setMessages(['Authentication successful.']);
101 102
            return;
        }
103

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

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

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

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

116
        $identity = $this->getCasClient(false)->getUser();
117

Bertrand Gauthier's avatar
Bertrand Gauthier committed
118
        error_reporting($oldErrorReporting);
119

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

128 129 130 131
        // 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 */
132
        $this->userService->userAuthenticated($ldapPeople);
Bertrand Gauthier's avatar
Bertrand Gauthier committed
133
    }
134

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

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

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

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

167 168 169 170 171 172 173
        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'];
        }
174

175
        $options = $this->casOptions;
176

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

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

186 187
        return $this->casClient;
    }
188

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

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

    /**
     * @return ModuleOptions
     */
    public function getOptions()
    {
214 215 216 217 218 219
//        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
220 221 222
        return $this->options;
    }

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    /**
     * 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;
242

243 244 245
        return $this;
    }

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

Bertrand Gauthier's avatar
Bertrand Gauthier committed
256
    /**
257
     * {@inheritdoc}
Bertrand Gauthier's avatar
Bertrand Gauthier committed
258 259 260 261 262 263
     */
    public function setEventManager(EventManagerInterface $eventManager)
    {
        $this->eventManager = $eventManager;
        return $this;
    }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
264 265 266 267 268 269 270 271 272 273 274 275 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

    /**
     * @param TreeRouteStack $router
     */
    public function reconfigureRoutesForCasAuth(TreeRouteStack $router)
    {
        $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
308
}