How programmatically login with fr3d_ldapbundle - symfony

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');

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 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.

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);

How to get plain password user with Symfony2?

I have to get the user's plain password for LDAP authentification and then retrieve LDAP user informations in the Active Directory with Symfony2.
/**
* #Route("/infos-profil/{id}", name="infos_profil")
* #Template()
*/
public function infosProfilAction($id)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('MyUserBundle:LdapUser')->find($id); // Find User Entity
if (!$user) {
throw $this->createNotFoundException('Unable to find LdapUser entity.');
}
$login = $user->getUsername(); // Login
$pass = $user->getPlainPassword(); // Password
$ds = ldap_connect("12.34.56.789"); // Domain connexion
if ($ds) {
$r = ldap_bind($ds, $login, $pass); // LDAP User connexion
if ($r) {
$filter = "(&(objectClass=user)(samaccountname=".$login.")(cn=*))";
$sr=ldap_search($ds, "ou=DOMAIN, ou=Test, ou=Users, dc=ats, dc=lan", $filter);
$info = ldap_get_entries($ds, $sr); // Retrieve user's Active Direcory informations
}
}
return array(
'user' => $user,
'info' => $info,
}
But it doesn't work, $pass is empty. When I put the plain password manually in the ldap_bind() function it works perfectly, I just have to get the plain password ! ...
Is it possible ?
It isn't possible to retrieve plain password from database for obvious security reasons.
For your problem, you should create a custom Authentication Provider, following this tutorial : https://symfony.com/doc/4.4/security/custom_authentication_provider.html
This way, your provider will get the plain password from the login form and you will be able to send it to your LDAP server.
You don't need the user's password to retrieve information about them from active directory. Once they are authenticated simply look them up via LDAP using their username, with either an anonymous connection or failing that, a known privileged account.

Automatically login in Symfony2 with FOSUserBundle [duplicate]

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));

Resources