Automatically login in Symfony2 with FOSUserBundle [duplicate] - symfony

This question already has answers here:
Automatic post-registration user authentication
(9 answers)
Closed 9 years ago.
I have created an individual sign up mechanism in my Symfony2 app (using FOSUserBundle) which exists in addition to the regular registration.
Is there any way - after I have created and persisted the User to the database - to automatically login that current user. And after that the User shall be redirected to a page which requires a logged in user (and due to the automatical login, the User can access that page)?
This is basically my method to create the user:
public function signupAction(Request $request) {
$user = new User();
$form = $this->createFormBuilder($user)
->...()
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
// Enable User
$user->setEnabled(true);
// Persist to DB
$em->persist($user);
$em->flush();
// Here I need the auto-login before redirecting to _root
return $this->redirect($this->generateUrl('_root'));
}
return $this->render('MyBundle:MyController:signup.html.twig', array(
'form' => $form->createView()
));
}

Attention: This doesn't seem to work in Symfony3 anymore.
Quoting from the answer to a duplicate question:
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
$user = //Handle getting or creating the user entity likely with a posted form
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.context')->setToken($token);
$this->get('session')->set('_security_main',serialize($token));

Related

How to create a new FOSUserBundle user programatically using the same validation as on web form?

I am running a Symfony 2.8 based web app using FOSUserBundle to manage users. Creating new users with a web form is absolutely no problem.
Now I would like to add a feature to create new users with a REST api. Of course submitting username, password, email, etc. to a controller is no big deal:
public function registerAction(Request $request) {
$requestJson = json_decode($request->getContent(), true);
$username = $requestJson[JSON_KEY_USERNAME];
$email = $requestJson[JSON_KEY_MAIL];
$password = $requestJson[JSON_KEY_PASSWORD];
...
$this->registerUser($username, $email, $password);
...
}
private function registerUser($username, $email, $password, $locale, $timezone, $currency) {
$userManager = $this->get('fos_user.user_manager');
$emailExist = $userManager->findUserByEmail($email);
$userNameExists = $userManager->findUserByUsername($username);
if ($emailExist || $userNameExists)
return false;
$user = $userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
...
$user->setLocked(0);
$user->setEnabled(0);
$userManager->updateUser($user);
return true;
}
However, this performs no validation at all. If for example the username is empty an NotNullConstraintViolationException is thrown when persisting the user object.
Of course I could manually re-implement the same validation process which is used by the RegistrationForm (username not empty, not taken, no invalid characters, password min length, e-mail format, etc.) and pass back the same error messages but this would mean to reinvent the wheel.
Is it somehow possible to run the exact same validation which is used by the RegistrationForm?
Symfony validator can work independently. In a controller you can use validator service like this:
$violations = $this->get('validator')->validate($user, null, ['your_groups_here']);
// Or inject Symfony\Component\Validator\Validator\ValidatorInterface into a service.
It will return a ConstraintViolationListInterface, you can loop trough this object.
You can check FOSUserBundle validation groups here: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/config/validation.xml

How programmatically login with fr3d_ldapbundle

I am using symfony 3.3 with fos_userbundle and fr3d_ldapbundle to authentichate my users trough LDAP.
The login works correctly if a try to use the standard login form generated.
But what I need to do is a manual(programmatically) login.
What is the best way to do it with fr3d_ldapbundle?
Sorry guys, I give you more details:
I tried to follow this guide: https://ourcodeworld.com/articles/read/459/how-to-authenticate-login-manually-an-user-in-a-controller-with-or-without-fosuserbundle-on-symfony-3
If I try to use the fos_user.user_manager the login works correctly, but using the fr3d_ldap.ldap_manager it doesn't work. (the isPasswordValid function return me "Username or Password not valid")
The user is retrieved correctly from LDAP server, but the "password" field is empty if I print the $user object. Using the standard login form the authentication works correctly and the username is stored in my fos user bundle table with the password field empty. Could be this my problem?
Also the $salt is empty.
This is my code of LoginAction:
public function loginAction(Request $request)
{
// This data is most likely to be retrieven from the Request object (from Form)
// But to make it easy to understand ...
$_username = "user";
$_password = "password";
// Retrieve the security encoder of symfony
$factory = $this->get('security.encoder_factory');
/// Start retrieve user
// Let's retrieve the user by its username:
/*
// If you are using FOSUserBundle:
$user_manager = $this->get('fos_user.user_manager');
$user = $user_manager->findUserByUsername($_username);
//Or by yourself
$user = $this->getDoctrine()->getManager()->getRepository("ApiBundle:User")
->findOneBy(array('username' => $_username));
*/
//Using fr3d/ldap-bundle
$user_manager = $this->get('fr3d_ldap.ldap_manager');
$user = $user_manager->findUserByUsername($_username);
//print_r($user);die();
/// End Retrieve user
// Check if the user exists !
if(!$user){
return new Response(
'Username doesnt exists',
Response::HTTP_UNAUTHORIZED,
array('Content-type' => 'application/json')
);
}
/// Start verification
$encoder = $factory->getEncoder($user);
$salt = $user->getSalt();
if(!$encoder->isPasswordValid($user->getPassword(), $_password, $salt)) {
return new Response(
'Username or Password not valid.',
Response::HTTP_UNAUTHORIZED,
array('Content-type' => 'application/json')
);
}
/// End Verification
// The password matches ! then proceed to set the user in session
//Handle getting or creating the user entity likely with a posted form
// The third parameter "main" can change according to the name of your firewall in security.yml
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.token_storage')->setToken($token);
// If the firewall name is not main, then the set value would be instead:
// $this->get('session')->set('_security_XXXFIREWALLNAMEXXX', serialize($token));
$this->get('session')->set('_security_main', serialize($token));
// Fire the login event manually
$event = new InteractiveLoginEvent($request, $token);
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
/*
* Now the user is authenticated !!!!
* Do what you need to do now, like render a view, redirect to route etc.
*/
return new Response(
'Welcome '. $user->getUsername(),
Response::HTTP_OK,
array('Content-type' => 'application/json')
);
}
Someone is able to help me?
Thank you.
#Jon Doe, you certainly cannot get the password information on user object while doing ldap authentication.
LDAP uses bind function which takes username and password information, tries to authenticate and return success or failure.
While using FR3DLdapBundle, this should be done inside Authentication Provider. Check LdapAuthenticationProvider.php file for following code.
if (!$this->ldapManager->bind($currentUser, $presentedPassword)) {
throw new BadCredentialsException('The credentials were changed from another session.');
}
In your controller - LoginAction you shouldn't be doing any authentication.
Just check for any authentication error and check for any access specific role if you need to have role based access as following example.
// get the login error if there is one
$error = $this->get('security.authentication_utils')->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $this->get('security.authentication_utils')->getLastUsername();
//if you need to check for the user role.
$roleGranted = $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN');

How to check if a username/password combination is valid for FOS UserBundle

We are currently using Symfony 2 and FOS/UserBundle for user authentication.
I want to check if a given username/password combination is valid without logging in. This is because another person is currently logged in but for example needs to do a specific action which needs to be done by someone with a higher clearance.
Basically I want another user to do a different controller action besides the person that is currently logged.
If there's a better way of doing this please let me know
How can validate username and password from controller #696
public function validUser($username, $password){
$user = new Users(); //entity
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$bool = $encoder->isPasswordValid($user->getPassword(),$password,$user->getSalt());
}
Symfony 5.4
Password validation can be done using UserPasswordHasherInterface
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class AuthenticaitonServices
{
public function __construct(UserPasswordHasherInterface $passwordHasher)
{
$this->hasher = $passwordHasher;
}
public function validate($request)
{
$form = [
"username" => $request->request->get("_username"),
"password" => $request->request->get("_password")
];
if(!$this->hasher->isPasswordValid($user, $form['password']))
{
// Incorrect Password
} else {
// Correct Password
}
isPasswordValid returns a bool response
Bundles are not longer available in newer Symfony versions. Above code is for validating password posted from a login form
Hope this is helpful.

fosuserbundle ldap configuration for strange use case

I'm trying to create a fosuserbundle for a quite strange use case, which is mandatory requirement, so no space to diplomacy.
Use case is as follow:
users in a mongo db table populated by jms messages -no registration form
users log in by ldap
user record not created by ldap, after a successful login username is checked against mongodb document
Considering that ldap could successfully log in people that exhist in ldap but cannot access site (but login is still successful), what could be the best way to perform such authentication chain?
I was thinking about some possible options:
listen on interactive login event, but imho there's no way to modify an onSuccess event
create a custom AuthenticationListener to do another check inside onSuccess method
chain authentication using scheb two-factor bundle
any hint?
I've used Fr3DLdapBundle which can be incorporate with FOSUserBundle quite easily (I'm using the 2.0.x version, I have no idea if the previous ones will do the same or be as easy to set up).
In the LdapManager (by default) it creates a new user if one is not already on the database which is not what I wanted (and doesn't seem to be what you want) so I have added my own manager that checks for the presence of the user in the database and then deals with the accordingly.
use FR3D\LdapBundle\Ldap\LdapManager as BaseLdapManager;
.. Other use stuff ..
class LdapManager extends BaseLdapManager
{
protected $userRepository;
protected $usernameCanonicalizer;
public function __construct(
LdapDriverInterface $driver,
$userManager,
array $params,
ObjectRepository $userRepository,
CanonicalizerInterface $usernameCanonicalizer
) {
parent::__construct($driver, $userManager, $params);
$this->userRepository = $userRepository;
$this->usernameCanonicalizer = $usernameCanonicalizer;
}
/**
* {#inheritDoc}
*/
public function findUserBy(array $criteria)
{
$filter = $this->buildFilter($criteria);
$entries = $this->driver->search(
$this->params['baseDn'], $filter, $this->ldapAttributes
);
if ($entries['count'] > 1) {
throw new \Exception('This search can only return a single user');
}
if ($entries['count'] == 0) {
return false;
}
$uid = $entries[0]['uid'][0];
$usernameCanonical = $this->usernameCanonicalizer->canonicalize($uid);
$user = $this->userRepository->findOneBy(
array('usernameCanonical' => $usernameCanonical)
);
if (null === $user) {
throw new \Exception('Your account has yet to be set up. See Admin.');
}
return $user;
}

How to set remember me cookie when logging user inside Controller in Symfony2

I have made my own custom FB login function because I need a certain flow that I couldn't achieve with HWIOAuthBundle. Everything works great, except one thing... I don't know how to set remember me functionality when I log in a user through my controller.
This is the LOGIN code I've got so far:
public function loginAction() {
// Facebook login code here
...
// User already connected with FB acc. Just log in.
$token = new UsernamePasswordToken($user, null, "main", $user->getRoles());
$this->get("security.context")->setToken($token);
//now dispatch the login event
$request = $this->get("request");
$event = new InteractiveLoginEvent($request, $token);
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
// Redirect user to hime page
return $this->redirect($this->generateUrl('/home'));
}
Thank you for any help or advice in advance!
You can use this remember token not the normal one it should be fixed :
$key = $this->container->getParameter('secret');
$token = new RememberMeToken($user, 'main', $key); //main is your firewall use name you gave to it.
$this->get('security.context')->setToken($token);

Resources