UserContext.php 9.54 KB
Newer Older
1
2
3
4
<?php

namespace UnicaenAuth\Service;

5
use BjyAuthorize\Acl\Role;
6
use UnicaenApp\Exception\RuntimeException;
7
use UnicaenApp\Traits\SessionContainerTrait;
8
use UnicaenAuth\Entity\Shibboleth\ShibUser;
9
use UnicaenAuth\Event\UserRoleSelectedEvent;
10
use UnicaenAuth\Provider\Identity\Chain;
11
use Zend\EventManager\EventManagerAwareInterface;
12
use Zend\Session\Container as SessionContainer;
13
use Zend\Permissions\Acl\Role\RoleInterface;
14
15
use ZfcUser\Entity\UserInterface;
use UnicaenAuth\Entity\Ldap\People;
16
use UnicaenAuth\Acl\NamedRole;
17
use Zend\EventManager\EventManagerAwareTrait;
18
19

/**
20
 * Service centralisant des méthodes utiles concernant l'utilisateur authentifié.
21
22
23
 *
 * @author Laurent LÉCLUSE <laurent.lecluse at unicaen.fr>
 */
24
class UserContext extends AbstractService implements EventManagerAwareInterface
25
{
26
    use EventManagerAwareTrait;
27
    use SessionContainerTrait;
28
29
30
31
32

    /**
     * @var mixed
     */
    protected $identity;
33

34
    /**
35
     * @var array
36
     */
37
    protected $identityRoles;
38

39

40
41
42
43
44
45
46
47
48
49
50
51
52

    /**
     * Retourne l'utilisateur BDD courant
     *
     * @return UserInterface
     */
    public function getDbUser()
    {
        if (($identity = $this->getIdentity())) {
            if (isset($identity['db']) && $identity['db'] instanceof UserInterface) {
                return $identity['db'];
            }
        }
53

54
55
56
        return null;
    }

57
58


59
60
61
62
63
64
65
66
67
68
69
70
    /**
     * Retourne l'utilisateur LDAP courant
     *
     * @return People
     */
    public function getLdapUser()
    {
        if (($identity = $this->getIdentity())) {
            if (isset($identity['ldap']) && $identity['ldap'] instanceof People) {
                return $identity['ldap'];
            }
        }
71

72
73
74
        return null;
    }

75
76


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
    /**
     * Retourne l'éventuel utilisateur Shibboleth courant.
     *
     * @return ShibUser|null
     */
    public function getShibUser()
    {
        if (($identity = $this->getIdentity())) {
            if (isset($identity['shib']) && $identity['shib'] instanceof ShibUser) {
                return $identity['shib'];
            }
        }

        return null;
    }



95
    /**
96
     * Retourne les données d'identité correspondant à l'utilisateur courant.
97
     *
98
     * @return mixed
99
     */
100
    public function getIdentity()
101
    {
102
103
104
105
106
107
        if (null === $this->identity) {
            $authenticationService = $this->getServiceLocator()->get('Zend\Authentication\AuthenticationService');
            if ($authenticationService->hasIdentity()) {
                $this->identity = $authenticationService->getIdentity();
            }
        }
108

109
110
        return $this->identity;
    }
111

112

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    /**
     * Retourne l'identifiant de connexion de l'utilisateur courant.
     *
     * @return string|null
     */
    public function getIdentityUsername()
    {
        if ($user = $this->getShibUser()) {
            return $user->getUsername();
        }
        if ($user = $this->getLdapUser()) {
            return $user->getUsername();
        }
        if ($user = $this->getDbUser()) {
            return $user->getUsername();
        }

        return null;
    }


134

Laurent Lécluse's avatar
Laurent Lécluse committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    /**
     * @param string $roleId
     *
     * @return Role
     */
    public function getIdentityRole($roleId)
    {
        $roles = $this->getServiceAuthorize()->getRoles();
        if (isset($roles[$roleId])) {
            return $roles[$roleId];
        }

        return null;
    }



152
    /**
153
     * Retourne tous les rôles de l'utilisateur courant, pas seulement le rôle courant sélectionné.
154
     *
155
156
157
     * Les clés du tableau sont les ID de rôles, les valeurs sont les objets Role
     *
     * @return Role[]
158
159
160
161
     */
    public function getIdentityRoles()
    {
        if (null === $this->identityRoles) {
162
163
164
            $this->identityRoles = [];

            $roles            = $this->getServiceAuthorize()->getRoles();
165
166
            $identityProvider = $this->getIdentityProvider();
            if ($identityProvider instanceof Chain) {
167
                $iRoles = $identityProvider->getAllIdentityRoles();
168
            } else {
169
170
171
172
173
174
175
176
177
                $iRoles = $identityProvider->getIdentityRoles();
            }
            foreach ($iRoles as $role) {
                if ($role instanceof Role) {
                    $this->identityRoles[$role->getRoleId()] = $role;
                } elseif (isset($roles[$role])) {
                    $role                                    = $roles[$role];
                    $this->identityRoles[$role->getRoleId()] = $role;
                }
178
            }
179
        }
180

181
182
        return $this->identityRoles;
    }
183

184
185


186
    /**
187
     * Retourne parmi tous les rôles de l'utilisateur courant ceux qui peuvent être sélectionnés.
188
     *
189
190
191
192
     * @return array
     */
    public function getSelectableIdentityRoles()
    {
193
194
195
        $filter = function ($r) {
            return !($r instanceof NamedRole && !$r->getSelectable());
        };
Bertrand Gauthier's avatar
Bertrand Gauthier committed
196
        $roles  = array_filter($this->getIdentityRoles(), $filter);
197

Bertrand Gauthier's avatar
Bertrand Gauthier committed
198
        return $roles;
199
    }
200

201
202


203
    /**
204
     * Si un utilisateur est authentifié, retourne le rôle utilisateur sélectionné,
205
     * ou alors le premier sélectionnable si aucun n'a été sélectionné.
206
207
208
209
     *
     * NB: Si un rôle est spécifié en session comme devant être le prochain rôle sélectionné,
     * c'est lui qui est pris en compte.
     *
210
211
212
213
     * @return mixed
     */
    public function getSelectedIdentityRole()
    {
214

215
216
217
218
219
220
221
        if ($this->getNextSelectedIdentityRole()) {
            $this->getSessionContainer()->selectedIdentityRole = $this->getNextSelectedIdentityRole();
        }

        if (null === $this->getSessionContainer()->selectedIdentityRole && $this->getIdentity()) {
            $roles = $this->getSelectableIdentityRoles();
            $this->setSelectedIdentityRole(reset($roles));
222
        }
223
224
225

        $roleId = $this->getSessionContainer()->selectedIdentityRole;

226
227
228
229
230
        if ($roleId) {

            $roles = $this->getServiceAuthorize()->getRoles(); // Récupération de tous les rôles du provider
            if (isset($roles[$roleId])) {
                $role = $roles[$roleId];
231
            } else {
232
233
234
                $role = null;
            }

235
236
237
            if ($this->isRoleValid($role)) {
                return $role;
            }
238
        }
239

240
        return null;
241
    }
242

243
244


245
    /**
Bertrand Gauthier's avatar
Bertrand Gauthier committed
246
     * Mémorise en session le rôle spécifié comme étant le rôle courant de l'utilisateur.
247
     *
Bertrand Gauthier's avatar
Bertrand Gauthier committed
248
     * NB: seul l'id du rôle est mémorisé en session.
249
     *
Bertrand Gauthier's avatar
Bertrand Gauthier committed
250
     * @param RoleInterface|string $role
251
     *
252
     * @return \UnicaenAuth\Service\UserContext
253
     * @throws RuntimeException
254
255
256
257
258
     */
    public function setSelectedIdentityRole($role)
    {
        if ($role) {
            if (!$this->isRoleValid($role)) {
259
                throw new RuntimeException("Rôle spécifié invalide.");
260
            }
Bertrand Gauthier's avatar
Bertrand Gauthier committed
261
262
263
264
            if ($role instanceof RoleInterface) {
                $role = $role->getRoleId();
            }
            $this->getSessionContainer()->selectedIdentityRole = $role;
265
        } else {
266
267
            unset($this->getSessionContainer()->selectedIdentityRole);
        }
268

269
270
        $this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role);

271
272
273
        return $this;
    }

274
275


276
277
278
279
280
    /**
     * Retourne l'éventuel rôle spécifié en session devant être le prochain rôle sélectionné.
     *
     * @return string|null
     */
281
    public function getNextSelectedIdentityRole()
282
283
284
285
    {
        return $this->getSessionContainer()->nextSelectedIdentityRole;
    }

286
287


288
289
290
291
292
293
    /**
     * Mémorise en session le rôle devant être le prochain rôle sélectionné.
     *
     * NB: seul l'id du rôle est mémorisé en session ; la durée de vie du stockage est de 1 requête seulement.
     *
     * @param RoleInterface|string $role
294
     *
295
296
297
298
299
300
301
302
303
304
305
     * @return \UnicaenAuth\Service\UserContext
     */
    public function setNextSelectedIdentityRole($role)
    {
        if ($role instanceof RoleInterface) {
            $role = $role->getRoleId();
        }

        if ($role) {
            $this->getSessionContainer()->nextSelectedIdentityRole = $role;
            $this->getSessionContainer()->setExpirationHops(1, 'nextSelectedIdentityRole');
306
        } else {
307
308
309
            unset($this->getSessionContainer()->nextSelectedIdentityRole);
        }

310
311
        $this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role);

312
313
        return $this;
    }
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
    /**
     * Déclenche l'événement donnant à l'application l'opportunité de réagir à la sélection d'un rôle.
     *
     * @param string $name Ex: UserRoleSelectedEvent::POST_SELECTION
     * @param RoleInterface|string|null $role Rôle sélectionné
     */
    private function triggerUserRoleSelectedEvent($name, $role)
    {
        $event = new UserRoleSelectedEvent($name);
        $event
            ->setRole($role)
            ->setTarget($this);
        $this->getEventManager()->trigger($event);
    }
329

330
    /**
331
     * Teste si le rôle spécifié fait partie des rôles disponibles.
332
333
     *
     * @param RoleInterface|string $role
334
     *
335
     * @return boolean
336
     */
337
    public function isRoleValid($role)
338
    {
Bertrand Gauthier's avatar
Bertrand Gauthier committed
339
340
341
        if ($role instanceof RoleInterface) {
            $role = $role->getRoleId();
        }
342

343
        foreach ($this->getIdentityRoles() as $r) {
344
            if ($r instanceof RoleInterface) {
345
346
347
348
349
350
                $r = $r->getRoleId();
            }
            if ($role === $r) {
                return true;
            }
        }
351

352
353
        return false;
    }
354

355
356


357
    /**
358
     *
359
360
361
362
     * @return \UnicaenAuth\Provider\Identity\Chain
     */
    private function getIdentityProvider()
    {
363
364
        return $this->getServiceAuthorize()->getIdentityProvider();
        /* @var $identityProvider \UnicaenAuth\Provider\Identity\Chain */
365
    }
366

367
}