I have a symfony app which serve a RESTful API(for mobile app) and have backend administration.
I can succesfuly login to the backend via facebook, but how should I allow loggin via the RESTful API?
Wooh.. after almost 12 hours(!) here is the solution for anyone who looking for too:
We need to create new custom firewall
This factory should connect to the FOSFacebook and validate the token
If it using our new firewall it should manually disable any session or cookie.
To use the firewall we need to send our token in every request
The code
First define our firewall listener
GoDisco/UserBundle/Security/Firewall/ApiFacebookListener.php
<?php
/**
* Authored by AlmogBaku
* almog.baku#gmail.com
* http://www.almogbaku.com/
*
* 9/6/13 2:17 PM
*/
namespace Godisco\UserBundle\Security\Firewall;
use FOS\FacebookBundle\Security\Authentication\Token\FacebookUserToken;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
/**
* API gateway through Facebook oAuth token: Firewall
*
* Class ApiFacebookListener
* #package Godisco\UserBundle\Security\Firewall
*/
class ApiFacebookListener implements ListenerInterface
{
/**
* #var \Symfony\Component\Security\Core\SecurityContextInterface
*/
protected $securityContext;
/**
* #var \Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface
*/
protected $authenticationManager;
/**
* #var Session
*/
protected $session;
/**
* #var string
*/
protected $providerKey;
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, Session $session, $providerKey)
{
if (empty($providerKey)) {
throw new \InvalidArgumentException('$providerKey must not be empty.');
}
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
$this->session = $session;
$this->providerKey=$providerKey;
}
/**
* #param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event The event.
*/
public function handle(GetResponseEvent $event)
{
$accessToken = $event->getRequest()->get('access_token');
$token = new FacebookUserToken($this->providerKey, '', array(), $accessToken);
/**
* force always sending token
*/
$_COOKIE=array();
$this->session->clear();
try {
if($accessToken)
$returnValue = $this->authenticationManager->authenticate($token);
$this->securityContext->setToken($returnValue);
}
} catch(AuthenticationException $exception) {
if(!empty($accessToken))
$event->setResponse(new Response(array("error"=>$exception->getMessage()),401));
}
}
}
Than create a new security factory which calling our listener, and will connect the authentication to the FOSFacebookBundle.
GoDisco/UserBundle/DependencyInjection/Security/Factory/ApiFacebookFactory.php
<?php
/**
* Authored by AlmogBaku
* almog.baku#gmail.com
* http://www.almogbaku.com/
*
* 9/6/13 2:31 PM
*/
namespace GoDisco\UserBundle\DependencyInjection\Security\Factory;
use FOS\FacebookBundle\DependencyInjection\Security\Factory\FacebookFactory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
/**
* API gateway through Facebook oAuth token: Factory
*
* Class ApiFacebookFactory
* #package GoDisco\UserBundle\DependencyInjection\Security\Factory
*/
class ApiFacebookFactory extends FacebookFactory
{
/**
* {#inheritdoc}
*/
public function getKey()
{
return 'api_facebook';
}
/**
* {#inheritdoc}
*/
public function addConfiguration(NodeDefinition $node)
{
$builder = $node->children();
$builder
->scalarNode('provider')->end()
->booleanNode('remember_me')->defaultFalse()->end()
;
foreach ($this->options as $name => $default) {
if (is_bool($default)) {
$builder->booleanNode($name)->defaultValue($default);
} else {
$builder->scalarNode($name)->defaultValue($default);
}
}
}
/**
* {#inheritdoc}
*/
protected function createEntryPoint($container, $id, $config, $defaultEntryPointId)
{
return null;
}
/**
* {#inheritdoc}
*/
protected function createListener($container, $id, $config, $userProvider)
{
$listenerId = "api_facebook.security.authentication.listener";
$listener = new DefinitionDecorator($listenerId);
$listener->replaceArgument(3, $id);
$listenerId .= '.'.$id;
$container->setDefinition($listenerId, $listener);
return $listenerId;
}
}
Defining the listener service, so we can inject the arguments
GoDisco/UserBundle/Resources/config/services.yml
services:
api_facebook.security.authentication.listener:
class: GoDisco\UserBundle\Security\Firewall\ApiFacebookListener
arguments: ['#security.context', '#security.authentication.manager', '#session', '']
Defining our new firewall!
app/config/security.yml
security:
api:
pattern: ^/api
api_facebook:
provider: godisco_facebook_provider
stateless: true
anonymous: true
main:
...
You need to implement oAuth authentication from your client app.
This was answered before:
How to restfully login, Symfony2 Security, FOSUserBundle, FOSRestBundle?
Related
I want to recover the date of the last time a user logged in my Symfony 5 website, I created a LoginListener and did the right settings (So-think-I ?) to make it work but in the class Login Listener :
namespace App\Event;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class LoginListener
{
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
// Get the User entity.
$user = $event->getAuthenticationToken()->getUser();
// Update your field here.
$user->setLastLogin(new \DateTime());
// Persist the data to database.
$this->em->persist($user);
$this->em->flush();
}
}
The setLastLogin(new \DateTime()) is described as an undefined method. Yet this method is in the entity User.php and it is properly called in the loginlistener. And the "use App\Entity\User :
/**
* {#inheritdoc}
*/
public function setLastLogin(\DateTime $time = null)
{
$this->lastLogin = $time;
return $this;
}
/**
* Gets the last login time.
*
* #return \DateTime|null
*/
public function getLastLogin()
{
return $this->lastLogin;
}
/**
* #var \DateTime $lastLogin
*
* #ORM\Column(type="datetime")
*/
private $lastLogin;
And when I try to make a exit(var_dump($user), nothing appears. Here is my services.yaml :
App\EventListener\LoginListener:
- tags:
- { name: 'kernel.event_listener', event: 'security.interactive_login', entity: 'App\Entity\User' }
Can someone help me please ? Thank you.
I want to use ConstraintValidator in my custom login authentication (using SimpleForm) to validate google Recaptcha of this bundle EWZRecaptchaBundle I have not an idea
security.yaml main firewall section:
providers:
default:
entity:
class: App:User
property: phone
main:
pattern: ^/
anonymous: ~
provider: default
simple_form:
authenticator: App\Security\Authenticator\UserAuthenticator
check_path: login
login_path: login
username_parameter: phone
password_parameter: password
use_referer: true
logout:
path: logout
I need to use Validaitor in App\Security\Authenticator\UserAuthenticator
This is my Custom Authenticator (App\Security\Authenticator\UserAuthenticator):
//...
class UserAuthenticator implements SimpleFormAuthenticatorInterface
{
private $encoder;
public function __construct(UserPasswordEncoderInterface $encoder)
{
$this->encoder = $encoder;
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
try {
$user = $userProvider->loadUserByUsername($token->getUsername());
}
catch (UsernameNotFoundException $exception) {
throw new CustomUserMessageAuthenticationException("invalid");
}
$isPasswordValid = $this->encoder->isPasswordValid($user, $token->getCredentials());
if ($isPasswordValid) {
return new UsernamePasswordToken($user, $user->getPassword(), $providerKey, $user->getRoles());
}
throw new CustomUserMessageAuthenticationException("invalid");
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof UsernamePasswordToken && $token->getProviderKey() === $providerKey;
}
public function createToken(Request $request, $username, $password, $providerKey)
{
return new UsernamePasswordToken($username, $password, $providerKey);
}
}
Check out How to Create a Custom Authentication System with Guard for a simpler and more flexible way to accomplish custom authentication tasks like this.
Especially the getCredentials method of the GuardAuthenticator class that you will create.
getCredentials(Request $request)
This will be called on every request and your job is to read the token (or whatever your "authentication" information is) from the request and return it. These credentials are later passed as the first argument of getUser().
or whatever your "authentication" information is so you will be able to handle the value passed within the recaptcha.
<?php
namespace App\Security\Authenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Validator\Validator\Validator\ValidatorInterface;
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
/**
* #var UserPasswordEncoderInterface
*/
private $encoder;
/**
* #var ValidatorInterface
*/
private $validator;
/**
* FormLoginAuthenticator constructor.
* #param UserPasswordEncoderInterface $encoder
* #param IsTrueValidator $isTrueValidator
*/
public function __construct(UserPasswordEncoderInterface $encoder, ValidatorInterface $validator)
{
$this->encoder = $encoder;
$this->validator = $validator;
}
/**
* Return the URL to the login page.
*
* #return string
*/
protected function getLoginUrl()
{
return '/login';
}
/**
* Does the authenticator support the given Request?
*
* If this returns false, the authenticator will be skipped.
*
* #param Request $request
*
* #return bool
*/
public function supports(Request $request)
{
return true;
}
/**
*
* #param Request $request
*
* #return mixed Any non-null value
*
* #throws \UnexpectedValueException If null is returned
*/
public function getCredentials(Request $request)
{
$violations = $this->validator->validate($request->request->get('g-recaptcha-response'), new IsTrue());
if($violations->count() > 0){
throw new AuthenticationException(self::INVALID_RECAPTCHA);
}
return array(
'username' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
);
}
/**
* Return a UserInterface object based on the credentials.
*
* The *credentials* are the return value from getCredentials()
*
* You may throw an AuthenticationException if you wish. If you return
* null, then a UsernameNotFoundException is thrown for you.
*
* #param mixed $credentials
* #param UserProviderInterface $userProvider
*
* #throws AuthenticationException
*
* #return UserInterface|null
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUsername($credentials['username']);
}
/**
* Returns true if the credentials are valid.
*
* If any value other than true is returned, authentication will
* fail. You may also throw an AuthenticationException if you wish
* to cause authentication to fail.
*
* The *credentials* are the return value from getCredentials()
*
* #param mixed $credentials
* #param UserInterface $user
*
* #return bool
*
* #throws AuthenticationException
*/
public function checkCredentials($credentials, UserInterface $user)
{
$plainPassword = $credentials['password'];
if (!empty($plainPassword) && !$this->encoder->isPasswordValid($user, $plainPassword)) {
throw new BadCredentialsException();
}
return true;
}
/**
* Called when authentication executed and was successful!
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* #param Request $request
* #param TokenInterface $token
* #param string $providerKey The provider (i.e. firewall) key
*
* #return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return null;
}
}
Make sure your authenticator is registered as a service. If you're using the default services.yaml configuration, that happens automatically. So you will be able also to pass the EWZRecaptchaBundle validator in the constructor of the GuardAuthenticator, then you can use it to validate the recaptcha value before sending the username and the password in getCredentials
and change security.yaml like this:
providers:
default:
entity:
class: App:User
property: phone
main:
pattern: ^/
anonymous: ~
provider: default
guard:
authenticators:
- App\Security\FormLoginAuthenticator
logout: ~
I have to create a simple user administration for a symfony 3 project.
One part of it is to start the password reset process for users.
(Yes, I know every user can trigger it himself but this is a request from our customer.)
Now I don't know how to start the process with a simple click in the admin interface for every user. Is there a method or a service in the UserBundle I can use?
There is no all in one method but this can be achieved by:
if (null === $user->getConfirmationToken()) {
$user->setConfirmationToken($this->tokenGenerator->generateToken());
}
// send email you requested
$this->mailer->sendResettingEmailMessage($user);
// this depends on requirements
$user->setPasswordRequestedAt(new \DateTime());
$this->userManager->updateUser($user);
with proper dependencies set.
Here's a service based solution written with Symfony 4.1 you can use without having to call in services form the container via get()
First you have to add an alias to services.yaml because the FOS mailer can't auto-wire:
FOS\UserBundle\Mailer\Mailer:
alias: fos_user.mailer.default
public: true
With that in place you can create the below class as service:
namespace App\Service; # change to your namespace
use FOS\UserBundle\Mailer\Mailer;
use FOS\UserBundle\Model\UserInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use FOS\UserBundle\Util\TokenGeneratorInterface;
/**
* Class UserPasswordResetService
*/
class UserPasswordResetService
{
/**
* #var Mailer
*/
private $mailer;
/**
* #var UserManagerInterface
*/
private $userManager;
/**
* #var TokenGeneratorInterface
*/
private $tokenGenerator;
/**
* UserPasswordResetService constructor.
*
* #param Mailer $mailer
* #param UserManagerInterface $userManager
*/
public function __construct(
Mailer $mailer,
UserManagerInterface $userManager,
TokenGeneratorInterface $tokenGenerator
)
{
$this->mailer = $mailer;
$this->userManager = $userManager;
$this->tokenGenerator = $tokenGenerator;
}
/**
* #param UserInterface $user
*/
public function resetPassword(UserInterface $user)
{
if (null === $user->getConfirmationToken()) {
$user->setConfirmationToken($this->tokenGenerator->generateToken());
}
// send email you requested
$this->mailer->sendResettingEmailMessage($user);
// this depends on requirements
$user->setPasswordRequestedAt(new \DateTime());
$this->userManager->updateUser($user);
}
}
Assuming you then add that service to a class via DI you can use it like this within a given method:
$this->passwordResetService->resetPassword($user);
From the information Kamil provided, this would be a full working function
/**
* Sends the user a new password
*
* #Route("reset_password/{id}", name="user_reset_password")
* #Security("has_role('ROLE_ADMIN')")
*
* #param User $user
* #return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function resetPasswordAction(User $user)
{
if (null === $user->getConfirmationToken()) {
/** #var $tokenGenerator TokenGeneratorInterface */
$tokenGenerator = $this->get('fos_user.util.token_generator');
$user->setConfirmationToken($tokenGenerator->generateToken());
}
$this->get('fos_user.mailer')->sendResettingEmailMessage($user);
$user->setPasswordRequestedAt(new \DateTime());
$this->get('fos_user.user_manager')->updateUser($user);
$this->addFlash('notice', "User {$user->getFullName()} got an email for resetting his password!");
return $this->redirectToRoute('user_index');
}
I am using FOSUserBundle in Symfone 2.8 webapp project. Currently the user is simply redirected to the homepage when he logs out. This should be changed to a "personal" logout page that can (optionally) display personal information (e.g. reminders for upcoming tasks or simple "Goodbey USERNAME" instead of just "Goodbey")...
So I need to access/use details of the currently logged out user. But since the user has just been logged out, I cannot access the user object any more?
How to solve this?
This is the configuration I use:
// config
security:
...
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
...
logout:
path: fos_user_security_logout
target: /logoutpage
// route
<route id="user_logout" path="/logoutpage" methods="GET">
<default key="_controller">AppBundle:Default:logout</default>
</route>
// Controller action
public function logoutAction() {
$loggedOutUser = HOW_TO_GET_USER(???);
$template = 'AppBundle:Default:logout.html.twig';
return $this->render($template, array('user' => $loggedOutUser));
}
The clean way would be to save the User's name/data in the session within an EventSubscriber/Listener that listens for a security.interactive_logout event.
The 2 problems arising thereby would be:
there is no logout event dispatched by the default LogoutHandler
symfony clears the session on logout per default configuration
You can change the session-clearing behavior by setting invalidate_session to false
security:
firewalls:
main:
# [..]
logout:
path: 'fos_user_security_logout'
target: '/logoutpage'
invalidate_session: false # <- do not clear the session
handlers:
- 'Namespace\Bridge\Symfony\Security\Handler\DispatchingLogoutHandler'
For the logout event you can create a logout handler like this:
class DispatchingLogoutHandler implements LogoutHandlerInterface
{
/** #var EventDispatcherInterface */
protected $eventDispatcher;
/**
* #param EventDispatcherInterface $event_dispatcher
*/
public function __construct(EventDispatcherInterface $event_dispatcher)
{
$this->eventDispatcher = $event_dispatcher;
}
/**
* {#inheritdoc}
*/
public function logout(Request $request, Response $response, TokenInterface $token)
{
$this->eventDispatcher->dispatch(
SecurityExtraEvents::INTERACTIVE_LOGOUT,
new InteractiveLogoutEvent($request, $response, $token)
);
}
}
Add some service configuration (or use autowiring):
Namespace\Bridge\Symfony\Security\Handler\DispatchingLogoutHandler:
class: 'Namespace\Bridge\Symfony\Security\Handler\DispatchingLogoutHandler'
arguments:
- '#event_dispatcher'
Events class
namespace Namespace\Bridge\Symfony;
final class SecurityExtraEvents
{
/**
* #Event("\Namespace\Bridge\Symfony\Security\Event\Logout\InteractiveLogoutEvent")
*/
const INTERACTIVE_LOGOUT = 'security.interactive_logout';
}
Event itself:
final class InteractiveLogoutEvent extends Event
{
/**
* #var Request
*/
protected $request;
/**
* #var Response
*/
protected $response;
/**
* #var TokenInterface
*/
protected $token;
/**
* #param Request $request
* #param Response $response
* #param TokenInterface $token
*/
public function __construct(Request $request, Response $response, TokenInterface $token)
{
$this->request = $request;
$this->response = $response;
$this->token = $token;
}
/**
* #return TokenInterface
*/
public function getToken()
{
return $this->token;
}
/**
* #return TokenInterface
*/
public function getRequest()
{
return $this->token;
}
/**
* #return Response
*/
public function getResponse()
{
return $this->response;
}
/**
* #return string
*/
public function getName()
{
return SecurityExtraEvents::INTERACTIVE_LOGOUT;
}
}
And the subscriber:
class UserEventSubscriber implements EventSubscriberInterface
{
/** #var LoggerInterface */
protected $logger;
/** #param LoggerInterface $logger */
public function __construct(LoggerInterface $logger)
{
// inject the session here
$this->logger = $logger;
}
/**
* {#inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
SecurityExtraEvents::INTERACTIVE_LOGOUT => 'onInteractiveLogout',
);
}
/**
* {#inheritdoc}
*/
public function onInteractiveLogout(InteractiveLogoutEvent $event)
{
$user = $event->getToken()->getUser();
// save the username in the session here
$this->logger->info(
'A User has logged out.',
array(
'event' => SecurityExtraEvents::INTERACTIVE_LOGOUT,
'user' => array(
'id' => $user->getId(),
'email' => $user->getEmail(),
)
)
);
}
}
Enable the subscriber by tagging it with kernel.event_subscriber
Namespace\EventSubscriber\UserEventSubscriber:
class: 'Namespace\EventSubscriber\UserEventSubscriber'
arguments: ['#monolog.logger.user']
tags:
- { name: 'kernel.event_subscriber' }
Easy huh? A somewhat dirty solution would be creating a request listener that saves the username in the session-flashbag on every request so you can get it from there in the logout-page template.
I'm using FOSUserBundle and I want when each user registers to be disabled by default. The administrator will contact every user by phone and he will make user active if it's appropriate. I have read about Overriding Default FOSUserBundle Controllers but I can't figure out how to make it working. I have created RegistrationController.php in src/AppBundle/Controller/RegistrationController.php with this method inside:
<?php
/*
* This file is part of the FOSUserBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace FOS\UserBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\AccountStatusException;
use FOS\UserBundle\Model\UserInterface;
/**
* Controller managing the registration
*
* #author Thibault Duplessis <thibault.duplessis#gmail.com>
* #author Christophe Coevoet <stof#notk.org>
*/
class RegistrationController extends ContainerAware
{
/**
* Receive the confirmation token from user email provider, login the user
*/
public function confirmAction($token)
{
$user = $this->container->get('fos_user.user_manager')->findUserByConfirmationToken($token);
if (null === $user) {
throw new NotFoundHttpException(sprintf('The user with confirmation token "%s" does not exist', $token));
}
$user->setConfirmationToken(null);
$user->setEnabled(false);
$user->setLastLogin(new \DateTime());
$this->container->get('fos_user.user_manager')->updateUser($user);
$response = new RedirectResponse($this->container->get('router')->generate('fos_user_registration_confirmed'));
$this->authenticateUser($user, $response);
return $response;
}
}
, but nothing works, maybe I need someone to show me the way to do it, nothing more.
For those still struggling with this question, set an observer listening the event: fos_user.registration.initialize like this (adapt you code path) :
app.listener.disable_registered_user:
class: AppBundle\Observer\DisableRegisteredUserListener
arguments:
- "#templating"
tags:
# split to multiple line for readability
# can be made into a single line like - { name: ..., event: ... , method: ... }
-
name: "kernel.event_listener"
event: "fos_user.registration.initialize"
method: "disableUser"
Then this is the content of your event listener class :
namespace AppBundle\Observer;
use FOS\UserBundle\Event\GetResponseUserEvent;
/**
* Class DisableRegisteredUserListener
* #package AppBundle\Observer
*/
class DisableRegisteredUserListener
{
/**
* #param \FOS\UserBundle\Event\GetResponseUserEvent $event
*/
public function disableUser(GetResponseUserEvent $event)
{
$user = $event->getUser();
/** #var \AppBundle\Entity\User $user */
$user->setEnabled(false);
}
}
You could just listen to the FOSUserEvents::REGISTRATION_CONFIRM and disable the registered user again before it gets persisted to the database.
As the FOSUserBundle automatically forwards the new user to the confirmedAction that requires a user to be logged in, you would need to provide your own response to override this.
Your listener...
class DisableRegisteredUserListener
{
/**
* #var EngineInterface
*/
private $templating;
/**
* #var EngineInterface $templating
*/
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
/**
* #var GetResponseUserEvent $event
* #return null
*/
public function disableUser(GetResponseUserEvent $event)
{
$user = $event->getUser();
$user->setEnabled(false);
$response = $this->templating->renderResponse(
'AppBundle:Registration:registration_complete.html.twig',
array(
'user' => $user,
)
);
}
}
Your services file (YAML)...
services:
app.listener.disable_registered_user:
class: AppBundle\EventListener\DisableRegisteredUserListener
arguments:
- "#templating"
tags:
# split to multiple line for readability
# can be made into a single line like - { name: ..., event: ... , method: ... }
-
name: "kernel.event_listener"
event: "fos_user.registration.confirm"
method: "disableUser"
Your AppBundle:Registration:registration_complete.html.twig could then be used to tell the new users that their account had been created but disabled and they would then be contacted by a member of your team to complete the process.