src/AppBundle/Security/CustomUsernamePasswordJsonAuthenticationListener.php line 32

Open in your IDE?
  1. <?php
  2. namespace AppBundle\Security;
  3. use Symfony\Component\Security\Http\Firewall\UsernamePasswordJsonAuthenticationListener;
  4. use Doctrine\ORM\EntityManager;
  5. use Psr\Log\LoggerInterface;
  6. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  7. use Symfony\Component\HttpFoundation\JsonResponse;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Symfony\Component\HttpFoundation\Response;
  10. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  11. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  12. use Symfony\Component\PropertyAccess\PropertyAccess;
  13. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  14. use Symfony\Component\PropertyAccess\Exception\AccessException;
  15. use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
  16. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  17. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  18. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  19. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  20. use Symfony\Component\Security\Core\Exception\BadCredentialsException;
  21. use Symfony\Component\Security\Core\Security;
  22. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  23. use Symfony\Component\Security\Http\HttpUtils;
  24. use Symfony\Component\Security\Http\SecurityEvents;
  25. use Symfony\Component\Security\Core\User\UserProviderInterface;
  26. /**
  27.  * CustomUsernamePasswordJsonAuthenticationListener
  28.  */
  29. class CustomUsernamePasswordJsonAuthenticationListener extends UsernamePasswordJsonAuthenticationListener
  30. {
  31.     /** @var AuthenticationManagerInterface */
  32.     private $authenticationManager;
  33.     /** @var HttpUtils */
  34.     private $httpUtils;
  35. //    private $providerKey = null;
  36.     private $successHandler null;
  37.     private $failureHandler null;
  38.     private $options;
  39.     /** @var EventDispatcherInterface */
  40.     private $eventDispatcher;
  41.     private $sessionStrategy;
  42.     /** @var UsernamePasswordJsonAuthenticationListener */
  43.     private $innerService;
  44.     /** @var PropertyAccessorInterface */
  45.     private $propertyAccessor;
  46.     /** @var LoggerInterface */
  47.     private $logger;
  48.     /** @var TokenStorageInterface */
  49.     private $tokenStorage;
  50.     /** @var UserProviderInterface */
  51.     private $provider;
  52.     /** @var BeLAEntityManager */
  53.     private $belaEm;
  54.     /** @var int */
  55.     private $ldapLogLevel;
  56.     /** @var string */
  57.     private $providerKey;
  58.     public function __construct(
  59.         UsernamePasswordJsonAuthenticationListener $innerService,
  60.         TokenStorageInterface $tokenStorage,
  61.         AuthenticationManagerInterface $authenticationManager,
  62.         HttpUtils $httpUtils,
  63.         UserProviderInterface $provider,
  64.         EventDispatcherInterface $dispatcher null,
  65.         EntityManager $belaEm null,
  66.         LoggerInterface $logger null,
  67.         int $ldapLogLevel 0,
  68.         array $options = []
  69.     ) {
  70.         parent::__construct(
  71.             $tokenStorage,
  72.             $authenticationManager,
  73.             $httpUtils,
  74.             null// $providerKey,
  75.             null// AuthenticationSuccessHandlerInterface $successHandler = null,
  76.             null// AuthenticationFailureHandlerInterface $failureHandler = null,
  77.             $options,
  78.             $logger,
  79.             $dispatcher,
  80.             null // PropertyAccessorInterface $propertyAccessor = null
  81.         );
  82.         $this->innerService $innerService;
  83.         $this->tokenStorage $tokenStorage;
  84.         $this->authenticationManager $authenticationManager;
  85.         $this->httpUtils $httpUtils;
  86.         $this->provider $provider;
  87.         $this->eventDispatcher $dispatcher;
  88.         $this->belaEm $belaEm;
  89.         $this->logger $logger;
  90.         $this->ldapLogLevel $ldapLogLevel;
  91.         $this->options $options;
  92.         $this->propertyAccessor PropertyAccess::createPropertyAccessor();
  93.         /** @todo how to get providerKey ("main" here) from configuration (security.yml)? */
  94.         $this->providerKey 'main';
  95.     }
  96.     public function handle(GetResponseEvent $event)
  97.     {
  98.         $request $event->getRequest();
  99.         if (false === strpos($request->getRequestFormat(), 'json')
  100.             && false === strpos($request->getContentType(), 'json')
  101.         ) {
  102.             return;
  103.         }
  104.         /** @todo how to get $options[] from decorated class config (security.yml > firewalls > main > json_login)? we need check_path, username_path and password_path from there or their default values - see parent class and comments below */
  105. //        if (isset($this->options['check_path']) && !$this->httpUtils->checkRequestPath($request, $this->options['check_path'])) {
  106.         if (!$this->httpUtils->checkRequestPath($request'/api/login')) {
  107.             return;
  108.         }
  109.         $data json_decode($request->getContent());
  110.         try {
  111.             if (!$data instanceof \stdClass) {
  112.                 throw new BadRequestHttpException('Invalid JSON.');
  113.             }
  114.             try {
  115. //                $username = $this->propertyAccessor->getValue($data, $this->options['username_path']);
  116.                 $username $this->propertyAccessor->getValue($data'username');
  117.             } catch (AccessException $e) {
  118. //                throw new BadRequestHttpException(sprintf('The key "%s" must be provided.', $this->options['username_path']), $e);
  119.                 throw new BadRequestHttpException('The key "username" must be provided.'$e);
  120.             }
  121.             try {
  122.                 $password $this->propertyAccessor->getValue($data'password');
  123.             } catch (AccessException $e) {
  124.                 throw new BadRequestHttpException('The key "password" must be provided.'$e);
  125.             }
  126.             if (!\is_string($username)) {
  127.                 throw new BadRequestHttpException('The key "username" must be a string.');
  128.             }
  129.             if (\strlen($username) > Security::MAX_USERNAME_LENGTH) {
  130.                 throw new BadCredentialsException('Invalid username.');
  131.             }
  132.             if (!\is_string($password)) {
  133.                 throw new BadRequestHttpException('The key "password" must be a string.');
  134.             }
  135.             if (empty($password)) {
  136.                 throw new BadCredentialsException('Password cannot be empty.');
  137.             }
  138.             $ldapAuth LdapAuth::initialize($this->belaEm$this->provider$this->logger$this->ldapLogLevel)
  139.                 ->setCallback([$this->innerService'handle'])
  140.                 ->setCallbackParams([ $event ]);
  141.             $user $ldapAuth->handle($data);
  142.             if (empty($user)) {
  143.                 return;
  144.             }
  145.             $authenticatedToken = new UsernamePasswordToken($user$password$this->providerKey$user->getRoles());
  146.             $response $this->onSuccess($request$authenticatedToken);
  147.         } catch (AuthenticationException $e) {
  148.             $response $this->onFailure($request$e);
  149.         } catch (BadRequestHttpException $e) {
  150.             $request->setRequestFormat('json');
  151.             throw $e;
  152.         }
  153.         if (null === $response) {
  154.             return;
  155.         }
  156.         $event->setResponse($response);
  157.     }
  158.     private function onSuccess(Request $requestTokenInterface $token)
  159.     {
  160.         if (null !== $this->logger) {
  161.             $this->logger->info('User has been authenticated successfully.', ['username' => $token->getUsername()]);
  162.         }
  163.         $this->migrateSession($request$token);
  164.         $this->tokenStorage->setToken($token);
  165.         if (null !== $this->eventDispatcher) {
  166.             $loginEvent = new InteractiveLoginEvent($request$token);
  167.             $this->eventDispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN$loginEvent);
  168.         }
  169.         if (!$this->successHandler) {
  170.             return; // let the original request succeeds
  171.         }
  172.         $response $this->successHandler->onAuthenticationSuccess($request$token);
  173.         if (!$response instanceof Response) {
  174.             throw new \RuntimeException('Authentication Success Handler did not return a Response.');
  175.         }
  176.         return $response;
  177.     }
  178.     private function onFailure(Request $requestAuthenticationException $failed)
  179.     {
  180.         if (null !== $this->logger) {
  181.             $this->logger->info('Authentication request failed.', ['exception' => $failed]);
  182.         }
  183.         $token $this->tokenStorage->getToken();
  184.         if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) {
  185.             $this->tokenStorage->setToken(null);
  186.         }
  187.         if (!$this->failureHandler) {
  188.             return new JsonResponse(['error' => $failed->getMessageKey()], 401);
  189.         }
  190.         $response $this->failureHandler->onAuthenticationFailure($request$failed);
  191.         if (!$response instanceof Response) {
  192.             throw new \RuntimeException('Authentication Failure Handler did not return a Response.');
  193.         }
  194.         return $response;
  195.     }
  196.     private function migrateSession(Request $requestTokenInterface $token)
  197.     {
  198.         if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
  199.             return;
  200.         }
  201.         $this->sessionStrategy->onAuthentication($request$token);
  202.     }
  203. }