I'm pretty new to Symfony 4 and it is mostly the first time I ever use something to handle connexion to an admin panel, or either yaml file to set parameters. As recommended in the documentation, I'm using Security recipe. As the whole site was working in my computer, I deployed it online, where connexion problem began.
So here's my problem :
I created a user while developping the website with username : User and password : Password. I used argon2i as recommended. When switching to production mode in a distant server, I just dumped the database and copied it on the server. The login page was not redirecting to admin panel.
I thought it could be because argon2 algorithm generated salt base on the OS resources or something like that. So I regenerated password for User. Connexion was still not working. I tried with another algorithm (changing the password directly in database each time).
I thought that production mode could not be set for differents roles so I lowered the security setting roles to IS_AUTHENTICATED_FULLY
I tried to recreate the same settings in production AND in developpement mode in my computer, and now it's not working anymore.
I first thought it was because of the server configuration but it's obviously not as I tried with Apache server, PHP server provided by server recipe and with PHP raw server. As I get HTTP code 401 for all servers, I think it's due to Symfony comparing hashed password in database with plaintext password entered by the user. I might be wrong but that seems to be the most probable issue.
I also have no idea how to fix this. I tried with form autogenerated (where I don't know how to put some logic when the form is valid and submitted), I tried with "old school" pop up so I thought security configuration would handle this...
Here's my code :
config/packages/security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
db_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
logout:
path: /logout
target: /
prod:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
logout:
path: /logout
target: /
main:
anonymous: ~
http_basic: ~
provider: db_provider
# form_login:
# login_path: login
# check_path: login
# default_target_path: projects_index
# always_use_default_target_path: true
# remember_me:
# secret: '%kernel.secret%'
# lifetime: 604800 # 1 week in seconds
# path: /
# always_remember_me: true
logout:
path: /logout
target: /
pattern: ^/admin
encoders:
Symfony\Component\Security\Core\User\User: plaintext
App\Entity\User:
algorithm: sha512
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/admin, roles: IS_AUTHENTICATED_FULLY }
# - { path: ^/user, roles: ROLE_ADMIN }
session_fixation_strategy: migrate
hide_user_not_found: true
always_authenticate_before_granting: false
erase_credentials: true
access_decision_manager:
strategy: affirmative # One of affirmative, consensus, unanimous
allow_if_all_abstain: false
allow_if_equal_granted_denied: true
src/Controller/SecurityController.php
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends Controller
{
/**
* @Route("/login", name="login")
*/
public function login(Request $request, AuthenticationUtils $authenticationUtils, UserPasswordE$
{
// 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', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
}
src/Form/UserType.php
use App\Entity\User;
use Doctrine\DBAL\Types\TextType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username')
->add('alias')
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => User::class,
));
}
}
I hope I was specific enough and that you'll help me find a solution for this. Thank you very much !