Evening everyone , I've been stack with this problem since few days and whatever I change it remains .. basically on login when I put an invalid email it says email not found , when I put invalid password it says wrong password( I edited it of course ) but when they're both correct it shows Invalid credentials for some reason , I m really disparate .. help me please I can link any page code but Im 90% sure the code is correct ,thanks in advance
SecurityController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* #Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('/index');
}
// 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]);
}
/**
* #Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
security.yaml
security:
encoders:
App\Entity\User5:
algorithm: bcrypt
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_user_provider:
entity:
class: 'App\Entity\User5'
property: 'email'
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
guard:
authenticators:
- App\Security\LoginFormAuthenticator
entry_point: App\Security\LoginFormAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# 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: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
# - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
login.html.twig
{% extends 'home.html.twig' %}
{% block title %}Log in!{% endblock %}
{% block body %}
<form method="post" action="{{ path('app_login')}}">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.username }}, Logout
</div>
{% endif %}
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail">Email</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" required autofocus>
<label for="inputPassword">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" required>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
{#
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
See https://symfony.com/doc/current/security/remember_me.html
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="_remember_me"> Remember me
</label>
</div>
#}
<button class="btn btn-lg btn-primary" type="submit" >
Sign in
</button>
</form>
{% endblock %}
LoginFormAuthenticator
<?php
namespace App\Security;
use App\Entity\User5;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
private const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'email' => $request->request->get('email'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['email']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User5::class)->findOneBy(['email' => $credentials['email']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Email could not be found.');
}
$user = $this->entityManager->getRepository(User5::class)->findOneBy(['password' => $credentials['password']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Wrong password.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
// For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
return new RedirectResponse($this->urlGenerator->generate('index'));
throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate('app_login');
}
}
User5.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Entity()
* #UniqueEntity("email")
*/
/**
* #ORM\Entity(repositoryClass="App\Repository\User5Repository")
* #UniqueEntity(
* fields={"email"},
* message="That Email is already taken , try another "
* )
*/
class User5 implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(unique=true, type="string", nullable=false)
*/
private $email;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Role", mappedBy="Users")
*/
private $userRoles;
public function __construct()
{
$this->userRoles = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
/**
* #return Collection|Role[]
*/
public function getUserRoles(): Collection
{
return $this->userRoles;
}
public function addUserRole(Role $userRole): self
{
if (!$this->userRoles->contains($userRole)) {
$this->userRoles[] = $userRole;
$userRole->addUser($this);
}
return $this;
}
public function removeUserRole(Role $userRole): self
{
if ($this->userRoles->contains($userRole)) {
$this->userRoles->removeElement($userRole);
$userRole->removeUser($this);
}
return $this;
}
}
You should remove this lines, the password is encrypted in the database so you can't retrieve a user by his password, Symfony will do this job (comparing the two passwords).
$user = $this->entityManager->getRepository(User5::class)->findOneBy(['password' => $credentials['password']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Wrong password.');
}
I solved it my self , apparently you cant use guard and form login in the same time you gotta pick one of them because both do the same job one is easy and one is customized also I forgot something very important in the register function , forgot to encode the password , now it works just fine
heres the new register function
public function register(Request $request , EntityManagerInterface $entityManager, UserPasswordEncoderInterface $encoder)
{
$user = new User5();
$form = $this->createForm(Form::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$hashed = $encoder->encodePassword($user, $user->getPassword());
$user->setPassword($hashed);
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash("success", "Welcome to our application");
return $this->redirectToRoute("app_login");
}
return $this->render('account/registration.html.twig',[
'form' => $form->createView()
]);
}
new security.yaml
security:
encoders:
App\Entity\User5:
algorithm: bcrypt
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_user_provider:
entity:
class: 'App\Entity\User5'
property: 'email'
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
# default_target_path: dashboard
logout:
path: logout_user
target: index
# target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# 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: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
# - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
# - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Related
I'm posting here because I had searching for hours now. When I was in dev mode, everything was totally working and now, I had push my app on the server, the login form do not work.
When I click on "login" we can see the password and the email on the URL (and we stay on the login page) like if I done get method:
"https://website/login?email=blablablamail%40gmail.com&password=paswword&_csrf_token=9fI5G0acHOHQ8rmpO4chM2XrI0Tm8HSN32ghrtRzb38"
I'm using fortrabbit server
-> my swiftmailer function is not working too but I don't know why because the .env is correctly done and the swiftmailer.yaml is ok too, maybe there is a link between this 2 errors.
thanx by advance
here is my .env
###> symfony/framework-bundle ###
APP_ENV=prod
APP_SECRET=959a3e56d7f63b190f107a24fc7eade4
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
#TRUSTED_HOSTS='^localhost|example\.com$'
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#conne$
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# For a PostgreSQL database, use: "postgresql://db_user:db_password#127.0.0.1:5432/db_name?serverVersion=11&charset=utf8"
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
DATABASE_URL=mysql://root:root#127.0.0.1:3306/mysuper?serverVersion=10.4.8
###< doctrine/doctrine-bundle ###
###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$
###< nelmio/cors-bundle ###
here is my security.yaml
security:
encoders:
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: lazy
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
guard:
authenticators:
- App\Security\UserAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# 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: ROLE_ADMIN }
- { path: ^/user, roles: ROLE_USER }
role_hierarchy:
ROLE_ADMIN: ROLE_USER
here is my user.php
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
* #UniqueEntity(fields={"email"}, message="There is already an account with this email")
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*#Assert\Regex(
* pattern="/^[a-zA-Z0-9_.-]+#[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/",
* message="Veuillez indiquer un mail valide"
* )
*/
private $email;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string" )
*/
private $password;
/**
* #ORM\Column(type="string", length=25, nullable=true)
* #Assert\Regex(
* pattern="/^[^0-9-<>()\[\]\\.,;:\s#\']+[ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçêëìíîïðòóôõöùúûüýÿ\s]{2,}$/" ,
* match=false,
* message="Ton prénom ne peux pas contenir de caractères spéciaux"
* )
*/
private $prenom;
/**
* #ORM\Column(type="string", length=25, nullable=true)
* #Assert\Regex(
* pattern="/^[^0-9-<>()\[\]\\.,;:\s#\']+[ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜÝàáâãäåçêëìíîïðòóôõöùúûüýÿ\s]{2,}$/" ,
* match=false,
* message="Ton nom ne peux pas contenir de caractères spéciaux"
* )
*/
private $nom;
/**
* #ORM\Column(type="string", length=10, nullable=true)
*
*
*
* * #Assert\Regex(
* pattern="/^
(?:(?:\+|00)33|0) # Dialing code
\s*[1-9] # First number (from 1 to 9)
(?:[\s.-]*\d{2}){4} # End of the phone number
$/" ,
* match=false,
* message="Veuillez écrire un numéro valide"
* )
*/
private $phone;
/**
* #ORM\Column(type="boolean", nullable=true)
*/
private $phoneok;
/**
* #ORM\OneToMany(targetEntity=Mission::class, mappedBy="User", orphanRemoval=true)
*/
private $missions;
public function __construct()
{
$this->missions = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getPrenom(): ?string
{
return $this->prenom;
}
public function setPrenom(?string $prenom): self
{
$this->prenom = $prenom;
return $this;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(?string $nom): self
{
$this->nom = $nom;
return $this;
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): self
{
$this->phone = $phone;
return $this;
}
public function getPhoneok(): ?bool
{
return $this->phoneok;
}
public function setPhoneok(?bool $phoneok): self
{
$this->phoneok = $phoneok;
return $this;
}
/**
* #return Collection|Mission[]
*/
public function getMissions(): Collection
{
return $this->missions;
}
public function addMission(Mission $mission): self
{
if (!$this->missions->contains($mission)) {
$this->missions[] = $mission;
$mission->setUser($this);
}
return $this;
}
public function removeMission(Mission $mission): self
{
if ($this->missions->contains($mission)) {
$this->missions->removeElement($mission);
// set the owning side to null (unless already changed)
if ($mission->getUser() === $this) {
$mission->setUser(null);
}
}
return $this;
}
}
here is my security controller
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* #Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
// if ($this->getUser()) {
// return $this->redirectToRoute('target_path');
// }
// 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]);
}
/**
* #Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
here is my login form :
{% extends 'base.html.twig' %}
{% block title %}Se connecter{% endblock %}
{% block body %}
<form action="{{ path('app_login') }}" method="post " class="mt-4">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% if app.user %}
<div class="mb-3">
Vous tes connect en tant que {{ app.user.prenom }}, Logout
</div>
{% endif %}
<div class="container-fluid ">
<h1 class="h3 mb-3 font-weight-normal">Veuillez vous connecter</h1>
<label for="inputEmail" class="m-2">Email</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control container-fluid " req$
<label for="inputPassword" class="m-2">Mot de passe</label>
<input type="password" name="password" id="inputPassword" class="form-control container-fluid " required>
<br>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
{#
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
See https://symfony.com/doc/current/security/remember_me.html
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="_remember_me"> Remember me
</label>
</div>
#}
<button class="btn btn-lg btn-primary m-2" type="submit">
Connexion
</button>
</div>
</form>
{% endblock %}
I want to implement the following authentication scenario in symfony 5:
User sends a login form with username and password, authentication is processed against an LDAP server
if authentication against the LDAP server is successful :
if there is an instance of my App\Entity\User that as the same username as the ldap matching entry, refresh some of its attributes from the ldap server and return this entity
if there is no instance create a new instance of my App\Entity\User and return it
I have implemented a guard authenticator which authenticates well against the LDAP server but it's returning me an instance of Symfony\Component\Ldap\Security\LdapUser and I don't know how to use this object to make relation with others entities!
For instance, let's say I have a Car entity with an owner property that must be a reference to an user.
How can I manage that ?
Here is the code of my security.yaml file:
security:
encoders:
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
my_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: "%env(LDAP_BASE_DN)%"
search_dn: "%env(LDAP_SEARCH_DN)%"
search_password: "%env(LDAP_SEARCH_PASSWORD)%"
default_roles: ROLE_USER
uid_key: uid
extra_fields: ['mail']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
lazy: true
provider: my_ldap
guard:
authenticators:
- App\Security\LdapFormAuthenticator
I finally found a good working solution.
The missing piece was a custom user provider.
This user provider has the responsibility to authenticate user against ldap and to return the matching App\Entity\User entity. This is done in getUserEntityCheckedFromLdap method of LdapUserProvider class.
If there is no instance of App\Entity\User saved in the database, the custom user provider will instantiate one and persist it. This is the first user connection use case.
Full code is available in this public github repository.
You will find below, the detailed steps I follow to make the ldap connection work.
So, let's declare the custom user provider in security.yaml.
security.yaml:
providers:
ldap_user_provider:
id: App\Security\LdapUserProvider
Now, configure it as a service, to pass some ldap usefull string arguments in services.yaml.
Note since we are going to autowire the Symfony\Component\Ldap\Ldap service, let's add this service configuration too:
services.yaml:
#see https://symfony.com/doc/current/security/ldap.html
Symfony\Component\Ldap\Ldap:
arguments: ['#Symfony\Component\Ldap\Adapter\ExtLdap\Adapter']
Symfony\Component\Ldap\Adapter\ExtLdap\Adapter:
arguments:
- host: ldap
port: 389
# encryption: tls
options:
protocol_version: 3
referrals: false
App\Security\LdapUserProvider:
arguments:
$ldapBaseDn: '%env(LDAP_BASE_DN)%'
$ldapSearchDn: '%env(LDAP_SEARCH_DN)%'
$ldapSearchPassword: '%env(LDAP_SEARCH_PASSWORD)%'
$ldapSearchDnString: '%env(LDAP_SEARCH_DN_STRING)%'
Note the arguments of the App\Security\LdapUserProvider come from env vars.
.env:
LDAP_URL=ldap://ldap:389
LDAP_BASE_DN=dc=mycorp,dc=com
LDAP_SEARCH_DN=cn=admin,dc=mycorp,dc=com
LDAP_SEARCH_PASSWORD=s3cr3tpassw0rd
LDAP_SEARCH_DN_STRING='uid=%s,ou=People,dc=mycorp,dc=com'
Implement the custom user provider :
App\Security\LdapUserProvider:
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Ldap\Ldap;
use Symfony\Component\Ldap\LdapInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class LdapUserProvider implements UserProviderInterface
{
/**
* #var Ldap
*/
private $ldap;
/**
* #var EntityManager
*/
private $entityManager;
/**
* #var string
*/
private $ldapSearchDn;
/**
* #var string
*/
private $ldapSearchPassword;
/**
* #var string
*/
private $ldapBaseDn;
/**
* #var string
*/
private $ldapSearchDnString;
public function __construct(EntityManagerInterface $entityManager, Ldap $ldap, string $ldapSearchDn, string $ldapSearchPassword, string $ldapBaseDn, string $ldapSearchDnString)
{
$this->ldap = $ldap;
$this->entityManager = $entityManager;
$this->ldapSearchDn = $ldapSearchDn;
$this->ldapSearchPassword = $ldapSearchPassword;
$this->ldapBaseDn = $ldapBaseDn;
$this->ldapSearchDnString = $ldapSearchDnString;
}
/**
* #param string $username
* #return UserInterface|void
* #see getUserEntityCheckedFromLdap(string $username, string $password)
*/
public function loadUserByUsername($username)
{
// must be present because UserProviders must implement UserProviderInterface
}
/**
* search user against ldap and returns the matching App\Entity\User. The $user entity will be created if not exists.
* #param string $username
* #param string $password
* #return User|object|null
*/
public function getUserEntityCheckedFromLdap(string $username, string $password)
{
$this->ldap->bind(sprintf($this->ldapSearchDnString, $username), $password);
$username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
$search = $this->ldap->query($this->ldapBaseDn, 'uid=' . $username);
$entries = $search->execute();
$count = count($entries);
if (!$count) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
}
if ($count > 1) {
throw new UsernameNotFoundException('More than one user found');
}
$ldapEntry = $entries[0];
$userRepository = $this->entityManager->getRepository('App\Entity\User');
if (!$user = $userRepository->findOneBy(['userName' => $username])) {
$user = new User();
$user->setUserName($username);
$user->setEmail($ldapEntry->getAttribute('mail')[0]);
$this->entityManager->persist($user);
$this->entityManager->flush();
}
return $user;
}
/**
* Refreshes the user after being reloaded from the session.
*
* When a user is logged in, at the beginning of each request, the
* User object is loaded from the session and then this method is
* called. Your job is to make sure the user's data is still fresh by,
* for example, re-querying for fresh User data.
*
* If your firewall is "stateless: true" (for a pure API), this
* method is not called.
*
* #return UserInterface
*/
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user)));
}
return $user;
// Return a User object after making sure its data is "fresh".
// Or throw a UsernameNotFoundException if the user no longer exists.
throw new \Exception('TODO: fill in refreshUser() inside ' . __FILE__);
}
/**
* Tells Symfony to use this provider for this User class.
*/
public function supportsClass($class)
{
return User::class === $class || is_subclass_of($class, User::class);
}
}
Configure the firewall to use our custom user provider:
security.yaml
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
lazy: true
provider: ldap_user_provider
logout:
path: app_logout
guard:
authenticators:
- App\Security\LdapFormAuthenticator
Write an authentication guard:
App\SecurityLdapFormAuthenticator:
<?php
namespace App\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class LdapFormAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
private $urlGenerator;
private $csrfTokenManager;
public function __construct(UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager)
{
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
}
public function supports(Request $request)
{
return 'app_login' === $request->attributes->get('_route') && $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'username' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['username']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $userProvider->getUserEntityCheckedFromLdap($credentials['username'], $credentials['password']);
if (!$user) {
throw new CustomUserMessageAuthenticationException('Username could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
//in this scenario, this method is by-passed since user authentication need to be managed before in getUser method.
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$request->getSession()->getFlashBag()->add('info', 'connected!');
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('app_homepage'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate('app_login');
}
}
My user entity looks like this:
`App\Entity\User`:
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password = 'password is not managed in entity but in ldap';
/**
* #ORM\Column(type="string", length=255)
*/
private $userName;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function setUserName(string $userName): self
{
$this->userName = $userName;
return $this;
}
}
For Symfony 6 I do like this.
No extra implementation
security:
role_hierarchy:
ROLE_USER: ROLE_USER
ROLE_ADMIN: [ROLE_USER, ROLE_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
providers:
pmh_db:
entity:
class: App\Entity\User
property: username
pmh_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: '%base_dn%'
search_dn: '%search_dn%'
search_password: '%search_password%'
default_roles: 'ROLE_USER'
uid_key: '%uid_key%'
extra_fields: ['email']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
pattern: ^/
provider: pmh_db
switch_user: { role: ROLE_ALLOWED_TO_SWITCH }
login_throttling:
max_attempts: 5
form_login_ldap:
login_path: app_login
check_path: app_login
service: Symfony\Component\Ldap\Ldap
dn_string: 'DOMAIN\{username}'
query_string: null
default_target_path: /
logout:
path: /logout
target: /
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
# by default, the feature is enabled by checking a
# checkbox in the login form (see below), uncomment the
# following line to always enable it.
always_remember_me: true
# 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: '^/login', roles: PUBLIC_ACCESS }
- { path: '^/admin', roles: [IS_AUTHENTICATED_FULLY, ROLE_ADMIN] }
- { path: '^/', roles: ROLE_USER }
I’m currently discovering symfony.I am trying to code some user account. There are two role : ADMIN_ROLE or USER_ROLE. When I try to connect an account, I have this message « Authentication request could not be processed due to a system problem. » even when I enter a wrong username/password !
I have been looking for a solution for days (in docs and on internet).
I can fill my database with my user thanks to the fixture (I can see it in SQLyog). I tried to erase ma database to create it again.
This is my security.yaml :
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
form_login:
login_path: login
check_path: login
logout:
path: app_logout
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# 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: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/, roles: ROLE_USER }
This is my UtilisateurFixtures (to create false data)
<?php
namespace App\DataFixtures;
use App\Entity\Utilisateur;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\User\User;
//use Symfony\Bridge\Doctrine\Tests\Fixtures\User;
class UtilisateurFixtures extends Fixture
{
/**
* #var UserPasswordEncoderInterface
*/
private $encoder;
public function __construct(UserPasswordEncoderInterface $encoder)
{
$this->encoder = $encoder;
}
public function load(ObjectManager $manager)
{
$user = new Utilisateur();
$user->setUsername('demo3');
$user->setPassword($this->encoder->encodePassword($user,'demo3'));
$user->setRoles(['ROLE_USER', 'ROLE_ADMIN']);
$manager->persist($user);
$manager->flush();
}
}
This is my SecurityController :
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* #Route("/login", name="login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
// 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]);
}
/**
* #Route("/logout", name="app_logout", methods={"GET"})
*/
public function logout()
{
// controller can be blank: it will never be executed!
throw new \Exception('Don\'t forget to activate logout in security.yaml');
}
}
This is my Utilisateur.php :
<?php
namespace App\DataFixtures;
use App\Entity\Utilisateur;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\User\User;
//use Symfony\Bridge\Doctrine\Tests\Fixtures\User;
class UtilisateurFixtures extends Fixture
{
/**
* #var UserPasswordEncoderInterface
*/
private $encoder;
public function __construct(UserPasswordEncoderInterface $encoder)
{
$this->encoder = $encoder;
}
public function load(ObjectManager $manager)
{
$user = new Utilisateur();
$user->setUsername('demo3');
$user->setPassword($this->encoder->encodePassword($user,'demo3'));
$user->setRoles(['ROLE_USER', 'ROLE_ADMIN']);
$manager->persist($user);
$manager->flush();
}
}
This is my login.htlml.twig (where there is my form) :
{% extends 'base.html.twig' %}
{% block title %}Log in!{% endblock %}
{% block body %}{% if error %}
{{ error.messageKey|trans(error.messageData, 'security') }}
{% endif %}
<form action="{{ path('login') }}" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" />
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
<input type="hidden" name="_target_path" value="/" />
{#
If you want to control the URL the user
is redirected to on success (more details below)
<input type="hidden" name="_target_path" value="/account" />
#}
<button type="submit">login</button>
</form>
{% endblock %}
This is UtilisateurRepository :
<?php
namespace App\Repository;
use App\Entity\Utilisateur;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Symfony\Bridge\Doctrine\RegistryInterface;
/**
• #method Utilisateur|null find($id, $lockMode = null, $lockVersion = null)
• #method Utilisateur|null findOneBy(array $criteria, array $orderBy = null)
• #method Utilisateur[] findAll()
• #method Utilisateur[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class UtilisateurRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Utilisateur::class);
}
// /**
// * #return Utilisateur[] Returns an array of Utilisateur objects
// /
/
public function findByExampleField($value)
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->orderBy('u.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Utilisateur
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
Thank you for your help ! Don't hesitate if you need anything.
I am implementing a login system with guard in my symfony application.
I already setup the system, but i did one mistake, therefore i cant login...
The essentials:
My User Entity implements "AdvancedUserInterface, \Serializable" and it provides email property instead of username property..moreover i changed "getUsername"-function to:
public function getUsername()
{
return $this->email;
}
security.yml:
# app/config/security.yml
security:
providers:
main_db_provider:
entity:
class: AppBundle:User
property: email
encoders:
AppBundle\Entity\User:
algorithm: bcrypt
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
logout:
path: /logout
target: /
guard:
authenticators:
- form_authenticator
provider: main_db_provider
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
services.yml:
services:
form_authenticator:
class: AppBundle\Security\FormAuthenticator
arguments: ["#service_container"]
login.html.twig:
<form action="{{ path('login') }}" method="POST">
<input type="text" name="email">
<input type="text" name="password">
<input type="submit" name="submit" value="Submit">
</form>
LoginController(part of it):
/**
* #Route("/login", name="login")
*/
public function loginAction(Request $request) {
$authenticationUtils = $this->get('security.authentication_utils');
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render(
'AppBundle:login:index.html.twig',
[
'error' => $error ? $error->getMessage() : NULL,
'last_username' => $lastUsername
]
);
}
And last my FormAuthentificator:
class FormAuthenticator extends AbstractGuardAuthenticator
{
private $container;
/**
* Default message for authentication failure.
*
* #var string
*/
private $failMessage = 'Invalid credentials';
/**
* Creates a new instance of FormAuthenticator
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* {#inheritdoc}
*/
public function getCredentials(Request $request)
{
if ($request->getPathInfo() != '/login' || !$request->isMethod('POST')) {
return;
}
return array(
'email' => $request->request->get('email'),
'password' => $request->request->get('password'),
);
}
/**
* {#inheritdoc}
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
$email = $credentials['email'];
return $userProvider->loadUserByUsername($email);
}
/**
* {#inheritdoc}
*/
public function checkCredentials($credentials, UserInterface $user)
{
$plainPassword = $credentials['password'];
$encoder = $this->container->get('security.password_encoder');
if (!$encoder->isPasswordValid($user, $plainPassword)) {
throw new CustomUserMessageAuthenticationException($this->failMessage);
}
return true;
}
/**
* {#inheritdoc}
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$url = $this->container->get('router')->generate('backend');
return new RedirectResponse($url);
}
/**
* {#inheritdoc}
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
$url = $this->container->get('router')->generate('login');
return new RedirectResponse($url);
}
/**
* {#inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$url = $this->container->get('router')->generate('login');
return new RedirectResponse($url);
}
/**
* {#inheritdoc}
*/
public function supportsRememberMe()
{
return false;
}
}
When i enter my valid credentials, i get:
Invalid credentials:
I also tried with other credentials, but always same error.
Anybody could help me to solve this issue?
Thanks and Greetings!
I always get message: "Bad credentials" when I try to login in symfony2. I am doing this based to http://symfony.com/doc/current/cookbook/security/custom_provider.html. Please help me to figure out, where the problem is? Thanks in advance.
security.yml looks like this
security:
encoders:
Zags\UserBundle\Security\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
webservice:
id: zags_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login_firewall:
pattern: ^/login$
anonymous: ~
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
#anonymous: ~
#http_basic:
# realm: "Secured Demo Area"
access_control:
- { path: ^/gender_type, roles: ROLE_USER }
#- { path: ^/_internal/secure, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
I have added these lines to routing.yml
login:
pattern: /login
defaults: { _controller: ZagsUserBundle:Security:login }
login_check:
pattern: /login_check
User.php class looks like this
<?php
namespace Zags\UserBundle\Security\User;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
{
private $username;
private $password;
private $salt;
private $roles;
public function __construct($username, $password, $salt, array $roles)
{
$this->username = $username;
$this->password = $password;
$this->salt = $salt;
$this->roles = $roles;
}
public function getRoles()
{
return $this->roles;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return $this->salt;
}
public function getUsername()
{
return $this->username;
}
public function eraseCredentials()
{
}
public function equals(UserInterface $user)
{
return $user->getUsername() === $this->username;
}
}
?>
So this is my UserProvider.php class
<?php
namespace Zags\UserBundle\Security\User;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
class UserProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
// make a call to your webservice here
$userData = array("username" => "latysh", "password" => "123", "salt" => "123", "roles" => array('ROLE_USER'));
// pretend it returns an array on success, false if there is no user
if ($userData) {
$username = $userData['username'];
$password = $userData['password'];
$salt = $userData['salt'];
$roles = $userData['roles'];
// ...
return new User($username, $password, $salt, $roles);
}
throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'Zags\UserBundle\Security\User\User';
}
}
?>
and services.yml looks like this
parameters:
zags_user_provider.class: Zags\UserBundle\Security\User\UserProvider
services:
zags_user_provider:
class: "%zags_user_provider.class%"
SecurityController.php
<?php
namespace Zags\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;
class SecurityController extends Controller
{
public function loginAction()
{
$request = $this->getRequest();
$session = $request->getSession();
// get the login error if there is one
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
}
return $this->render('ZagsUserBundle:Security:login.html.twig', array(
// last username entered by the user
'last_username' => $session->get(SecurityContext::LAST_USERNAME),
'error' => $error,
));
}
}
?>
and login.html.twig
{% if error %}
<div>{{ error.message }}</div>
{% endif %}
<form action="{{ path('login_check') }}" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" />
<label for="password">Password:</label>
<input type="password" id="password" name="_password" />
{#
If you want to control the URL the user is redirected to on success (more details below)
<input type="hidden" name="_target_path" value="/account" />
#}
<button type="submit">login</button>
</form>
Has found answer to my question. Thanks to machour for responce. The problem was with SALT. So I updated the User.php class to
public function getSalt()
{
return '';
}
Then it logs in correctly or I should have encoded password with salt to successfully login. If one know how to do it, please write it as answer, YAHOO ))
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$pass = $encoder->encodePassword($user->getPassword(), $user->getSalt());