/** * To access private user data, you need his/her authorization. This endpoint is an HTML page that ask the current * logged user if (s)he wants to accept your application. If (s)he doesn't, (s)he is redirected to EtuUTT. I f(s)he * does, (s)he is redirected to your application URL with the parameter `code`. * * Let's take a small example: * * Your application "MyApp" (reidrect URL: http://myapp.com) wants to access private data of the current user. * To do so, you need to redirect user to this page: * * `/api/oauth/authorize?response_type=code&client_id=<your_client_id>&scope=public%20private_user_account&state=xyz` * * If the user accept the application, he will be redirected to `http://myapp.com/?code=<authorization_code>`. * * And using this code (in the parameter `code`), you are now able to get an `access_token` using `/api/oauth/token`. * * * If an error occured on the page and the client_id is provided, the user will be redirect to: * `http://myapp.com/?error=<error_type>&error_description=<error_description>` so you can handle the problem. * * @ApiDoc( * section = "OAuth", * description = "Display the authorization page for user to allow a given application", * parameters = { * { * "name" = "client_id", * "required" = true, * "dataType" = "string", * "description" = "Your client ID (given in your developper panel)" * }, * { * "name" = "scope", * "required" = false, * "dataType" = "string", * "description" = "List of the scopes you need for the token, separated by spaces, for instance: `public private_user_account`. If not provided, grant only access to public scope." * }, * { * "name" = "response_type", * "required" = true, * "dataType" = "string", * "description" = "Must be `code` (only authorization_code is supported for the moment)" * }, * { * "name" = "state", * "required" = true, * "dataType" = "string", * "description" = "Must be `xyz` (only authorization_code is supported for the moment)" * } * } * ) * * @Route("/authorize", name="oauth_authorize") * @Method({"GET", "POST"}) * @Template() */ public function authorizeAction(Request $request) { /* * Initialize OAuth */ /** @var EntityManager $em */ $em = $this->getDoctrine()->getManager(); if (!$request->query->has('client_id')) { $this->get('session')->getFlashBag()->set('message', array('type' => 'error', 'message' => 'L\'application externe n\'a pas été trouvée. Vous avez été redirigé vers EtuUTT.')); return $this->redirect($this->generateUrl('homepage')); } // Find the client /** @var OauthClient $client */ $client = $em->getRepository('EtuCoreApiBundle:OauthClient')->findOneBy(['clientId' => $request->query->get('client_id')]); if (!$client) { $this->get('session')->getFlashBag()->set('message', array('type' => 'error', 'message' => 'L\'application externe n\'a pas été trouvée. Vous avez été redirigé vers EtuUTT.')); return $this->redirect($this->generateUrl('homepage')); } // Not logged in if (!$this->getUserLayer()->isConnected()) { $this->get('session')->getFlashBag()->set('message', array('type' => 'error', 'message' => $this->get('translator')->trans('user.api_login.login', ['%name%' => $client->getName()]))); $this->get('session')->set('etu.last_url', $request->getRequestUri()); return $this->redirect($this->generateUrl('user_connect')); } // Logged in but as organization if ($this->getUserLayer()->isOrga()) { $this->get('session')->getFlashBag()->set('message', array('type' => 'error', 'message' => $this->get('translator')->trans('user.api_login.orga'))); return $this->redirect($this->generateUrl('homepage')); } $requestedScopes = ['public']; if ($request->query->has('scopes')) { $requestedScopes = array_unique(array_merge($requestedScopes, explode(' ', $request->query->get('scopes')))); } // Search if user already approved the app $authorization = $em->getRepository('EtuCoreApiBundle:OauthAuthorization')->findOneBy(['client' => $client, 'user' => $this->getUser()]); if ($authorization) { $authorizationScopes = []; foreach ($authorization->getScopes() as $scope) { $authorizationScopes[] = $scope->getName(); } // Compare scopes : if more requested, reask authorization, otherwise redirect $newScopes = array_diff($requestedScopes, $authorizationScopes); if (empty($newScopes)) { $authorizationCode = new OauthAuthorizationCode(); $authorizationCode->setUser($this->getUser()); $authorizationCode->setClient($client); $authorizationCode->generateCode(); foreach ($authorization->getScopes() as $scope) { $authorizationCode->addScope($scope); } $em->persist($authorizationCode); $em->flush(); return $this->redirect($client->getRedirectUri() . '?authorization_code=' . $authorizationCode->getCode()); } } // Scopes $qb = $em->createQueryBuilder(); /** @var OauthScope[] $scopes */ $scopes = $qb->select('s')->from('EtuCoreApiBundle:OauthScope', 's')->where($qb->expr()->in('s.name', $requestedScopes))->orderBy('s.weight', 'ASC')->getQuery()->getResult(); // If the use didn't already approve the app, ask him / her $form = $this->createFormBuilder()->add('accept', 'submit', ['label' => 'Oui, accepter', 'attr' => ['class' => 'btn btn-primary', 'value' => '1']])->add('cancel', 'submit', ['label' => 'Non, annuler', 'attr' => ['class' => 'btn btn-default', 'value' => '0']])->getForm(); if ($request->getMethod() == 'POST' && $form->submit($request)->isValid()) { $formData = $request->request->get('form'); if (isset($formData['accept'])) { // Remove old authorizations $em->createQueryBuilder()->delete()->from('EtuCoreApiBundle:OauthAuthorization', 'a')->where('a.client = :client')->andWhere('a.user = :user')->setParameter('client', $client->getId())->setParameter('user', $this->getUser()->getId())->getQuery()->execute(); $authorizationCode = new OauthAuthorizationCode(); $authorizationCode->setUser($this->getUser()); $authorizationCode->setClient($client); $authorizationCode->generateCode(); /** @var OauthScope[] $defaultScopes */ $defaultScopes = $em->getRepository('EtuCoreApiBundle:OauthScope')->findBy(['isDefault' => true]); foreach ($defaultScopes as $defaultScope) { $authorizationCode->addScope($defaultScope); } foreach ($scopes as $scope) { if (!$scope->getIsDefault()) { $authorizationCode->addScope($scope); } } $em->persist($authorizationCode); // Persist authorization to not ask anymore $em->persist(OauthAuthorization::createFromAuthorizationCode($authorizationCode)); $em->flush(); return $this->redirect($client->getRedirectUri() . '?authorization_code=' . $authorizationCode->getCode()); } else { return $this->redirect($client->getRedirectUri() . '?error=authentification_canceled&error_message=L\'utilisateur a annulé l\'authentification.'); } } return ['client' => $client, 'user' => $client->getUser(), 'scopes' => $scopes, 'form' => $form->createView()]; }
/** * @param OauthAuthorizationCode $code * @return OauthAuthorization */ public static function createFromAuthorizationCode(OauthAuthorizationCode $code) { return new self($code->getClient(), $code->getUser(), $code->getScopes()); }