From 99d66c71e0a551eaacc087e10da3afc5aa93f813 Mon Sep 17 00:00:00 2001
From: Camille Simiand <camille.simiand@tetras-libre.fr>
Date: Tue, 30 Nov 2021 15:44:22 +0100
Subject: [PATCH] Various fixes: - Login tests - log in check when user account
 not verified - remove duplicated bundles in composer.json - correct sign in
 -> log in in template

---
 composer.json                           |  2 -
 config/packages/security.yaml           |  1 +
 src/Controller/SecurityController.php   | 17 ++++--
 src/Security/AppCustomAuthenticator.php |  1 -
 src/Security/UserChecker.php            | 37 ++++++++++++
 templates/security/login.html.twig      | 14 ++---
 tests/functional/LoginTest.php          | 76 ++++++++++++++++++++-----
 translations/messages.en.yaml           |  2 +
 8 files changed, 122 insertions(+), 28 deletions(-)
 create mode 100644 src/Security/UserChecker.php
 create mode 100644 translations/messages.en.yaml

diff --git a/composer.json b/composer.json
index 4c16ac3..1b4e852 100644
--- a/composer.json
+++ b/composer.json
@@ -53,8 +53,6 @@
         "codeception/module-asserts": "^1.3",
         "codeception/module-phpbrowser": "^1.0",
         "codeception/module-symfony": "^2.0",
-        "dama/doctrine-test-bundle": "^6.7",
-        "doctrine/doctrine-fixtures-bundle": "^3.4",
         "phpstan/extension-installer": "^1.1",
         "phpstan/phpstan": "^1.2",
         "phpstan/phpstan-doctrine": "^1.0",
diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index c1ebf67..bfb5e2f 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -21,6 +21,7 @@ security:
             lazy: true
             provider: app_user_provider
             custom_authenticator: App\Security\AppCustomAuthenticator
+            user_checker: App\Security\UserChecker
             logout:
                 path: app_logout
                 # where to redirect after logout
diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php
index 6fdeced..57a3c87 100644
--- a/src/Controller/SecurityController.php
+++ b/src/Controller/SecurityController.php
@@ -2,10 +2,13 @@
 
 namespace App\Controller;
 
+use App\Entity\User;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;
+use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException;
 use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
+use Symfony\Contracts\Translation\TranslatorInterface;
 
 class SecurityController extends AbstractController
 {
@@ -14,16 +17,22 @@ class SecurityController extends AbstractController
      */
     public function login(AuthenticationUtils $authenticationUtils): Response
     {
-         if ($this->getUser()) {
-             return $this->redirectToRoute('capsule_list');
-         }
+        if ($this->getUser()) {
+            return $this->redirectToRoute('capsule_list');
+        }
 
         // get the login error if there is one
         $error = $authenticationUtils->getLastAuthenticationError();
         // last username entered by the user
         $lastUsername = $authenticationUtils->getLastUsername();
 
-        return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
+        return $this->render(
+            'security/login.html.twig',
+            [
+                'last_username' => $lastUsername,
+                'error' => $error
+            ]
+        );
     }
 
     /**
diff --git a/src/Security/AppCustomAuthenticator.php b/src/Security/AppCustomAuthenticator.php
index d9ddbb8..05d6c1b 100644
--- a/src/Security/AppCustomAuthenticator.php
+++ b/src/Security/AppCustomAuthenticator.php
@@ -50,7 +50,6 @@ class AppCustomAuthenticator extends AbstractLoginFormAuthenticator
             return new RedirectResponse($targetPath);
         }
 
-        // For example:
         return new RedirectResponse($this->urlGenerator->generate('capsule_list'));
     }
 
diff --git a/src/Security/UserChecker.php b/src/Security/UserChecker.php
new file mode 100644
index 0000000..36201e3
--- /dev/null
+++ b/src/Security/UserChecker.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Security;
+
+use App\Entity\User;
+use Symfony\Component\Security\Core\Exception\AccountStatusException;
+use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException;
+use Symfony\Component\Security\Core\User\UserCheckerInterface;
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+class UserChecker implements UserCheckerInterface
+{
+    private TranslatorInterface $translator;
+
+    public function __construct(TranslatorInterface $translator)
+    {
+        $this->translator = $translator;
+    }
+
+    public function checkPreAuth(UserInterface $user)
+    {
+    }
+
+    public function checkPostAuth(UserInterface $user)
+    {
+        if (!$user instanceof User) {
+            return;
+        }
+
+        if (!$user->isVerified()) {
+            throw new CustomUserMessageAccountStatusException(
+                $this->translator->trans('login.account_disabled_feedback')
+            );
+        }
+    }
+}
diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig
index 5a0aa54..58285ed 100644
--- a/templates/security/login.html.twig
+++ b/templates/security/login.html.twig
@@ -1,6 +1,6 @@
 {% extends 'layout.html.twig' %}
 
-{% block title %}Log in!{% endblock %}
+{% block title %}Log in{% endblock %}
 
 {% block body %}
 <form method="post" class="d-flex flex-column justify-content-center">
@@ -17,17 +17,15 @@
         </div>
     {% endif %}
 
-  <h1 class="mb-3 m-auto col-6">Please sign in</h1>
-      <div class="form-group d-flex flex-column m-auto mb-4 col-6">
+    <div class="form-group d-flex flex-column m-auto mb-4 mt-4 col-6">
         <label for="inputEmail" class="form-label">Email</label>
         <input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" autocomplete="email" required autofocus>
-      </div>
+    </div>
     <div class="form-group d-flex flex-column m-auto mb-4 col-6">
-      <label for="inputPassword" class="form-label">Password</label>
-      <input type="password" name="password" id="inputPassword" class="form-control" autocomplete="current-password" required>
+        <label for="inputPassword" class="form-label">Password</label>
+        <input type="password" name="password" id="inputPassword" class="form-control" autocomplete="current-password" required>
     </div>
 
-
     <input type="hidden" name="_csrf_token"
            value="{{ csrf_token('authenticate') }}"
     >
@@ -44,7 +42,7 @@
     #}
 
     <button class="btn btn-primary col-2 m-auto" type="submit">
-        Sign in
+        Log in
     </button>
 </form>
 {% endblock %}
diff --git a/tests/functional/LoginTest.php b/tests/functional/LoginTest.php
index 16b0e7d..b6e06d8 100644
--- a/tests/functional/LoginTest.php
+++ b/tests/functional/LoginTest.php
@@ -2,28 +2,78 @@
 
 namespace App\Tests\Controller;
 
-use App\Repository\UserRepository;
+use Symfony\Bundle\FrameworkBundle\KernelBrowser;
 use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+use Symfony\Component\DomCrawler\Form;
 
 class LoginTest extends WebTestCase
 {
-    public function testSomething(): void
-    {
-        $client = static::createClient();
-        $crawler = $client->request('GET', '/login');
+    private KernelBrowser $client;
+    private Form $form;
 
+    protected function setUp(): void
+    {
+        $this->client = static::createClient();
+        $crawler = $this->client->request('GET', '/login');
         $this->assertResponseIsSuccessful();
 
-        $client->enableProfiler();
-        $submit = $crawler->selectButton('Sign in');
-        $form = $submit->form();
+        $this->client->enableProfiler();
+        $submit_button = $crawler->selectButton('Log in');
+        $this->form = $submit_button->form();
+    }
+
+    public function testRegisteredUserWithEnabledAccountIsRedirectedToCapsulesPageWhenSubmittingLoginForm(): void
+    {
+        $this->form['email'] = 'defaultUser@localhost.com';
+        $this->form['password'] = "password";
+
+        $this->client->submit($this->form);
 
-        $form['email'] = 'defaultUser@localhost.com';
-        $form['password'] = "password";
+        $this->assertResponseRedirects(
+            '/my_capsules',
+            302,
+            'Once the user is logged in, He should be redirected to its capsules lists'
+        );
+
+        $this->client->followRedirect();
 
-        $client->submit($form);
-        $this->assertResponseRedirects('/my_capsules', 302, 'Once the user is logged in, He should be redirected to its capsules lists');
-        $client->followRedirect();
         $this->assertResponseIsSuccessful('/my_capsules');
     }
+
+    public function testRegisteredUserWithDisabledAccountIsRedirectedToLoginPageWhenSubmittingLoginForm(): void
+    {
+        $this->form['email'] = 'notVerified@localhost.com';
+        $this->form['password'] = "password";
+
+        $this->client->submit($this->form);
+
+        $this->assertResponseRedirects(
+            '/login',
+            302,
+            '
+            A registered user with a disabled account is redirected to login page when trying to log in'
+        );
+
+        $this->client->followRedirect();
+
+        $this->assertResponseIsSuccessful('/login');
+    }
+
+    public function testNonRegisteredUserIsRedirectedToLoginPageWhenSubmittingLoginForm(): void
+    {
+        $this->form['email'] = 'notRegistered@localhost.com';
+        $this->form['password'] = "password";
+
+        $this->client->submit($this->form);
+
+        $this->assertResponseRedirects(
+            '/login',
+            302,
+            'A non registered user is redirected to login page when trying to log in'
+        );
+
+        $this->client->followRedirect();
+
+        $this->assertResponseIsSuccessful('/login');
+    }
 }
diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml
new file mode 100644
index 0000000..8369909
--- /dev/null
+++ b/translations/messages.en.yaml
@@ -0,0 +1,2 @@
+login:
+  account_disabled_feedback: Your user account is disabled. Please click on the link your receive by email to validate your registration.
\ No newline at end of file
-- 
GitLab