factorisation

This commit is contained in:
Rudy Masson 2022-05-03 15:09:42 +02:00
parent f9a6535906
commit 98733f3a01
10 changed files with 114 additions and 153 deletions

View File

@ -4,16 +4,20 @@
# Put parameters here that don't need to change on each machine where the app is deployed # Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters: parameters:
fetchDatas: "lastname, firstname, email, random " fetchDatas: "lastname, firstname, email, random"
# Paramètres de connexion base de données: "nome du serveur", "nom utilisateur", "mot de passe", "nom de la bdd", "port" # Paramètres de connexion base de données: "nome du serveur", "nom utilisateur", "mot de passe", "nom de la bdd", "port"
urlDatabase: "%env(resolve:urlDatabase)%" urlDatabase: "%env(resolve:urlDatabase)%"
dbUser: "%env(resolve:dbUser)%" dbUser: "%env(resolve:dbUser)%"
dbPassword: "%env(resolve:dbPassword)%" dbPassword: "%env(resolve:dbPassword)%"
queryHashPassword: "%env(resolve:queryHashPassword)%" queryHashPassword: "%env(resolve:queryHashPassword)%"
queryFetchDatas: "%env(resolve:queryFetchDatas)%"
hashMethod: hashMethod:
passwordColumnName: "password" passwordColumnName: "password"
userTableName: "USER" userTableName: "USER"
emailColumnName: "email" emailColumnName: "email"
urlLogoutSuccess: "http://portal.mse.local:8000/logout-success"
urlIssuer:
- "http://portal.mse.local:8000/"
url_login_challenge: '%env(resolve:url_login_challenge)%' url_login_challenge: '%env(resolve:url_login_challenge)%'
url_login_challenge_reject: '%env(resolve:url_login_challenge_reject)%' url_login_challenge_reject: '%env(resolve:url_login_challenge_reject)%'

View File

@ -14,14 +14,21 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class MainController extends AbstractController class MainController extends AbstractController
{ {
/** /**
* @var Session * @var Session
*/ */
private $session; private $session;
/**
* @var UrlGeneratorInterface
*/
private $router;
/** /**
* @var HttpClientInterface * @var HttpClientInterface
@ -29,11 +36,12 @@ class MainController extends AbstractController
public $client; public $client;
private $pdoServices; private $pdoServices;
public function __construct(PdoServices $pdoServices, HttpClientInterface $client, SessionInterface $session) public function __construct(PdoServices $pdoServices, HttpClientInterface $client, SessionInterface $session, UrlGeneratorInterface $router)
{ {
$this->pdoServices = $pdoServices; $this->pdoServices = $pdoServices;
$this->session = $session; $this->session = $session;
$this->client = $client; $this->client = $client;
$this->router = $router;
} }
/** /**
@ -67,45 +75,46 @@ class MainController extends AbstractController
*/ */
public function oauth(Request $request) public function oauth(Request $request)
{ {
if( $request->headers->get('referer') !== $this->router->generate('oauth_login', [], 0) && !in_array($request->headers->get('referer'), $this->getParameter('urlIssuer'))){
throw new BadRequestException('Vous devez passer par le issuer pour vous connecter');
}
$user = new User(); $user = new User();
$loginForm = $this->createForm(UserType::class, $user); $loginForm = $this->createForm(UserType::class, $user);
$loginForm->handleRequest($request); $loginForm->handleRequest($request);
if($loginForm->isSubmitted() && $loginForm->isValid()){ if($loginForm->isSubmitted() && $loginForm->isValid()){
$email = $loginForm->get('email')->getData(); $email = $loginForm->get('email')->getData();
$dbh = $this->pdoServices->connection();
try { try {
//requête préparée // requête préparée
$query = $dbh->prepare($this->getParameter("queryHashPassword")."'".$email ."';"); $datas = $this->pdoServices->fetchDatas($email);
$query->execute();
$hashPassword = $query->fetch(PDO::FETCH_ASSOC);
if(!$hashPassword){ if(!$datas){
// Si le hash du password n'est pas trouvé, c'est que l'email n'existe pas, on retourne la page de login avec une erreur // Si le hash du password n'est pas trouvé, c'est que l'email n'existe pas, on retourne la page de login avec une erreur
return $this->render('login.html.twig', [ return $this->render('login.html.twig', [
'form'=>$loginForm->createView(), "form" => $loginForm->createView(),
"error"=> "mail non trouvé", "error_mail" => "mail non trouvé",
]); ]);
} }
$hashPassword = array_values($hashPassword)[0]; $hashPassword = $datas[$this->getParameter('passwordColumnName')];
$password = $loginForm->get('password')->getData(); $password = $loginForm->get('password')->getData();
if($this->pdoServices->verifyPassword($password, $hashPassword)){ if($this->pdoServices->verifyPassword($password, $hashPassword)){
$this->session->set('datas', $this->pdoServices->fetchDatas($email)); unset($datas[$this->getParameter('passwordColumnName')]);
$this->session->set('datas', $datas);
$response = $this->client->request('PUT', $this->getParameter('url_login_challenge_accept').$this->session->get('challenge'), [ $response = $this->client->request('PUT', $this->getParameter('url_login_challenge_accept').$this->session->get('challenge'), [
'json' => [ 'json' => [
'subject' => $email, 'subject' => $email,
], ],
]); ]);
// On initie l'acceptation du login challenge émis par hydra et on récupère l'url de redirection // On initie l'acceptation du login challenge émis par hydra et on récupère l'url de redirection
// dd($response->toArray());
$redirect_to = $response->toArray()['redirect_to']; $redirect_to = $response->toArray()['redirect_to'];
return $this->redirect($redirect_to, 301); return $this->redirect($redirect_to, 301);
}else{ }else{
return $this->render('login.html.twig', [ return $this->render('login.html.twig', [
'form'=>$loginForm->createView(), 'form'=>$loginForm->createView(),
"error"=> "Le mot de passe est incorrect" "error_password"=> "Le mot de passe est incorrect"
]); ]);
} }
@ -113,14 +122,9 @@ class MainController extends AbstractController
}catch (\Exception $e){ }catch (\Exception $e){
dd($e); dd($e);
} }
// $rememberMe = $loginForm->get('rememberMe')->getData();
} }
return $this->render('login.html.twig', [ return $this->render('login.html.twig', [
'form'=>$loginForm->createView(), 'form'=>$loginForm->createView(),
"error_mail"=>false,
"error_password"=>false
]); ]);
} }
@ -162,4 +166,14 @@ class MainController extends AbstractController
return $this->redirect($redirect_to, 301); return $this->redirect($redirect_to, 301);
} }
/**
* @Route("/oauth/logout", name="app_logout")
*/
public function logout()
{
$this->session->clear();
return $this->redirect($this->getParameter('urlLogoutSuccess'));
}
} }

View File

@ -3,19 +3,13 @@
namespace App\Entity; namespace App\Entity;
use App\Validator as AcmeAssert; use App\Validator as AcmeAssert;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface class User
{ {
/** private string $email;
* @AcmeAssert\ExistingEmail()
*/
private $email;
private $password; private string $password;
private $datas; private string $rememberMe;
private $rememberMe;
private $roles;
public function getEmail(): ?string public function getEmail(): ?string
{ {
@ -29,7 +23,6 @@ class User implements UserInterface
return $this; return $this;
} }
public function getPassword(): string public function getPassword(): string
{ {
return $this->password; return $this->password;
@ -42,20 +35,6 @@ class User implements UserInterface
return $this; return $this;
} }
public function addData($data): self
{
if (!$this->datas->contains($data)) {
$this->datas[] = $data;
}
return $this;
}
public function getDatas()
{
return $this->datas;
}
public function getRememberMe(): string public function getRememberMe(): string
{ {
return $this->rememberMe; return $this->rememberMe;
@ -67,36 +46,4 @@ class User implements UserInterface
return $this; return $this;
} }
public function getUserIdentifier()
{
return $this->email;
}
public function getRoles(){
return $this->roles;
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
public function getSalt(){
return '';
}
public function eraseCredentials(){
return $this;
}
public function getUsername(){
return $this->email;
}
public function __toString()
{
return $this->email;
}
} }

View File

@ -18,6 +18,7 @@ class UserType extends AbstractType
{ {
$builder $builder
->add('email', EmailType::class, [ ->add('email', EmailType::class, [
"required"=>true
]) ])
->add("password", PasswordType::class, [ ->add("password", PasswordType::class, [
"attr" => ["class" => "password-field"], "attr" => ["class" => "password-field"],

View File

@ -25,7 +25,9 @@ class PdoServices extends AbstractController
{ {
try { try {
$dbh = $this->connection(); $dbh = $this->connection();
$datas = $dbh->query("SELECT " . $this->getParameter('fetchDatas'). " from USER where email = '" . $email . "';")->fetch(PDO::FETCH_ASSOC); $query = $dbh->prepare($this->getParameter('queryFetchDatas'));
$query->execute(['email'=> $email]);
$datas = $query->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) { } catch (PDOException $e) {
print "Erreur !: " . $e->getMessage() . "<br/>"; print "Erreur !: " . $e->getMessage() . "<br/>";
@ -48,9 +50,6 @@ class PdoServices extends AbstractController
default: default:
return password_verify($password, $hashedPassword); return password_verify($password, $hashedPassword);
break; break;
} }
} }

View File

@ -1,18 +0,0 @@
<?php
namespace App\Validator;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class ExistingEmail extends Constraint
{
public $message = 'Le mail "{{ string }}" n\'existe pas.';
public function validatedBy()
{
return static::class.'Validator';
}
}

View File

@ -1,48 +0,0 @@
<?php
namespace App\Validator;
use PDO;
use App\Services\PdoServices;
use App\Validator\ExistingEmail;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class ExistingEmailValidator extends ConstraintValidator
{
private PdoServices $pdoServices;
public $params;
public function __construct(PdoServices $pdoServices, ParameterBagInterface $params)
{
$this->pdoServices = $pdoServices;
$this->params = $params;
}
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof ExistingEmail) {
throw new UnexpectedTypeException($constraint, ExistingEmail::class);
}
// custom constraints should ignore null and empty values to allow
// other constraints (NotBlank, NotNull, etc.) to take care of that
if (null === $value || '' === $value) {
return;
}
$dbh = $this->pdoServices->connection();
$query = $dbh->prepare($this->params->get("queryHashPassword")."'".$value ."';");
$query->execute();
$hashPassword = $query->fetch(PDO::FETCH_ASSOC);
if(!$hashPassword){
$this->context->buildViolation(
$constraint->message
)->setParameter('{{ string }}', $value)
->addViolation()
;
}
}
}

View File

@ -4248,3 +4248,55 @@
2022-05-02 15:14:44,772 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2022-05-02 15:14:44,772 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-02 15:14:44,773 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2022-05-02 15:14:44,773 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-02 15:14:44,773 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2022-05-02 15:14:44,773 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 10:10:40,758 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2022-05-03 10:10:41,070 INFO RPC interface 'supervisor' initialized
2022-05-03 10:10:41,071 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2022-05-03 10:10:41,071 INFO supervisord started with pid 13
2022-05-03 10:10:42,073 INFO spawned: 'apache2' with pid 14
2022-05-03 10:10:42,074 INFO spawned: 'php-fpm' with pid 15
2022-05-03 10:10:42,075 INFO spawned: 'rsyslog' with pid 16
2022-05-03 10:10:43,153 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 10:10:43,153 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 10:10:43,154 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:34:50,492 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2022-05-03 11:34:50,494 INFO RPC interface 'supervisor' initialized
2022-05-03 11:34:50,494 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2022-05-03 11:34:50,494 INFO supervisord started with pid 25
2022-05-03 11:34:51,497 INFO spawned: 'apache2' with pid 26
2022-05-03 11:34:51,499 INFO spawned: 'php-fpm' with pid 27
2022-05-03 11:34:51,500 INFO spawned: 'rsyslog' with pid 28
2022-05-03 11:34:52,524 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:34:52,524 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:34:52,524 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:43:10,052 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2022-05-03 11:43:10,054 INFO RPC interface 'supervisor' initialized
2022-05-03 11:43:10,054 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2022-05-03 11:43:10,054 INFO supervisord started with pid 26
2022-05-03 11:43:11,057 INFO spawned: 'apache2' with pid 27
2022-05-03 11:43:11,058 INFO spawned: 'php-fpm' with pid 28
2022-05-03 11:43:11,059 INFO spawned: 'rsyslog' with pid 29
2022-05-03 11:43:12,075 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:43:12,075 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:43:12,075 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:54:33,580 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2022-05-03 11:54:33,885 INFO RPC interface 'supervisor' initialized
2022-05-03 11:54:33,885 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2022-05-03 11:54:33,885 INFO supervisord started with pid 12
2022-05-03 11:54:34,889 INFO spawned: 'apache2' with pid 13
2022-05-03 11:54:34,892 INFO spawned: 'php-fpm' with pid 14
2022-05-03 11:54:34,895 INFO spawned: 'rsyslog' with pid 15
2022-05-03 11:54:35,921 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:54:35,921 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 11:54:35,922 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 14:32:10,672 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2022-05-03 14:32:10,978 INFO RPC interface 'supervisor' initialized
2022-05-03 14:32:10,978 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2022-05-03 14:32:10,979 INFO supervisord started with pid 12
2022-05-03 14:32:11,981 INFO spawned: 'apache2' with pid 13
2022-05-03 14:32:11,984 INFO spawned: 'php-fpm' with pid 14
2022-05-03 14:32:11,985 INFO spawned: 'rsyslog' with pid 15
2022-05-03 14:32:11,997 INFO exited: rsyslog (exit status 1; not expected)
2022-05-03 14:32:13,008 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 14:32:13,009 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2022-05-03 14:32:13,011 INFO spawned: 'rsyslog' with pid 77
2022-05-03 14:32:14,019 INFO success: rsyslog entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

View File

@ -1 +1 @@
25 12

View File

@ -22,7 +22,7 @@
display:flex; display:flex;
flex-direction: column; flex-direction: column;
} }
.form-errors{ .form-error{
color: red; color: red;
} }
@ -32,11 +32,21 @@
{% block body %} {% block body %}
<div class="wrapper"> <div class="wrapper">
{{ form_start(form)}} {{ form_start(form)}}
<div class="form-errors"> <div class="mb-3">
{% if error is defined %}{{ error }}{% endif %} {{ form_row(form.email) }}
{% if error_mail is defined %}
<div class="form-text form-error">{{ error_mail }}</div>
{% endif %}
</div>
<div class="mb-3">
{{ form_row(form.password) }}
{% if error_password is defined %}
<div class="form-text form-error">{{ error_password }}</div>
{% endif %}
</div>
<div class="mb-3 form-check">
{{ form_row(form.rememberMe) }}
</div> </div>
{{ form_widget(form)}}
<button type="submit" class="btn btn-success">valider</button> <button type="submit" class="btn btn-success">valider</button>
{{ form_end(form)}} {{ form_end(form)}}
</div> </div>