src/Security/KeycloakAuthenticator.php line 21

Open in your IDE?
  1. <?php
  2. namespace App\Security;
  3. use App\Entity\Company;
  4. use App\Entity\Log;
  5. use App\Entity\Role;
  6. use App\Entity\User;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
  9. use KnpU\OAuth2ClientBundle\Client\OAuth2ClientInterface;
  10. use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator;
  11. use Symfony\Component\HttpFoundation\RedirectResponse;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Routing\RouterInterface;
  15. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  16. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  17. use Symfony\Component\Security\Core\User\UserProviderInterface;
  18. class KeycloakAuthenticator extends SocialAuthenticator
  19. {
  20.     private ClientRegistry $clientRegistry;
  21.     private EntityManagerInterface $em;
  22.     private RouterInterface $router;
  23.     public function __construct(ClientRegistry $clientRegistryEntityManagerInterface $emRouterInterface $router)
  24.     {
  25.         $this->clientRegistry $clientRegistry;
  26.         $this->em $em;
  27.         $this->router $router;
  28.     }
  29.     public function start(Request $requestAuthenticationException $authException null)
  30.     {
  31.         return new RedirectResponse(
  32.             '/login'// might be the site, where users choose their oauth provider
  33.             Response::HTTP_TEMPORARY_REDIRECT
  34.         );
  35.     }
  36.     public function supports(Request $request)
  37.     {
  38.         return 'openid_check_auth' === $request->attributes->get('_route');
  39.     }
  40.     public function getCredentials(Request $request)
  41.     {
  42.         return $this->fetchAccessToken($this->getKeycloakClient());
  43.     }
  44.     public function getUser($credentialsUserProviderInterface $userProvider)
  45.     {
  46.         $keycloakUser $this->getKeycloakClient()->fetchUserFromToken($credentials);
  47.         $existingUser $this
  48.             ->em
  49.             ->getRepository(User::class)
  50.             ->findOneBy(['keycloakId' => $keycloakUser->getId()]);
  51.         if ($existingUser) {
  52.             return $existingUser;
  53.         }
  54.         // if user exist but never connected with keycloak
  55.         $email $keycloakUser->getEmail();
  56.         /** @var User $userInDatabase */
  57.         $userInDatabase $this->em->getRepository(User::class)
  58.             ->findOneBy(['email' => $email]);
  59.         if($userInDatabase) {
  60.             $userInDatabase->setKeycloakId($keycloakUser->getId());
  61.             $this->em->persist($userInDatabase);
  62.             $this->em->flush();
  63.             return $userInDatabase;
  64.         }
  65.         $keycloakUserArray $keycloakUser->toArray();
  66.         //user not exist in database =======> CREATE
  67.         $user = new User();
  68.         $user->setKeycloakId($keycloakUser->getId());
  69.         $user->setEmail($keycloakUser->getEmail());
  70.         //Roles
  71.         if(isset($keycloakUserArray['roles'])){
  72.             if(in_array('kinalgo-user',$keycloakUserArray['roles'])){
  73.                 $user_role $this->em->getRepository(Role::class)->findOneBy(['name' => User::ROLE_USER_ACTIF]);
  74.             }
  75.             else if(in_array('kinalgo-rh',$keycloakUserArray['roles'])){
  76.                 $user_role $this->em->getRepository(Role::class)->findOneBy(['name' => 'ROLE_RH']);
  77.             }
  78.             else if(in_array('kinalgo-admin',$keycloakUserArray['roles'])){
  79.                 $user_role $this->em->getRepository(Role::class)->findOneBy(['name' => 'ROLE_ADMIN']);
  80.             }
  81.             else{
  82.                 $user_role $this->em->getRepository(Role::class)->findOneBy(['name' => User::ROLE_USER_ACTIF]);
  83.             }
  84.         }
  85.         else{
  86.             $user_role $this->em->getRepository(Role::class)->findOneBy(['name' => User::ROLE_USER_ACTIF]);
  87.         }
  88.         $user->setRoles($user_role);
  89.         //company
  90.         if(isset($keycloakUserArray['groups'])){
  91.             $companyName str_replace('/',"",$keycloakUserArray['groups'][0]);
  92.             $company $this->em->getRepository(Company::class)->findOneBy(['slug' => trim($companyName)]);
  93.         }
  94.         if(!isset($company) || !$company) return false;
  95.         if($company){
  96.             $user->setCompany($company);
  97.         }
  98.         $user->setFirstname($keycloakUserArray['given_name']);
  99.         $user->setLastname($keycloakUserArray['family_name']);
  100.         $this->em->persist($user);
  101.         $this->em->flush();
  102.         return $user;
  103.     }
  104.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception)
  105.     {
  106.         $message strtr($exception->getMessageKey(), $exception->getMessageData());
  107.         return new Response($messageResponse::HTTP_FORBIDDEN);
  108.     }
  109.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $providerKey)
  110.     {
  111.         /* @var $user User*/
  112.         $user $token->getUser();
  113.         if($user->getLastLoginAt() !== null){
  114.             $this->setLastLoginAt($user);
  115.             $targetUrl $this->router->generate('user_dashboard');
  116.         }
  117.         else{
  118.             $this->setLastLoginAt($user);
  119.             $targetUrl $this->router->generate('profil');
  120.         }
  121.         return new RedirectResponse($targetUrl);
  122.     }
  123.     /**
  124.      * @return OAuth2ClientInterface
  125.      */
  126.     private function getKeycloakClient()
  127.     {
  128.         return $this->clientRegistry->getClient('keycloak');
  129.     }
  130.     private function  setLastLoginAt($user){
  131.         //TODO à voir si on garde le champ lastLoginAt ou si on utilise celui des logs
  132.         $date = new \DateTime("now", new \DateTimeZone("Europe/Paris"));
  133.         $user->setLastLoginAt($date);
  134.         $this->em->persist($user);
  135.         //Persistence en BD pour les stats - date sur createdAt
  136.         $log =  new Log();
  137.         $log->setUser$user );
  138.         $log->setEvent('login');
  139.         $log->setSources(['ip'=>$_SERVER['REMOTE_ADDR'],'date'=>$date->format('Y-m-d H:i')]);
  140.         $this->em->persist($log);
  141.         $this->em->flush();
  142.     }
  143. }