I created a CRUD that allows me to create users, societies and schools in a back office.
However, for an unknown reason, I can't log in with a created user with the password I gave him.
Here is my controller (the part where the user is created)
/**
* Creates a new User entity.
*
* #Route("/new", name="user_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$user = new User();
$form = $this->createForm('UserBundle\Form\UserType', $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$password = $this->get('security.password_encoder')->encodePassword($user, $user->getPassword());
$user->setPassword($password);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_show', array('id' => $user->getId()));
}
return $this->render('user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
}
After registering a new user, when I check it in the fos_user table, I can see that the password has been encrypted. However, if I try to login with the password I used, I simply get "bad credential" from my login form.
I can't figure out why.
Tell me if you need to see another file, I'll update my question
Any idea ?
Thank you in advance
The correct way to create user and set password in FOSUserBundle is the following:
$userManager = $this->container->get('fos_user.user_manager');
$userAdmin = $userManager->createUser();
$userAdmin->setUsername('System');
$userAdmin->setEmail('system#example.com');
$userAdmin->setPlainPassword('test');
$userAdmin->setEnabled(true);
$userManager->updateUser($userAdmin, true);
Password is kept encrypted in database. And to make it harder to bruteforce, database contains an additional field, named salt. You don't store it in your code, that's why it's impossible later to check password. But actually, you don't have to encrypt password and store it in database. User model contains a special method for it, setPlainPassword, which is intended to encrypt password populate both fields salt and password in database with correct values.
Related
I do import of users from a csv file to the database. In csv file I have some kinda username and password string. So how do I create a new user manually?
As I understand I need to getPasswordHash and generateAuthKey (last one generates random string). But probably I loose something important since when I try to log in I get an error that Username or Password is incorrect. Did anyone ever experienced such situation? Thanks in advance.
This should be the minimum required in your case. $username and $password are raw values taken from the CSV. Remember that there will be validation applied.
$user = new User();
$user->username = $username;
$user->setPassword($password);
$user->generateAuthKey();
return $user->save();
I think you forgot to set an active status of new User. You should check it in Login method of User model in your app, or in actionLogin of SiteController. For example, in my app the login method is:
public function login()
{
if ($this->validate() and $this->getUser()->status !== User::INACTIVE_STATUS) {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
}
return false;
}
If you show your code we can help you faster)
So if you are importing a list of users from a csv file, you will probably process this in a loop, try:
foreach ($csv_data as $user_data) {
$user = new User();
$user->setPassword($password);
$user->username = $user_data->username // or anything else, depending on your code
$user->status = 1 // or = User::STATUS_ACTIVE, depending on your code
$user->save();
}
I was stuck in this problem for almost a week. Even going through all the solutions in the internet doesn't help me to solve my problem. So I decided to ask my problem here and hope I will get solution.
My problem is why i always get Auth FALSE even my password is correct? I manage to add a new user and it stores the encrypted password, but when I try to login using that username and `password, it displays "Invalid username or password, try again"
Here is my code.
Thank in advance
I had some troubles with this part of cake as well, here is the way that I ended up using which works for me
public function login() {
if ($this->request->is('post')) {
$options = array(
'conditions' => array(
'User.username' => $this->request->data['User']['username'],
'User.password' => Security::hash($this->request->data['User']['password'], 'sha256', true)
),
'fields' => array(
'User.id',
'User.username',
'User.group_id',
// other fields you need
)
);
$userData = $this->User->find('first', $options);
if (!empty($userData) && $this->Auth->login($userData['User'])) {
$this->redirect($this->Auth->redirectUrl());
} else {
$this->Session->setFlash(__('Username, and/or password are incorrect'));
}
}
}
so, the bottom line is to manually check if the user with the given username and password exists, and then login them. Btw, pls pay attention that to login() function I am passing an array like this
array(
'id' => 1,
'email' => 'test#gmail.com',
'group_id' => 2
);
and not
array(
'User' => array(
'id' => 1,
'email' => 'test#gmail.com',
'group_id' => 2
)
);
also, you do not want to pass the password to the login function if you are using cake 2.x, from cake docs
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#identifying-users-and-logging-them-in
In 2.x $this->Auth->login($this->request->data) will log the user in
with whatever data is posted, whereas in 1.3
$this->Auth->login($this->data) would try to identify the user first
and only log in when successful.
so, first of all no need to pass the password, but you should be careful to check the valid user password before using login because if as it mentioned above, cake will login the user with any data.
About the password hashing part, please be sure you are using the same hashing algorithm with exact same salt (if you use it and you should) that you used during registration.
edit:
try using this in the model's beforeSave
public function beforeSave($options = array()) {
parent::beforeSave($options);
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = Security::hash($this->data[$this->alias]['password'], 'sha256', true);
}
}
For the last thing it is better practice to save a unique salt per user(salt should be saved in db along with user's password). In cake only one application side salt is being used for all passwords, and if the db and the app are compromised attacker can generate just one custom rainbow table for all passwords, but if the salt is unique for each user, then the bad guy should create custom rainbow table for each user separately, which is a lot more work/time/money.
I am trying to insert records in the database using Eloquent. I have the following code wherein I am creating a new user and then inserting a new row in the profile table so that the user update his/her profile as and when he/she logs in.
$user = new User();
$user->fill(Input::all());
$user->save();
$profile = new Profile();
$user->profile()->save($profile);
return Response::json(array('message' => 'Your account has been created.'));
The biggest disadvantage of my code here is - it leaves my tables in a half fried state. For example if the user's record were created but for some reason , there was an issue while creating the profile record, a user can exist where a profile has not been created for him/her.
Is there a way this can be circumvented ? I know I can check for the existence of the profile when I am about to access the user's profile (and create it if it has not been created - with the default values) but I would like to know if there are any other methods apart from this.
I believe using transaction is the way forward, if yes - can you please provide me an example ?
thanks
You can use transaction here:
$user = new User();
$user->fill(Input::all());
try {
DB::beginTransaction();
$user->save();
$profile = new Profile();
$user->profile()->save($profile);
DB::commit();
return Response::json(array('message' => 'Your account has been created.'));
}
catch (QueryException $e) {
DB::rollBack();
return Redirect::to('url')->withInput()
->with('error', 'Error occurred. Try again or contact administrator');
}
You can use this
$user = new User();
$user->fill(Input::all());
$profile = new Profile();
return DB::transaction(function() use ($user, $profile) {
$user->save();
$user->profile()->save($profile);
return Response::json(array('message' => 'Your account has been created.'));
});
I started trying out CakePHP a few months ago and I'm now attempting to create a "change password page" for logged in users. I have a form consisting of these fields: current password, new password and new password confirmation. For the current password, I want to validate that it matches the password of the logged in user, as a rule within the user Model. I know that I can get information of the logged in user with this: AuthComponent::user(). However, it provides me every field of the model except the password.
I know that Auth->login() is responsible for setting the session variables for the logged in user, but I'm not sure what I'm doing wrong here that only the password field cannot be accessed:
public function login() {
if ($this->request->is('POST')) {
if($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash('Your username/password combination was incorrect.');
}
}
}
Here's my login view:
<h2>Login</h2>
<?php
echo $this->Form->create('Promoter');
echo $this->Form->input('username');
echo $this->Form->input('password', array('type' => 'password'));
echo $this->Form->end('Login');?>
I'm using the Promoter model as the user, which i set in the AppController:
public $components = array(
'Auth'=>array(
...
'authenticate' => array(
'Form' => array('userModel' => 'Promoter')
),
'authorize' => array('Controller')
)
);
I can resort to validating the password in the Controller, but that would be giving up :) Please tell me if I need to provide more code to clarify the issue.
Thanks.
You're probably not doing anything wrong, this is most likely a security feature. There is no reason to keep a password in your session.
Secondly, even if it was in session, it would be encrypted (or at least I hope so, if it's not you should change that immediately!). So you still couldn't do a simple comparison.
To compare the old password, you should query your Promoter model, and get the hashed password from there, then hash the old password from your "change password" form, and finally compare the hashed results.
Because cake doesn't store the password in the session:
lib/Cake/Component/Auth/BaseAuthenticate.php line 94
unset($user[$fields['password']]);
I'm trying to find a way to log in user without password.
The reason is that I have phpBB3 forums in my site and the users already log in there. So I'm now building an expansion to the site to have more than just the forum (Using CakePHP). I thought that I could attach automatic account creation to CakePHP when user creates an account to forums (And ofcourse other link for the existing users). So the users would get CakePHP account that has the same username that they have registered in forums. That means that the only way to register to CakePHP part of the site would be to register to the forums first.
Now I'd like to handle the whole logging thing by phpBB3 login so users would still login to forums, and then I'd attach a piece of code that would also login them to CakePHP part of the site with the username they used to login to forums.
This way I could do also put users to their own ACL groups by their status in forums.
Thats what I'm after and I need to know the way to login users this way. I'm not looking for complete code I'm just looking for an answer that explains how I log in users in CakePHP without them having passwords at all.
I have also looked http://bakery.cakephp.org/articles/wilsonsheldon/2009/01/13/phpbb3-api-bridge but it just doesn't quite look what I'm looking for...
As far as I recall, Auth requires two pieces of info for a login.
You can change which fields in the users table are checked by auth with.
$Auth->fields = array(
'username' => 'username',
'password' => 'password'
);
So if you you want to be able to log in users according to their nickname and shoesize:
$Auth->fields = array(
'username' => 'nickname',
'password' => 'shoesize'
);
IMPORTANT:
The AuthComponent expects the password value stored in the database to be hashed instead of being stored in plaintext.
(I think it is a sha1 of the password and Security.salt)
In the above example, if any entries already existed in the database you'd have to overwrite the shoesize field for each of them with hashed versions of the shoesizes.
To generate a hashed password yourself you can use $Auth->password('A Password');
Quick and Dirty
If you fill the password fields in your users table with the return value of:
$Auth->password(null);
Then you can use the following:
$Auth->login(
array(
'User'=>array(
'username'=> USERNAME_FROM_PHPBB3,
'password'=>null
)
)
);
Less Quick and Dirty
When creating a new user.
Set the password field to the md5 hash of some random input.
$this->authUser[$this->User->alias][$Auth->fields['password']] = $Auth->password(md5(rand().rand()));
Use the Username from phpBB3 to retrieve the relevant record
from the users table in the database.
$this->authUser = $this->User->findByUsername( USERNAME_FROM_PHPBB3 );
If the query was successful Log in the user
if($this->authUser){
if($Auth->login($this->authUser)){
// Login Successful
}
}
From your cakephp app you can check if a user exist in the phpbb forums table and you can use the phpbb session to check if a user is logged in.
This function will solve your problem:
public function forceLogin($userName = NULL) {
$this->_setDefaults();
$this->User = ClassRegistry::init('User');
$this->User->recursive = 0;
$user = $this->User->findByUsername($userName);
if (!empty($user['User'])) {
$this->Session->renew();
$user['User']['id'] = null;
$user['User']['password'] = null;
$this->Session->write(self::$sessionKey, $user['User']);
}
return $this->loggedIn();
}