Exponential 5.x Kernel 7.5.40 Exponential New Stack (Symfony-based) Kernel — PHP Class Reference

SecurityListener.php
Go to the documentation of this file.
1 <?php
2
7 namespace eZ\Publish\Core\MVC\Symfony\Security\EventListener;
8
9 use eZ\Publish\API\Repository\Repository;
10 use eZ\Publish\Core\MVC\ConfigResolverInterface;
11 use eZ\Publish\Core\MVC\Symfony\MVCEvents;
12 use eZ\Publish\Core\MVC\Symfony\Security\Authorization\Attribute;
13 use eZ\Publish\Core\MVC\Symfony\Security\Exception\UnauthorizedSiteAccessException;
14 use eZ\Publish\Core\MVC\Symfony\Security\InteractiveLoginToken;
15 use eZ\Publish\Core\MVC\Symfony\Security\UserInterface as eZUser;
16 use eZ\Publish\API\Repository\Values\User\User as APIUser;
17 use eZ\Publish\Core\MVC\Symfony\Event\InteractiveLoginEvent;
18 use eZ\Publish\Core\MVC\Symfony\Security\UserWrapped;
19 use eZ\Publish\Core\MVC\Symfony\SiteAccess;
20 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
21 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
22 use Symfony\Component\HttpFoundation\Request;
23 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
24 use Symfony\Component\HttpKernel\HttpKernelInterface;
25 use Symfony\Component\HttpKernel\KernelEvents;
26 use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
27 use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
28 use Symfony\Component\Security\Http\Event\InteractiveLoginEvent as BaseInteractiveLoginEvent;
29 use Symfony\Component\Security\Http\SecurityEvents;
30 use Symfony\Component\Security\Core\User\UserInterface;
31
40 class SecurityListener implements EventSubscriberInterface
41 {
43 protected $repository;
44
46 protected $configResolver;
47
49 protected $eventDispatcher;
50
52 protected $tokenStorage;
53
55 protected $authorizationChecker;
56
62 protected $fragmentPath;
63
64 public function __construct(
65 Repository $repository,
66 ConfigResolverInterface $configResolver,
67 EventDispatcherInterface $eventDispatcher,
68 TokenStorageInterface $tokenStorage,
69 AuthorizationCheckerInterface $authorizationChecker,
70 $fragmentPath = '/_fragment'
71 ) {
72 $this->repository = $repository;
73 $this->configResolver = $configResolver;
74 $this->eventDispatcher = $eventDispatcher;
75 $this->tokenStorage = $tokenStorage;
76 $this->authorizationChecker = $authorizationChecker;
77 $this->fragmentPath = $fragmentPath;
78 }
79
80 public static function getSubscribedEvents()
81 {
82 return [
83 SecurityEvents::INTERACTIVE_LOGIN => [
84 ['onInteractiveLogin', 10],
85 ['checkSiteAccessPermission', 9],
86 ],
87 // Priority 7, so that it occurs just after firewall (priority 8)
88 KernelEvents::REQUEST => ['onKernelRequest', 7],
89 ];
90 }
91
99 public function onInteractiveLogin(BaseInteractiveLoginEvent $event)
100 {
101 $token = $event->getAuthenticationToken();
102 $originalUser = $token->getUser();
103 if ($originalUser instanceof eZUser || !$originalUser instanceof UserInterface) {
104 return;
105 }
106
107 /*
108 * 1. Send the event.
109 * 2. If no eZ user is returned, load Anonymous user.
110 * 3. Inject eZ user in repository.
111 * 4. Create the UserWrapped user object (implementing eZ UserInterface) with loaded eZ user.
112 * 5. Create new token with UserWrapped user
113 * 6. Inject the new token in security context
114 */
115 $subLoginEvent = new InteractiveLoginEvent($event->getRequest(), $token);
116 $this->eventDispatcher->dispatch(MVCEvents::INTERACTIVE_LOGIN, $subLoginEvent);
117
118 if ($subLoginEvent->hasAPIUser()) {
119 $apiUser = $subLoginEvent->getAPIUser();
120 } else {
121 $apiUser = $this->repository->getUserService()->loadUser(
122 $this->configResolver->getParameter('anonymous_user_id')
123 );
124 }
125
126 $this->repository->setCurrentUser($apiUser);
127
128 $providerKey = method_exists($token, 'getProviderKey') ? $token->getProviderKey() : __CLASS__;
129 $interactiveToken = new InteractiveLoginToken(
130 $this->getUser($originalUser, $apiUser),
131 get_class($token),
132 $token->getCredentials(),
133 $providerKey,
134 $token->getRoles()
135 );
136 $interactiveToken->setAttributes($token->getAttributes());
137 $this->tokenStorage->setToken($interactiveToken);
138 }
139
149 protected function getUser(UserInterface $originalUser, APIUser $apiUser)
150 {
151 return new UserWrapped($originalUser, $apiUser);
152 }
153
161 public function checkSiteAccessPermission(BaseInteractiveLoginEvent $event)
162 {
163 $token = $event->getAuthenticationToken();
164 $originalUser = $token->getUser();
165 $request = $event->getRequest();
166 $siteAccess = $request->attributes->get('siteaccess');
167 if (!($originalUser instanceof eZUser && $siteAccess instanceof SiteAccess)) {
168 return;
169 }
170
171 if (!$this->hasAccess($siteAccess)) {
172 throw new UnauthorizedSiteAccessException($siteAccess, $originalUser->getUsername());
173 }
174 }
175
183 public function onKernelRequest(GetResponseEvent $event)
184 {
185 $request = $event->getRequest();
186 // Ignore sub-requests, including fragments.
187 if (!$this->isMasterRequest($request, $event->getRequestType())) {
188 return;
189 }
190
191 $siteAccess = $request->attributes->get('siteaccess');
192 if (!$siteAccess instanceof SiteAccess) {
193 return;
194 }
195
196 $token = $this->tokenStorage->getToken();
197 if ($token === null) {
198 return;
199 }
200
201 if (
202 // Leave access to login route, so that user can attempt re-authentication.
203 $request->attributes->get('_route') !== 'login'
204 && !$this->hasAccess($siteAccess)
205 ) {
206 throw new UnauthorizedSiteAccessException($siteAccess, $token->getUsername());
207 }
208 }
209
219 private function isMasterRequest(Request $request, $requestType)
220 {
221 if (
222 $requestType !== HttpKernelInterface::MASTER_REQUEST
223 || substr($request->getPathInfo(), -strlen($this->fragmentPath)) === $this->fragmentPath
224 ) {
225 return false;
226 }
227
228 return true;
229 }
230
238 protected function hasAccess(SiteAccess $siteAccess)
239 {
240 return $this->authorizationChecker->isGranted(
241 new Attribute('user', 'login', ['valueObject' => $siteAccess])
242 );
243 }
244 }
eZ\Publish\API\Repository\Values\User\User
Definition: Publish/API/Repository/Values/User/User.php:24
eZ\Publish\Core\MVC\Symfony\Event\InteractiveLoginEvent
Definition: InteractiveLoginEvent.php:13
eZ\Publish\Core\MVC\Symfony\MVCEvents
Definition: MVCEvents.php:10
eZ\Publish\Core\MVC\Symfony\MVCEvents\INTERACTIVE_LOGIN
const INTERACTIVE_LOGIN
INTERACTIVE_LOGIN event occurs when a user has been authenticated by a foreign user provider.
Definition: MVCEvents.php:69
eZ\Publish\Core\MVC\Symfony\Security\Authorization\Attribute
Authorization attribute class to be used with SecurityContextInterface::isGranted().
Definition: Attribute.php:31
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener
This security listener listens to security.interactive_login event to:
Definition: SecurityListener.php:41
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\$fragmentPath
$fragmentPath
Definition: SecurityListener.php:62
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\$configResolver
$configResolver
Definition: SecurityListener.php:46
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\onInteractiveLogin
onInteractiveLogin(BaseInteractiveLoginEvent $event)
Tries to retrieve a valid eZ user if authenticated user doesn't come from the repository (foreign use...
Definition: SecurityListener.php:99
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\hasAccess
hasAccess(SiteAccess $siteAccess)
Returns true if current user has access to given SiteAccess.
Definition: SecurityListener.php:238
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\onKernelRequest
onKernelRequest(GetResponseEvent $event)
Throws an UnauthorizedSiteAccessException if current user doesn't have access to current SiteAccess.
Definition: SecurityListener.php:183
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\$eventDispatcher
$eventDispatcher
Definition: SecurityListener.php:49
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\getSubscribedEvents
static getSubscribedEvents()
Definition: SecurityListener.php:80
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\$repository
$repository
Definition: SecurityListener.php:43
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\checkSiteAccessPermission
checkSiteAccessPermission(BaseInteractiveLoginEvent $event)
Throws an UnauthorizedSiteAccessException if current user doesn't have permission to current SiteAcce...
Definition: SecurityListener.php:161
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\$authorizationChecker
$authorizationChecker
Definition: SecurityListener.php:55
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\__construct
__construct(Repository $repository, ConfigResolverInterface $configResolver, EventDispatcherInterface $eventDispatcher, TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker, $fragmentPath='/_fragment')
Definition: SecurityListener.php:64
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\getUser
getUser(UserInterface $originalUser, APIUser $apiUser)
Returns new user object based on original user and provided API user.
Definition: SecurityListener.php:149
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\$tokenStorage
$tokenStorage
Definition: SecurityListener.php:52
eZ\Publish\Core\MVC\Symfony\Security\EventListener\SecurityListener\isMasterRequest
isMasterRequest(Request $request, $requestType)
Returns true if given request is considered as a master request.
Definition: SecurityListener.php:219
eZ\Publish\Core\MVC\Symfony\Security\Exception\UnauthorizedSiteAccessException
This exception is thrown when a user tries to authenticate against a SiteAccess for which he doesn't ...
Definition: UnauthorizedSiteAccessException.php:18
eZ\Publish\Core\MVC\Symfony\Security\InteractiveLoginToken
This token is used when a user has been matched by a foreign user provider.
Definition: InteractiveLoginToken.php:16
eZ\Publish\Core\MVC\Symfony\Security\UserWrapped
This class represents a UserWrapped object.
Definition: UserWrapped.php:25
eZ\Publish\Core\MVC\Symfony\SiteAccess
Base struct for a siteaccess representation.
Definition: SiteAccess.php:16
eZ\Publish\API\Repository\Repository
Repository interface.
Definition: API/Repository/Repository.php:16
eZ\Publish\Core\MVC\ConfigResolverInterface
Interface for config resolvers.
Definition: ConfigResolverInterface.php:19
eZ\Publish\Core\MVC\Symfony\Security\UserInterface
Interface for Repository based users.
Definition: UserInterface.php:16
eZ\Publish\Core\MVC\Symfony\Security\EventListener
Definition: SecurityListener.php:7
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.