<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Doctrine\Persistence\ManagerRegistry;
use Ramsey\Uuid\Uuid;
use App\Service\LdapService;
use App\Entity\User;
use App\Entity\Group;
use App\Form\LoginType;
class SecurityController extends AbstractController
{
private $appKernel;
private $tokenstorage;
private $ldapservice;
public function __construct(KernelInterface $appKernel, TokenStorageInterface $tokenstorage, LdapService $ldapservice)
{
$this->appKernel = $appKernel;
$this->tokenstorage = $tokenstorage;
$this->ldapservice = $ldapservice;
}
public function login(Request $request, AuthenticationUtils $authenticationUtils, ManagerRegistry $em)
{
switch ($this->getParameter('mode_auth')) {
case 'SQL':
return $this->loginSQL($request, $authenticationUtils, $em);
break;
case 'CAS':
return $this->loginCAS($request, $authenticationUtils, $em);
break;
case 'LDAP':
return $this->loginLDAP($request, $authenticationUtils, $em);
break;
}
}
public function loginSQL(Request $request, AuthenticationUtils $authenticationUtils, ManagerRegistry $em)
{
return $this->render('Security\loginSQL.html.twig', [
'last_username' => $authenticationUtils->getLastUsername(),
'error' => $authenticationUtils->getLastAuthenticationError(),
'useheader' => false,
'usemenu' => false,
'usesidebar' => false
]);
}
public function loginLDAP(Request $request, AuthenticationUtils $authenticationUtils, ManagerRegistry $em)
{
// Création du formulaire
$form = $this->createForm(LoginType::class);
// Récupération des data du formulaire
$form->handleRequest($request);
// Affichage du formulaire
return $this->render('Security/loginLDAP.html.twig', [
'useheader' => false,
'usemenu' => false,
'usesidebar' => false,
'form' => $form->createView(),
'error' => "",
]);
}
public function ldapcheckuser(Request $request, AuthenticationUtils $authenticationUtils, ManagerRegistry $em)
{
$username = $request->get('login')['username'];
$password = $request->get('login')['password'];
// Récupération de la cible de navigation
$redirect = $request->getSession()->get('_security.main.target_path');
// L'utilisateur se co à l'annuaire
$userldap = $this->ldapservice->userconnect($username, $password);
if ($userldap) {
$user=$em->getRepository("App\Entity\User")->findOneBy(["username"=>$username]);
// Il n'y a pas d'autosubmit / autoupdate : il doit se faire par synchronisation
if($user) {
// Autoconnexion
return $this->autoconnexion($user, $redirect, $request);
}
}
return $this->redirect($this->generateUrl('app_core_login'));
}
public function loginCAS(Request $request, AuthenticationUtils $authenticationUtils, ManagerRegistry $em)
{
// Récupération de la cible de navigation
$redirect = $request->getSession()->get('_security.main.target_path');
// Masteridentity
$masteridentity=$this->getParameter("masteridentity");
// Init Client CAS
// \phpCAS::setDebug("/var/log/phpcas/phpCAS-ninegate.log");
$url=$this->getHost($request);
$url=str_replace("http://",$this->getParameter("protocole")."://",$url);
$url=str_replace("https://",$this->getParameter("protocole")."://",$url);
if($this->getParameter("cas_type")=="client")
@\phpCAS::client(CAS_VERSION_2_0, $this->getParameter('cas_host'), intval($this->getParameter('cas_port')), is_null($this->getParameter('cas_path')) ? '' : $this->getParameter('cas_path'), $url, false);
else
@\phpCAS::proxy(CAS_VERSION_2_0, $this->getParameter('cas_host'), intval($this->getParameter('cas_port')), is_null($this->getParameter('cas_path')) ? '' : $this->getParameter('cas_path'), $url, false);
\phpCAS::setNoCasServerValidation();
// Authentification
\phpCAS::forceAuthentication();
// Récupération UID
$username = \phpCAS::getUser();
// Récupération Attribut
$attributes = \phpCAS::getAttributes();
// Init
$email = "";
$lastname = "";
$firstname = "";
// Rechercher l'utilisateur
if(isset($attributes[$this->getParameter('user_attr_cas_username')]))
$username = $attributes[$this->getParameter('user_attr_cas_username')];
if(isset($attributes[$this->getParameter('user_attr_cas_mail')]))
$email = $attributes[$this->getParameter('user_attr_cas_mail')];
if(isset($attributes[$this->getParameter('user_attr_cas_lastname')]))
$lastname = $attributes[$this->getParameter('user_attr_cas_lastname')];
if(isset($attributes[$this->getParameter('user_attr_cas_firstname')]))
$firstname = $attributes[$this->getParameter('user_attr_cas_firstname')];
$user = $em->getRepository('App\Entity\User')->findOneBy(array("username"=>$username));
$exists = $user ? true : false;
if (!$exists) {
if($masteridentity=="SQL") {
// C'est pas normal que l'on puisse se connecter alors que l'utilisateur n'est pas connu en base
// La base étant le maitre de l'identité
throw $this->createNotFoundException('Permission denied');
}
if($masteridentity=="LDAP") {
// Normalement la synchronisation des comptes aurait du générer le compte en base c'est donc pas normal
// Peut-être juste relancer une synchronisation
// On tente une synchronisation via methode SSO
$masteridentity="SSO";
// throw $this->createNotFoundException('Permission denied. Need to synchronize LDAP ? Contact your administrator');
}
if($masteridentity=="SSO") {
if(empty($email)) $email = $username."@nomail.com";
// On s'assure qu'il n'y a pas déjà un utilisateur avec le même mail
$usermail = $em->getRepository('App\Entity\User')->findOneBy(array("email"=>$email));
if($usermail) {
return $this->render('App\Entity\Registration:info.html.twig', [
'useheader' => true,
'usemenu' => false,
'usesidebar' => false,
'infotitle' => "Première connexion",
'info' => "Votre compte ne peut être activé car votre adresse mel est déjà utilisée par un autre compte utilisateur.<br>Nous sommes désolés du désagrément et vous invitons à contacter un administrateur.",
'mode' => "error",
'redirectto' => "",
]);
}
// Là c'est normal que potentiellement il n'existe pas il faut donc l'autogénérer
$user = new User();
// On calcule le niveau01 de l'utilisateur
$niveau01=$em->getRepository('App\Entity\Niveau01')->calculateNiveau01($attributes);
if(!$niveau01) {
$niveau01=$em->getRepository('App\Entity\Niveau01')->findAll()[0];
//throw $this->createNotFoundException('Permission denied. No Organisation Niveau 01 match');
}
$user->setUsername($username);
$user->setEmail($email);
$user->setLastname($lastname);
$user->setFirstname($firstname);
$user->setPassword("CASPWD-".$username);
$user->setSalt("CASPWD-".$username);
$user->setApikey(Uuid::uuid4());
$user->setNiveau01($niveau01);
$user->setSiren($niveau01->getSiren());
$user->setSiret("");
$user->setAvatar("noavatar.png");
$user->setVisible(true);
$user->setAuthlevel("simple");
$user->setBelongingpopulation("agent");
$user->setRole("ROLE_USER");
if(in_array($username,$this->getParameter("ldap_usersadmin")))
$user->setRole("ROLE_ADMIN");
$em->getManager()->persist($user);
$em->getManager()->flush();
// Génération auto des groupes
$this->submitGroup($em,$attributes);
// On calcule les groupes de l'utilisateur
$user=$em->getRepository('App\Entity\Group')->calculateGroup($user,$attributes);
}
}
else {
// Mise à jour des valeurs uniquement si le maitre de l'identité est le SSO
if($masteridentity=="SSO") {
// On calcule le niveau01 de l'utilisateur
$niveau01=$em->getRepository('App\Entity\Niveau01')->calculateNiveau01($attributes);
if(!$niveau01)
throw $this->createNotFoundException('Permission denied. No Organisation Niveau 01 match');
// On s'assure que le niveau 02 appartient bien au niveau 01 calculé
$sameniveau01=(!is_null($user->getNiveau02())&&$niveau01==$user->getNiveau02()->getNiveau01());
$user->setLastname($lastname);
$user->setFirstname($firstname);
$user->setEmail($email);
if(!$sameniveau01) {
$user->setNiveau01($niveau01);
$user->setNiveau02(null);
}
if(in_array($username,$this->getParameter("ldap_usersadmin")))
$user->setRole("ROLE_ADMIN");
// Génération auto des groupes
$this->submitGroup($em,$attributes);
// On calcule les groupes de l'utilisateur
$user=$em->getRepository('App\Entity\Group')->calculateGroup($user,$attributes);
$em->getManager()->flush();
}
}
// Sauvegarde des attributes en session
$request->getSession()->set('attributes', $attributes);
// Sauvegarde des ssoitems en session
$ssoitems=[];
if($this->getParameter('ssosynchroitem')) {
$user_attr_cas_item=$this->getParameter('user_attr_cas_item');
if(array_key_exists($user_attr_cas_item,$attributes)) {
if(!is_array($attributes[$user_attr_cas_item])) {
$attributes[$user_attr_cas_item]=[$attributes[$user_attr_cas_item]];
}
$ssoitems=$attributes[$user_attr_cas_item];
}
}
$request->getSession()->set('ssoitems', $ssoitems);
// Autoconnexion
return $this->autoconnexion($user, $redirect, $request);
}
public function logout(Request $request)
{
$auth_mode = $this->getParameter('mode_auth');
switch ($auth_mode) {
case 'SQL':
return $this->logoutSQL($request);
break;
case 'CAS':
return $this->logoutCAS($request);
break;
case 'LDAP':
return $this->logoutLDAP($request);
break;
case 'OPENID':
return $this->logoutOPENID($request);
break;
}
}
public function logoutSQL(Request $request)
{
$this->tokenstorage->setToken(null);
$request->getSession()->invalidate();
return $this->redirectToRoute('app_core_home');
}
public function logoutCAS(Request $request)
{
// Init Client CAS
// \phpCAS::setDebug("/var/log/phpcas/phpCAS-ninegate.log");
$url=$this->getHost($request);
$url=str_replace("http://",$this->getParameter("protocole")."://",$url);
$url=str_replace("https://",$this->getParameter("protocole")."://",$url);
\phpCAS::client(CAS_VERSION_2_0, $this->getParameter('cas_host'), intval($this->getParameter('cas_port')), is_null($this->getParameter('cas_path')) ? '' : $this->getParameter('cas_path'), $url, false);
\phpCAS::setNoCasServerValidation();
// Logout
$url = $this->generateUrl('app_core_home', [], UrlGeneratorInterface::ABSOLUTE_URL);
$url=str_replace("http://",$this->getParameter("protocole")."://",$url);
$url=str_replace("https://",$this->getParameter("protocole")."://",$url);
\phpCAS::logout(['service' => $url]);
$this->tokenstorage->setToken(null);
$request->getSession()->invalidate();
return true;
}
public function logoutLDAP(Request $request)
{
$this->tokenstorage->setToken(null);
$request->getSession()->invalidate();
return $this->redirectToRoute('app_core_home');
}
public function checkuser(Request $request)
{
$userapp = $this->getUser();
$fgforceconnect = $request->getSession()->get('fgforceconnect');
$modeauth=$this->getParameter('mode_auth');
if(is_null($userapp) && $fgforceconnect) {
return new Response("<script>window.location.href='".$this->generateUrl("app_core_login")."';</script>");
}
else
{
// Mode d'authentification
switch($modeauth) {
case "CAS":
// Init Client CAS
$url=$this->getHost($request);
$url=str_replace("http://",$this->getParameter("protocole")."://",$url);
$url=str_replace("https://",$this->getParameter("protocole")."://",$url);
\phpCAS::client(CAS_VERSION_2_0, $this->getParameter('cas_host'), intval($this->getParameter('cas_port')), is_null($this->getParameter('cas_path')) ? '' : $this->getParameter('cas_path'), $url, false);
\phpCAS::setNoCasServerValidation();
if(\phpCAS::checkAuthentication()) {
$usercas = \phpCAS::getUser();
// si on a un usercas mais pas de userapp c'est qu'il faut s'autoconnect
if(!$userapp) {
$url=$this->generateUrl('app_core_login');
return new Response(
'<script>document.location.replace("'.$url.'");</script>'
);
}
}
break;
}
}
return new Response();
}
private function autoconnexion($user, $redirect, Request $request)
{
// Récupérer le token de l'utilisateur
$token = new UsernamePasswordToken($user, 'main', $user->getRoles());
$this->tokenstorage->setToken($token);
$request->getSession()->set('_security_main', serialize($token));
// Simuler l'evenement de connexion
$event = new InteractiveLoginEvent($request, $token);
$dispatcher = new EventDispatcher();
$dispatcher->dispatch($event);
// Redirection
if ($redirect) {
return $this->redirect($redirect);
} else {
return $this->redirect($this->generateUrl('app_core_home'));
}
}
private function submitGroup($em,$attributes) {
if(!$this->getParameter('ssosynchrogroup'))
return null;
$user_attr_cas_group=$this->getParameter('user_attr_cas_group');
// Si l'utilisateur possège l'attribut groupe dans ses attributs
if(array_key_exists($user_attr_cas_group,$attributes)) {
if(!is_array($attributes[$user_attr_cas_group])) {
$attributes[$user_attr_cas_group]=[$attributes[$user_attr_cas_group]];
}
foreach($attributes[$user_attr_cas_group] as $ssogroup) {
$basedn=$this->getParameter('ldap_basedn');
$name=$ssogroup;
if($basedn!="") {
// Si présence du basedn dans le nom du groupe = nous sommes en présence d'un DN = on récupere donc comme nom que son cn
if(stripos($name,$basedn)!==false) {
$tbname=explode(",",$name);
$tbname=explode("=",$tbname[0]);
$name=$tbname[1];
}
}
// Recherche du groupe
$group=$em->getRepository("App\Entity\Group")->findOneBy(["label"=>$name]);
if(!$group) {
$group=new Group();
$group->setLabel($name);
$group->setFgcancreatepage(false);
$group->setFgcancreateblog(false);
$group->setFgcancreatecalendar(false);
$group->setFgcancreateproject(false);
$group->setFgcanshare(false);
$group->setFgopen(false);
$group->setFgall(false);
}
$group->setAttributes('{"'.$user_attr_cas_group.'":"'.$ssogroup.'"}');
$group->setFgtemplate(false);
$em->getManager()->persist($group);
$em->getManager()-> flush();
}
}
}
public function imapunread(Request $request) {
if($this->getParameter("active_imapunread")&&$this->getParameter("cas_type")=="proxy") {
$ip=$this->getParameter("imapundread_ip");
// Init Client CAS
// \phpCAS::setDebug("/var/log/phpcas/phpCAS-ninegate.log");
@\phpCAS::proxy(CAS_VERSION_2_0, $this->getParameter('cas_host'), intval($this->getParameter('cas_port')), is_null($this->getParameter('cas_path')) ? '' : $this->getParameter('cas_path'), $this->getHost($request), false);
\phpCAS::setNoCasServerValidation();
\phpCAS::forceAuthentication();
$pt= \phpCAS::retrievePT('imap://'.$ip,$t,$f);
$a = \phpCAS::serviceMail("{".$ip.":993/imap/ssl/novalidate-cert}","imap://".$ip,0, $errc,$err,$pt);
$unseen = imap_status($a, "{".$ip.":993/imap/ssl/novalidate-cert}INBOX", SA_UNSEEN);
$count=$unseen->unseen;
$response = new JsonResponse($count);
}
else
$response = new JsonResponse("");
return $response;
}
public function redirectroute(Request $request, $route, $id) {
if($route=="app_core_home")
return $this->redirectToRoute($route,["id"=>$id]);
else
return $this->redirectToRoute("app_core_home",["gotoroute"=>$route,"gotoid"=>$id]);
}
private function getHost($request) {
$host = $request->getHost();
$protocol = $request->getScheme();
$port = $request->getPort();
return $protocol."://".$host.($port!=80&&$port!=443?":".$port:"");
}
}