* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\Event\SwitchUserEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * SwitchUserListener allows a user to impersonate another one temporarily * (like the Unix su command). * * @author Fabien Potencier */ class SwitchUserListener implements ListenerInterface { const EXIT_VALUE = '_exit'; private $tokenStorage; private $provider; private $userChecker; private $providerKey; private $accessDecisionManager; private $usernameParameter; private $role; private $logger; private $dispatcher; private $stateless; public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null, $stateless = false) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); } $this->tokenStorage = $tokenStorage; $this->provider = $provider; $this->userChecker = $userChecker; $this->providerKey = $providerKey; $this->accessDecisionManager = $accessDecisionManager; $this->usernameParameter = $usernameParameter; $this->role = $role; $this->logger = $logger; $this->dispatcher = $dispatcher; $this->stateless = $stateless; } /** * Handles the switch to another user. * * @throws \LogicException if switching to a user failed */ public function handle(GetResponseEvent $event) { $request = $event->getRequest(); $username = $request->get($this->usernameParameter) ?: $request->headers->get($this->usernameParameter); if (!$username) { return; } if (self::EXIT_VALUE === $username) { $this->tokenStorage->setToken($this->attemptExitUser($request)); } else { try { $this->tokenStorage->setToken($this->attemptSwitchUser($request, $username)); } catch (AuthenticationException $e) { throw new \LogicException(sprintf('Switch User failed: "%s"', $e->getMessage())); } } if (!$this->stateless) { $request->query->remove($this->usernameParameter); $request->server->set('QUERY_STRING', http_build_query($request->query->all(), '', '&')); $response = new RedirectResponse($request->getUri(), 302); $event->setResponse($response); } } /** * Attempts to switch to another user. * * @param Request $request A Request instance * @param string $username * * @return TokenInterface|null The new TokenInterface if successfully switched, null otherwise * * @throws \LogicException * @throws AccessDeniedException */ private function attemptSwitchUser(Request $request, $username) { $token = $this->tokenStorage->getToken(); $originalToken = $this->getOriginalToken($token); if (false !== $originalToken) { if ($token->getUsername() === $username) { return $token; } throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); } if (false === $this->accessDecisionManager->decide($token, array($this->role))) { $exception = new AccessDeniedException(); $exception->setAttributes($this->role); throw $exception; } if (null !== $this->logger) { $this->logger->info('Attempting to switch to user.', array('username' => $username)); } $user = $this->provider->loadUserByUsername($username); $this->userChecker->checkPostAuth($user); $roles = $user->getRoles(); $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->tokenStorage->getToken()); $token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles); if (null !== $this->dispatcher) { $switchEvent = new SwitchUserEvent($request, $token->getUser(), $token); $this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent); // use the token from the event in case any listeners have replaced it. $token = $switchEvent->getToken(); } return $token; } /** * Attempts to exit from an already switched user. * * @return TokenInterface The original TokenInterface instance * * @throws AuthenticationCredentialsNotFoundException */ private function attemptExitUser(Request $request) { if (null === ($currentToken = $this->tokenStorage->getToken()) || false === $original = $this->getOriginalToken($currentToken)) { throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); } if (null !== $this->dispatcher && $original->getUser() instanceof UserInterface) { $user = $this->provider->refreshUser($original->getUser()); $switchEvent = new SwitchUserEvent($request, $user, $original); $this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent); $original = $switchEvent->getToken(); } return $original; } /** * Gets the original Token from a switched one. * * @return TokenInterface|false The original TokenInterface instance, false if the current TokenInterface is not switched */ private function getOriginalToken(TokenInterface $token) { foreach ($token->getRoles() as $role) { if ($role instanceof SwitchUserRole) { return $role->getSource(); } } return false; } } __halt_compiler();----SIGNATURE:----RcPhrrvjP3e1lmuSu7wXnDaP7om4JEi8BNJBeRb2GjANV9CNvlrf94hxZ3VV2KMlfox4BhMKY+peFT1ZVdGtXqtLZZ2fLLCeQDC3kQflh0Hlwm3oBo3F01QBSnG4tz/zAPiA3VYe7yz7sXa23KVi6t+/TJdqjFmkx6HiWaakNT1DLH7K5U+XekQKc00D80d2tOHsCrmZwG+SShtc5ff3fzWn3MohRZJYjp5KO/v7fYIsBeHWC+z8TuwFTw2yhDTybaIGaeo62K3xpvi7P7jTZY/41RB/Bh+Mnwpmr+gqju7hdz+Do83pYJl42zAn4qNtH/8aZV1TzXgsVFTQOyQCpsKqkyjkhlAf+1ift1PmmuVQeICsbLnbiJYEpvv7EZmSdwsYFvP+FrNKMnDOwrK4qgqOrccrzKKU+m4tm3ltaQUqL3T3rwdDg2/HC9cN5IjEpe3lNeXcbCvJ5ID6fAMNZEdAq1gHe7Ov192qnQZBMOn1GAzIacTbsenVDEXwAN8syDfmyvnoXw6flJnmhIhEiU/tzNFIMQuo9nPsVu28ujPTiJ+C808+7dOA4HkhucnoZUri5FSqwwEUViLNlsDEBdcFtWEzb1xRZX5VnA7oET4IQRRwfNIiBiDjmna7WKYbBlFHrxHLA1+BBWHFb8e7hcayGvhkNBG0TtICY8UJdpc=----ATTACHMENT:----NTAwOTM2Njc1OTE0ODgwNCA1NjIwNjYzMzE3NjM2NzM0IDYwMDI3MjUxNDUzNDc1Nzc=