vendor/hwi/oauth-bundle/Controller/ConnectController.php line 279

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the HWIOAuthBundle package.
  4.  *
  5.  * (c) Hardware.Info <opensource@hardware.info>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace HWI\Bundle\OAuthBundle\Controller;
  11. use HWI\Bundle\OAuthBundle\Event\FilterUserResponseEvent;
  12. use HWI\Bundle\OAuthBundle\Event\FormEvent;
  13. use HWI\Bundle\OAuthBundle\Event\GetResponseUserEvent;
  14. use HWI\Bundle\OAuthBundle\HWIOAuthEvents;
  15. use HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface;
  16. use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
  17. use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
  18. use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException;
  19. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  20. use Symfony\Component\Form\Extension\Core\Type\FormType;
  21. use Symfony\Component\Form\FormInterface;
  22. use Symfony\Component\HttpFoundation\RedirectResponse;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\Response;
  25. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  26. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  27. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  28. use Symfony\Component\Security\Core\Exception\AccountStatusException;
  29. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  30. use Symfony\Component\Security\Core\Security;
  31. use Symfony\Component\Security\Core\User\UserInterface;
  32. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  33. use Symfony\Component\Security\Http\SecurityEvents;
  34. /**
  35.  * @author Alexander <iam.asm89@gmail.com>
  36.  */
  37. class ConnectController extends Controller
  38. {
  39.     /**
  40.      * Action that handles the login 'form'. If connecting is enabled the
  41.      * user will be redirected to the appropriate login urls or registration forms.
  42.      *
  43.      * @param Request $request
  44.      *
  45.      * @throws \LogicException
  46.      *
  47.      * @return Response
  48.      */
  49.     public function connectAction(Request $request)
  50.     {
  51.         $connect $this->container->getParameter('hwi_oauth.connect');
  52.         $hasUser $this->getUser() ? $this->isGranted($this->container->getParameter('hwi_oauth.grant_rule')) : false;
  53.         $error $this->getErrorForRequest($request);
  54.         // if connecting is enabled and there is no user, redirect to the registration form
  55.         if ($connect && !$hasUser && $error instanceof AccountNotLinkedException) {
  56.             $key time();
  57.             $session $request->getSession();
  58.             if (!$session->isStarted()) {
  59.                 $session->start();
  60.             }
  61.             $session->set('_hwi_oauth.registration_error.'.$key$error);
  62.             return $this->redirectToRoute('hwi_oauth_connect_registration', array('key' => $key));
  63.         }
  64.         if ($error) {
  65.             if ($error instanceof AuthenticationException) {
  66.                 $error $error->getMessageKey();
  67.             } else {
  68.                 $error $error->getMessage();
  69.             }
  70.         }
  71.         return $this->render('@HWIOAuth/Connect/login.html.twig', array(
  72.             'error' => $error,
  73.         ));
  74.     }
  75.     /**
  76.      * Shows a registration form if there is no user logged in and connecting
  77.      * is enabled.
  78.      *
  79.      * @param Request $request a request
  80.      * @param string  $key     key used for retrieving the right information for the registration form
  81.      *
  82.      * @return Response
  83.      *
  84.      * @throws NotFoundHttpException if `connect` functionality was not enabled
  85.      * @throws AccessDeniedException if any user is authenticated
  86.      * @throws \RuntimeException
  87.      */
  88.     public function registrationAction(Request $request$key)
  89.     {
  90.         $connect $this->container->getParameter('hwi_oauth.connect');
  91.         if (!$connect) {
  92.             throw new NotFoundHttpException();
  93.         }
  94.         $hasUser $this->isGranted($this->container->getParameter('hwi_oauth.grant_rule'));
  95.         if ($hasUser) {
  96.             throw new AccessDeniedException('Cannot connect already registered account.');
  97.         }
  98.         $session $request->getSession();
  99.         if (!$session->isStarted()) {
  100.             $session->start();
  101.         }
  102.         $error $session->get('_hwi_oauth.registration_error.'.$key);
  103.         $session->remove('_hwi_oauth.registration_error.'.$key);
  104.         if (!$error instanceof AccountNotLinkedException) {
  105.             throw new \RuntimeException('Cannot register an account.'0$error instanceof \Exception $error null);
  106.         }
  107.         $userInformation $this
  108.             ->getResourceOwnerByName($error->getResourceOwnerName())
  109.             ->getUserInformation($error->getRawToken())
  110.         ;
  111.         /* @var $form FormInterface */
  112.         if ($this->container->getParameter('hwi_oauth.fosub_enabled')) {
  113.             // enable compatibility with FOSUserBundle 1.3.x and 2.x
  114.             if (interface_exists('FOS\UserBundle\Form\Factory\FactoryInterface')) {
  115.                 $form $this->container->get('hwi_oauth.registration.form.factory')->createForm();
  116.             } else {
  117.                 $form $this->container->get('hwi_oauth.registration.form');
  118.             }
  119.         } else {
  120.             $form $this->container->get('hwi_oauth.registration.form');
  121.         }
  122.         $formHandler $this->container->get('hwi_oauth.registration.form.handler');
  123.         if ($formHandler->process($request$form$userInformation)) {
  124.             $event = new FormEvent($form$request);
  125.             $this->get('event_dispatcher')->dispatch(HWIOAuthEvents::REGISTRATION_SUCCESS$event);
  126.             $this->container->get('hwi_oauth.account.connector')->connect($form->getData(), $userInformation);
  127.             // Authenticate the user
  128.             $this->authenticateUser($request$form->getData(), $error->getResourceOwnerName(), $error->getAccessToken());
  129.             if (null === $response $event->getResponse()) {
  130.                 if ($targetPath $this->getTargetPath($session)) {
  131.                     $response $this->redirect($targetPath);
  132.                 } else {
  133.                     $response $this->render('@HWIOAuth/Connect/registration_success.html.twig', array(
  134.                         'userInformation' => $userInformation,
  135.                     ));
  136.                 }
  137.             }
  138.             $event = new FilterUserResponseEvent($form->getData(), $request$response);
  139.             $this->get('event_dispatcher')->dispatch(HWIOAuthEvents::REGISTRATION_COMPLETED$event);
  140.             return $response;
  141.         }
  142.         // reset the error in the session
  143.         $session->set('_hwi_oauth.registration_error.'.$key$error);
  144.         $event = new GetResponseUserEvent($form->getData(), $request);
  145.         $this->get('event_dispatcher')->dispatch(HWIOAuthEvents::REGISTRATION_INITIALIZE$event);
  146.         if ($response $event->getResponse()) {
  147.             return $response;
  148.         }
  149.         return $this->render('@HWIOAuth/Connect/registration.html.twig', array(
  150.             'key' => $key,
  151.             'form' => $form->createView(),
  152.             'userInformation' => $userInformation,
  153.         ));
  154.     }
  155.     /**
  156.      * Connects a user to a given account if the user is logged in and connect is enabled.
  157.      *
  158.      * @param Request $request the active request
  159.      * @param string  $service name of the resource owner to connect to
  160.      *
  161.      * @throws \Exception
  162.      *
  163.      * @return Response
  164.      *
  165.      * @throws NotFoundHttpException if `connect` functionality was not enabled
  166.      * @throws AccessDeniedException if no user is authenticated
  167.      */
  168.     public function connectServiceAction(Request $request$service)
  169.     {
  170.         $connect $this->container->getParameter('hwi_oauth.connect');
  171.         if (!$connect) {
  172.             throw new NotFoundHttpException();
  173.         }
  174.         $hasUser $this->isGranted($this->container->getParameter('hwi_oauth.grant_rule'));
  175.         if (!$hasUser) {
  176.             throw new AccessDeniedException('Cannot connect an account.');
  177.         }
  178.         // Get the data from the resource owner
  179.         $resourceOwner $this->getResourceOwnerByName($service);
  180.         $session $request->getSession();
  181.         if (!$session->isStarted()) {
  182.             $session->start();
  183.         }
  184.         $key $request->query->get('key'time());
  185.         if ($resourceOwner->handles($request)) {
  186.             $accessToken $resourceOwner->getAccessToken(
  187.                 $request,
  188.                 $this->container->get('hwi_oauth.security.oauth_utils')->getServiceAuthUrl($request$resourceOwner)
  189.             );
  190.             // save in session
  191.             $session->set('_hwi_oauth.connect_confirmation.'.$key$accessToken);
  192.         } else {
  193.             $accessToken $session->get('_hwi_oauth.connect_confirmation.'.$key);
  194.         }
  195.         // Redirect to the login path if the token is empty (Eg. User cancelled auth)
  196.         if (null === $accessToken) {
  197.             if ($this->container->getParameter('hwi_oauth.failed_use_referer') && $targetPath $this->getTargetPath($session'failed_target_path')) {
  198.                 return $this->redirect($targetPath);
  199.             }
  200.             return $this->redirectToRoute($this->container->getParameter('hwi_oauth.failed_auth_path'));
  201.         }
  202.         // Show confirmation page?
  203.         if (!$this->container->getParameter('hwi_oauth.connect.confirmation')) {
  204.             return $this->getConfirmationResponse($request$accessToken$service);
  205.         }
  206.         // Symfony <3.0 BC
  207.         /** @var $form FormInterface */
  208.         $form method_exists('Symfony\Component\Form\AbstractType''getBlockPrefix')
  209.             ? $this->createForm(FormType::class)
  210.             : $this->createForm('form');
  211.         // Handle the form
  212.         $form->handleRequest($request);
  213.         if ($form->isSubmitted() && $form->isValid()) {
  214.             return $this->getConfirmationResponse($request$accessToken$service);
  215.         }
  216.         $event = new GetResponseUserEvent($this->getUser(), $request);
  217.         $this->get('event_dispatcher')->dispatch(HWIOAuthEvents::CONNECT_INITIALIZE$event);
  218.         if ($response $event->getResponse()) {
  219.             return $response;
  220.         }
  221.         return $this->render('@HWIOAuth/Connect/connect_confirm.html.twig', array(
  222.             'key' => $key,
  223.             'service' => $service,
  224.             'form' => $form->createView(),
  225.             'userInformation' => $resourceOwner->getUserInformation($accessToken),
  226.         ));
  227.     }
  228.     /**
  229.      * @param Request $request
  230.      * @param string  $service
  231.      *
  232.      * @throws NotFoundHttpException
  233.      *
  234.      * @return RedirectResponse
  235.      */
  236.     public function redirectToServiceAction(Request $request$service)
  237.     {
  238.         try {
  239.             $authorizationUrl $this->container->get('hwi_oauth.security.oauth_utils')->getAuthorizationUrl($request$service);
  240.         } catch (\RuntimeException $e) {
  241.             throw new NotFoundHttpException($e->getMessage(), $e);
  242.         }
  243.         $session $request->getSession();
  244.         // Check for a return path and store it before redirect
  245.         if (null !== $session) {
  246.             // initialize the session for preventing SessionUnavailableException
  247.             if (!$session->isStarted()) {
  248.                 $session->start();
  249.             }
  250.             foreach ($this->container->getParameter('hwi_oauth.firewall_names') as $providerKey) {
  251.                 $sessionKey '_security.'.$providerKey.'.target_path';
  252.                 $sessionKeyFailure '_security.'.$providerKey.'.failed_target_path';
  253.                 $param $this->container->getParameter('hwi_oauth.target_path_parameter');
  254.                 if (!empty($param) && $targetUrl $request->get($param)) {
  255.                     $session->set($sessionKey$targetUrl);
  256.                 }
  257.                 if ($this->container->getParameter('hwi_oauth.failed_use_referer') && !$session->has($sessionKeyFailure) && ($targetUrl $request->headers->get('Referer')) && $targetUrl !== $authorizationUrl) {
  258.                     $session->set($sessionKeyFailure$targetUrl);
  259.                 }
  260.                 if ($this->container->getParameter('hwi_oauth.use_referer') && !$session->has($sessionKey) && ($targetUrl $request->headers->get('Referer')) && $targetUrl !== $authorizationUrl) {
  261.                     $session->set($sessionKey$targetUrl);
  262.                 }
  263.             }
  264.         }
  265.         return $this->redirect($authorizationUrl);
  266.     }
  267.     /**
  268.      * Get the security error for a given request.
  269.      *
  270.      * @param Request $request
  271.      *
  272.      * @return string|\Exception
  273.      */
  274.     protected function getErrorForRequest(Request $request)
  275.     {
  276.         $authenticationErrorKey Security::AUTHENTICATION_ERROR;
  277.         if ($request->attributes->has($authenticationErrorKey)) {
  278.             return $request->attributes->get($authenticationErrorKey);
  279.         }
  280.         $session $request->getSession();
  281.         if (null !== $session && $session->has($authenticationErrorKey)) {
  282.             $error $session->get($authenticationErrorKey);
  283.             $session->remove($authenticationErrorKey);
  284.             return $error;
  285.         }
  286.         return '';
  287.     }
  288.     /**
  289.      * Get a resource owner by name.
  290.      *
  291.      * @param string $name
  292.      *
  293.      * @return ResourceOwnerInterface
  294.      *
  295.      * @throws NotFoundHttpException if there is no resource owner with the given name
  296.      */
  297.     protected function getResourceOwnerByName($name)
  298.     {
  299.         foreach ($this->container->getParameter('hwi_oauth.firewall_names') as $firewall) {
  300.             $id 'hwi_oauth.resource_ownermap.'.$firewall;
  301.             if (!$this->container->has($id)) {
  302.                 continue;
  303.             }
  304.             $ownerMap $this->container->get($id);
  305.             if ($resourceOwner $ownerMap->getResourceOwnerByName($name)) {
  306.                 return $resourceOwner;
  307.             }
  308.         }
  309.         throw new NotFoundHttpException(sprintf("No resource owner with name '%s'."$name));
  310.     }
  311.     /**
  312.      * Generates a route.
  313.      *
  314.      * @deprecated since version 0.4. Will be removed in 1.0.
  315.      *
  316.      * @param string $route    Route name
  317.      * @param array  $params   Route parameters
  318.      * @param bool   $absolute absolute url or note
  319.      *
  320.      * @return string
  321.      */
  322.     protected function generate($route, array $params = array(), $absolute false)
  323.     {
  324.         @trigger_error('The '.__METHOD__.' method is deprecated since version 0.4 and will be removed in 1.0. Use Symfony\Bundle\FrameworkBundle\Controller\Controller::generateUrl instead.'E_USER_DEPRECATED);
  325.         return $this->container->get('router')->generate($route$params$absolute);
  326.     }
  327.     /**
  328.      * Authenticate a user with Symfony Security.
  329.      *
  330.      * @param Request       $request
  331.      * @param UserInterface $user
  332.      * @param string        $resourceOwnerName
  333.      * @param string        $accessToken
  334.      * @param bool          $fakeLogin
  335.      */
  336.     protected function authenticateUser(Request $requestUserInterface $user$resourceOwnerName$accessToken$fakeLogin true)
  337.     {
  338.         try {
  339.             $this->container->get('hwi_oauth.user_checker')->checkPreAuth($user);
  340.             $this->container->get('hwi_oauth.user_checker')->checkPostAuth($user);
  341.         } catch (AccountStatusException $e) {
  342.             // Don't authenticate locked, disabled or expired users
  343.             return;
  344.         }
  345.         $token = new OAuthToken($accessToken$user->getRoles());
  346.         $token->setResourceOwnerName($resourceOwnerName);
  347.         $token->setUser($user);
  348.         $token->setAuthenticated(true);
  349.         $this->get('security.token_storage')->setToken($token);
  350.         if ($fakeLogin) {
  351.             // Since we're "faking" normal login, we need to throw our INTERACTIVE_LOGIN event manually
  352.             $this->container->get('event_dispatcher')->dispatch(
  353.                 SecurityEvents::INTERACTIVE_LOGIN,
  354.                 new InteractiveLoginEvent($request$token)
  355.             );
  356.         }
  357.     }
  358.     /**
  359.      * @param SessionInterface $session
  360.      *
  361.      * @return string|null
  362.      */
  363.     private function getTargetPath(SessionInterface $session)
  364.     {
  365.         foreach ($this->container->getParameter('hwi_oauth.firewall_names') as $providerKey) {
  366.             $sessionKey '_security.'.$providerKey.'.target_path';
  367.             if ($session->has($sessionKey)) {
  368.                 return $session->get($sessionKey);
  369.             }
  370.         }
  371.         return null;
  372.     }
  373.     /**
  374.      * @param Request $request     The active request
  375.      * @param array   $accessToken The access token
  376.      * @param string  $service     Name of the resource owner to connect to
  377.      *
  378.      * @return Response
  379.      *
  380.      * @throws NotFoundHttpException if there is no resource owner with the given name
  381.      */
  382.     private function getConfirmationResponse(Request $request, array $accessToken$service)
  383.     {
  384.         /** @var $currentToken OAuthToken */
  385.         $currentToken $this->container->get('security.token_storage')->getToken();
  386.         /** @var $currentUser UserInterface */
  387.         $currentUser $currentToken->getUser();
  388.         /** @var $resourceOwner ResourceOwnerInterface */
  389.         $resourceOwner $this->getResourceOwnerByName($service);
  390.         /** @var $userInformation UserResponseInterface */
  391.         $userInformation $resourceOwner->getUserInformation($accessToken);
  392.         $event = new GetResponseUserEvent($currentUser$request);
  393.         $this->get('event_dispatcher')->dispatch(HWIOAuthEvents::CONNECT_CONFIRMED$event);
  394.         $this->container->get('hwi_oauth.account.connector')->connect($currentUser$userInformation);
  395.         if ($currentToken instanceof OAuthToken) {
  396.             // Update user token with new details
  397.             $newToken =
  398.                 is_array($accessToken) &&
  399.                 (isset($accessToken['access_token']) || isset($accessToken['oauth_token'])) ?
  400.                     $accessToken $currentToken->getRawToken();
  401.             $this->authenticateUser($request$currentUser$service$newTokenfalse);
  402.         }
  403.         if (null === $response $event->getResponse()) {
  404.             if ($targetPath $this->getTargetPath($request->getSession())) {
  405.                 $response $this->redirect($targetPath);
  406.             } else {
  407.                 $response $this->render('@HWIOAuth/Connect/connect_success.html.twig', array(
  408.                     'userInformation' => $userInformation,
  409.                     'service' => $service,
  410.                 ));
  411.             }
  412.         }
  413.         $event = new FilterUserResponseEvent($currentUser$request$response);
  414.         $this->get('event_dispatcher')->dispatch(HWIOAuthEvents::CONNECT_COMPLETED$event);
  415.         return $response;
  416.     }
  417. }