I tried to create an authenticator for my login form, but I always am unlogged for some unclear reason.
[2016-10-05 18:54:53] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user="test@test.test", authenticated=true, roles="ROLE_USER"))","authenticator":"AppBundle\Security\Authenticator\FormLoginAuthenticator"} []
[2016-10-05 18:54:54] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\Component\Security\Core\Exception\AuthenticationExpiredException(code: 0): at /space/products/insurance/vendor/symfony/symfony/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php:86)"} []
[2016-10-05 18:54:54] security.INFO: The security token was removed due to an AccountStatusException. {"exception":"[object] (Symfony\Component\Security\Core\Exception\AuthenticationExpiredException(code: 0): at /space/products/insurance/vendor/symfony/symfony/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php:86)"} []
I don't understand this "AuthenticationExpiredException" as I have nothing stateless, nor any expiration in any way nowhere in my app.
Does this issue speak to anyone?
Edit 1
After a bunch of hours, it looks like I am unlogged because of the {{ is_granted('ROLE_USER') }}
in Twig. Don't see why anyway.
Edit 2
If I dump() my security token on the onAuthenticationSuccess authenticator's method, authenticated = true
.
But, If I dump() my security token after a redirect or when accessing a new page, 'authenticated' = false
.
Why the hell my authentication isn't stored.
app/config/security.yml
security:
encoders:
AppBundleSecurityUserMember:
algorithm: bcrypt
cost: 12
providers:
members:
id: app.provider.member
role_hierarchy:
ROLE_ADMIN: "ROLE_USER"
firewalls:
dev:
pattern: "^/(_(profiler|wdt|error)|css|images|js)/"
security: false
main:
pattern: "^/"
anonymous: ~
logout: ~
guard:
authenticators:
- app.authenticator.form_login
access_control:
- { path: "^/connect", role: "IS_AUTHENTICATED_ANONYMOUSLY" }
- { path: "^/register", role: "IS_AUTHENTICATED_ANONYMOUSLY" }
- { path: "^/admin", role: "ROLE_ADMIN" }
- { path: "^/user", role: "ROLE_USER" }
- { path: "^/logout", role: "ROLE_USER" }
AppBundle/Controller/SecurityController.php
<?php
namespace AppBundleController;
use AppBundleBaseBaseController;
use AppBundleFormTypeConnectType;
use AppBundleSecurityUserMember;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBundleConfigurationTemplate;
use SymfonyComponentHttpFoundationRequest;
class SecurityController extends BaseController
{
/**
* @Route("/connect", name="security_connect")
* @Template()
*/
public function connectAction(Request $request)
{
$connectForm = $this
->createForm(ConnectType::class)
->handleRequest($request)
;
return [
'connect' => $connectForm->createView(),
];
}
}
AppBundle/Form/Type/ConnectType.php
<?php
namespace AppBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentFormExtensionCoreType;
use SymfonyComponentValidatorConstraints;
use EWZBundleRecaptchaBundleFormTypeEWZRecaptchaType;
use EWZBundleRecaptchaBundleValidatorConstraintsIsTrue as RecaptchaTrue;
class ConnectType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', TypeEmailType::class, [
'label' => 'Your email',
'required' => true,
'constraints' => [
new ConstraintsLength(['min' => 8])
],
])
->add('password', TypePasswordType::class, [
'label' => 'Your password',
'constraints' => new ConstraintsLength(['min' => 8, 'max' => 4096]), /* CVE-2013-5750 */
])
->add('recaptcha', EWZRecaptchaType::class, [
'label' => 'Please tick the checkbox below',
'constraints' => [
new RecaptchaTrue()
],
])
->add('submit', TypeSubmitType::class, [
'label' => 'Connect',
])
;
}
}
AppBundle/Security/Authenticator/FormLoginAuthenticator.php
<?php
namespace AppBundleSecurityAuthenticator;
use SymfonyComponentSecurityGuardAuthenticatorAbstractFormLoginAuthenticator;
use SymfonyComponentDependencyInjectionContainerInterface;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCoreExceptionBadCredentialsException;
use AppBundleFormTypeConnectType;
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
private $container; // ˉ\_(ツ)_/ˉ
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getCredentials(Request $request)
{
if ($request->getPathInfo() !== '/connect') {
return null;
}
$connectForm = $this
->container
->get('form.factory')
->create(ConnectType::class)
->handleRequest($request)
;
if ($connectForm->isValid()) {
$data = $connectForm->getData();
return [
'username' => $data['email'],
'password' => $data['password'],
];
}
return null;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUsername($credentials['username']);
}
public function checkCredentials($credentials, UserInterface $user)
{
$isValid = $this
->container
->get('security.password_encoder')
->isPasswordValid($user, $credentials['password'])
;
if (!$isValid) {
throw new BadCredentialsException();
}
return true;
}
protected function getLoginUrl()
{
return $this
->container
->get('router')
->generate('security_connect')
;
}
protected function getDefaultSuccessRedirectUrl()
{
return $this
->container
->get('router')
->generate('home')
;
}
}
AppBundle/Security/Provider/MemberProvider.php
<?php
namespace AppBundleSecurityProvider;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreExceptionUsernameNotFoundException;
use SymfonyComponentSecurityCoreExceptionUnsupportedUserException;
use AppBundleSecurityUserMember;
use ApiGatewayRequestResponseRequestResponseHandlerInterface;
use ApiBusinessInsuranceWebsiteActionGetInsuranceMemberGetInsuranceMemberRequest;
use ApiGatewayExceptionNoResultException;
class MemberProvider implements UserProviderInterface
{
protected $gateway;
public function __construct(RequestResponseHandlerInterface $gateway)
{
$this->gateway = $gateway;
}
public function loadUserByUsername($username)
{
try {
$response = $this->gateway->handle(
new GetInsuranceMemberRequest($username)
);
} catch (NoResultException $ex) {
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
$member = new Member();
$member->setId($response->getId());
$member->setUsername($response->getEmail());
$member->setPassword($response->getPassword());
$member->setCompanyId($response->getCompanyId());
$member->setFirstname($response->getFirstname());
$member->setLastname($response->getLastname());
$member->setIsManager($response->isManager());
$member->setIsEnabled($response->isEnabled());
return $member;
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof Member) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === Member::class;
}
}
AppBundle/Security/User/Member.php
<?php
namespace AppBundleSecurityUser;
use SymfonyComponentSecurityCoreUserUserInterface;
class Member implements UserInterface
{
private $id;
private $username;
private $password;
private $companyId;
private $firstname;
private $lastname;
private $isManager;
private $isEnabled;
private $roles = ['ROLE_USER'];
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
return $this;
}
public function getUsername()
{
return $this->username;
}
public function setUsername($username)
{
$this->username = $username;
return $this;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
return $this;
}
public function getCompanyId()
{
return $this->companyId;
}
public function setCompanyId($companyId)
{
$this->companyId = $companyId;
return $this;
}
public function getFirstname()
{
return $this->firstname;
}
public function setFirstname($firstname)
{
$this->firstname = $firstname;
return $this;
}
public function getLastname()
{
return $this->lastname;
}
public function setLastname($lastname)
{
$this->lastname = $lastname;
return $this;
}
public function isManager()
{
return $this->isManager;
}
public function setIsManager($isManager)
{
$this->isManager = $isManager;
return $this;
}
public function IsEnabled()
{
return $this->isEnabled;
}
public function setIsEnabled($isEnabled)
{
$this->isE