login consent app sql
This commit is contained in:
@ -3,11 +3,163 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use PDO;
|
||||
use App\Entity\User;
|
||||
use App\Form\UserType;
|
||||
use App\Services\PdoServices;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||
|
||||
class MainController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var Session
|
||||
*/
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* @var HttpClientInterface
|
||||
*/
|
||||
public $client;
|
||||
private $pdoServices;
|
||||
|
||||
public function __construct(PdoServices $pdoServices, HttpClientInterface $client, SessionInterface $session)
|
||||
{
|
||||
$this->pdoServices = $pdoServices;
|
||||
$this->session = $session;
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/oauth/login", name="app_login")
|
||||
*/
|
||||
public function loginOidc(Request $request)
|
||||
{
|
||||
$challenge = $request->query->get('login_challenge');
|
||||
// S'il n'y a pas de challenge, on déclenche une bad request
|
||||
if(!$challenge){
|
||||
throw new BadRequestException('pas de challenge');
|
||||
}
|
||||
//On vérifie que la requête d'identification provient bien de hydra
|
||||
$response = $this->client->request('GET', $this->getParameter('url_login_challenge').$challenge, [
|
||||
'headers' => [
|
||||
'Content-Type: application/json',
|
||||
],
|
||||
]);
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
$this->session->clear();
|
||||
throw new BadRequestException('pa de code 200');
|
||||
}
|
||||
// si le challenge est validé par hydra, on le stocke en session pour l'utiliser par la suite et on redirige vers une route interne protégée qui va déclencher l'identification FranceConnect
|
||||
$this->session->set('challenge', $challenge);
|
||||
|
||||
return $this->redirectToRoute('oauth_login');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/oauth/connect", name="oauth_login")
|
||||
*/
|
||||
public function oauth(Request $request)
|
||||
{
|
||||
$user = new User();
|
||||
$loginForm = $this->createForm(UserType::class, $user);
|
||||
$loginForm->handleRequest($request);
|
||||
if($loginForm->isSubmitted() && $loginForm->isValid()){
|
||||
$email = $loginForm->get('email')->getData();
|
||||
$dbh = $this->pdoServices->connection();
|
||||
try {
|
||||
//requête préparée
|
||||
$query = $dbh->prepare($this->getParameter("queryHashPassword")."'".$email ."';");
|
||||
$query->execute();
|
||||
$hashPassword = $query->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if(!$hashPassword){
|
||||
// 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', [
|
||||
'form'=>$loginForm->createView(),
|
||||
"error"=> "mail non trouvé",
|
||||
|
||||
]);
|
||||
}
|
||||
$hashPassword = array_values($hashPassword)[0];
|
||||
$password = $loginForm->get('password')->getData();
|
||||
|
||||
if($this->pdoServices->verifyPassword($password, $hashPassword)){
|
||||
$this->session->set('datas', $this->pdoServices->fetchDatas($email));
|
||||
$response = $this->client->request('PUT', $this->getParameter('url_login_challenge_accept').$this->session->get('challenge'), [
|
||||
'json' => [
|
||||
'subject' => $email,
|
||||
],
|
||||
]);
|
||||
// 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'];
|
||||
return $this->redirect($redirect_to, 301);
|
||||
|
||||
}else{
|
||||
return $this->render('login.html.twig', [
|
||||
'form'=>$loginForm->createView(),
|
||||
"error"=> "Le mot de passe est incorrect"
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
}catch (\Exception $e){
|
||||
dd($e);
|
||||
}
|
||||
// $rememberMe = $loginForm->get('rememberMe')->getData();
|
||||
|
||||
}
|
||||
|
||||
return $this->render('login.html.twig', [
|
||||
'form'=>$loginForm->createView(),
|
||||
"error_mail"=>false,
|
||||
"error_password"=>false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/oauth/consent", name="consent")
|
||||
*/
|
||||
public function consent(Request $request)
|
||||
{
|
||||
$challenge = $request->query->get('consent_challenge');
|
||||
if (!$challenge) {
|
||||
throw new BadRequestException("Le challenge n'est pas disponible");
|
||||
}
|
||||
|
||||
// Vérification du consent_challenge avec hydra
|
||||
$response = $this->client->request('GET', $this->getParameter('url_consent_challenge').$challenge, [
|
||||
'headers' => [
|
||||
'Content-Type: application/json',
|
||||
],
|
||||
]);
|
||||
if(200!== $response->getStatusCode()){
|
||||
$this->session->clear();
|
||||
throw new BadRequestException("Le challenge n'est pas authorisé");
|
||||
}
|
||||
$response = $this->client->request('PUT', $this->getParameter('url_consent_challenge_accept').$challenge, [
|
||||
'headers' => [
|
||||
'Content-Type: application/json',
|
||||
],
|
||||
'json' => [
|
||||
'grant_scope' => ['openid', 'offline_access'],
|
||||
'session' => [
|
||||
'id_token' => [
|
||||
'user' => $this->session->get('datas'),
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$redirect_to = $response->toArray()['redirect_to'];
|
||||
|
||||
return $this->redirect($redirect_to, 301);
|
||||
|
||||
}
|
||||
}
|
102
src/Entity/User.php
Normal file
102
src/Entity/User.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Validator as AcmeAssert;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
class User implements UserInterface
|
||||
{
|
||||
/**
|
||||
* @AcmeAssert\ExistingEmail()
|
||||
*/
|
||||
private $email;
|
||||
|
||||
private $password;
|
||||
private $datas;
|
||||
private $rememberMe;
|
||||
private $roles;
|
||||
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): self
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): self
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
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
|
||||
{
|
||||
return $this->rememberMe;
|
||||
}
|
||||
|
||||
public function setRememberMe(bool $rememberMe): self
|
||||
{
|
||||
$this->rememberMe = $rememberMe;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
40
src/Form/UserType.php
Normal file
40
src/Form/UserType.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Validator\ExistingEmail;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||
|
||||
class UserType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('email', EmailType::class, [
|
||||
])
|
||||
->add("password", PasswordType::class, [
|
||||
"attr" => ["class" => "password-field"],
|
||||
"required" => true,
|
||||
"label"=>"Mot de passe"
|
||||
])
|
||||
->add('rememberMe', CheckboxType::class, [
|
||||
"required"=> false,
|
||||
"label"=> "Se souvenir de moi"
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
"data_class" => User::class,
|
||||
]);
|
||||
}
|
||||
}
|
57
src/Services/PdoServices.php
Normal file
57
src/Services/PdoServices.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
|
||||
class PdoServices extends AbstractController
|
||||
{
|
||||
private $params;
|
||||
|
||||
public function __construct(ParameterBagInterface $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
public function connection()
|
||||
{
|
||||
return new PDO($this->params->get('urlDatabase'), $this->params->get('dbUser'), $this->params->get('dbPassword'));
|
||||
}
|
||||
|
||||
public function fetchDatas($email)
|
||||
{
|
||||
try {
|
||||
$dbh = $this->connection();
|
||||
$datas = $dbh->query("SELECT " . $this->getParameter('fetchDatas'). " from USER where email = '" . $email . "';")->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
print "Erreur !: " . $e->getMessage() . "<br/>";
|
||||
die();
|
||||
}
|
||||
return $datas;
|
||||
}
|
||||
|
||||
public function verifyPassword($password, $hashedPassword)
|
||||
{
|
||||
$hashMethod = $this->params->get('hashMethod');
|
||||
switch ($hashMethod){
|
||||
case "sha1":
|
||||
return $hashedPassword === sha1($password, false);
|
||||
break;
|
||||
case "md5":
|
||||
return $hashedPassword === md5($password);
|
||||
break;
|
||||
case "BCRYPT":
|
||||
default:
|
||||
return password_verify($password, $hashedPassword);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
18
src/Validator/ExistingEmail.php
Normal file
18
src/Validator/ExistingEmail.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?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';
|
||||
}
|
||||
}
|
48
src/Validator/ExistingEmailValidator.php
Normal file
48
src/Validator/ExistingEmailValidator.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?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()
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user