cakephp 2.5.7 login->Auth always false even password is correct - cakephp

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.

Related

Troubles with logging in with a newly created user

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.

Custom non-username/password based login with CakePHP

The jist of this question is about how to override CakePHP's auth component login function to log a user in based on something other than the default username and password.
So, we're developing a custom login function for one of our partners. Basically, the solution provides online courses to a number of companies who want to provide their clients and/or employees with in house training material.
This particular solution takes a home loan account number and personal identification number and does some algorithm validation and logs the user in. Or at least - that's what it should do.
Currently, the auth component tries to user a particular model to compare username and hashed password. Is there anyway to override this particular behaviour and get the Authcomponent to log the user in using the algorithm (glorified regex check) in a custom function? It should completely ignore the need for a username and password. In addition we won't actually have these account numbers and ID numbers stored anywhere. They will each be checked for certain related patterns.
Cheers
Custom your login with authenticate property :
In your appController
public $components = array(
'Session',
'Auth' => array(
'authError' => "You don't have accès",
'authorize' => array('Controller'),
authenticate' => array(
'Form' => array('userModel' => 'MyUserModel',
'fields' => array('username' => 'numberuser','password' => 'personnalId'),
)
)
);

CakePHP - Cannot access logged in user's password in Model using Authcomponent::user

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

logged in user can access data of other users

Please bear with me, as I'm a programming/cakephp noob, but I do not know how to restrict the user from access to other user data. When a user logs in, they get a dashboard of their listings (which come from several models....restaurants, hotels, golf courses, images for each listing, location information, coupons, etc..).
Depending on the model/controller, I could have user '3' (who has hotel listings) type into the browser bar /restaurants/edit/1 and edit the restaurant information of user '17' who has a restaurant with ID='1'. Worse, they can even access /users/dashboard/17. How do I limit a user to only access their own data? I was hoping there was some sort of 'beforeAllow()' part of the AuthComponent I could use in the AppController that checks user id beforehand and kicks them back out to their dashboard if they try to perform a CRUD action on other users' data.
Even if I was using ACL (I know I should but it's frankly a little too over my head at this stage of learning), I'd still have to know the right code to limit user access, correct?
Below is my AppController:
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array('controller' => 'users', 'action' => 'view'),
'logoutRedirect' => array('controller' => 'docs', 'action' => 'index'),
'authError' => 'Sorry, you are not authorized to view this page.'
)
);
function beforeFilter() {
$this->Auth->userModel = 'User';
$this->Auth->allow('join_now','debug','index', 'condos', 'houses', 'hotels_and_motels', 'print_all_coupons', 'print_coupon', 'search', 'golf', 'charters', 'events', 'nightlife', 'shopping', 'visitors_info', 'contact_us', 'view', 'results');
}
}
and here is a sample edit function (the edit function from my UnitsController):
function edit($id) {
$this->set('title', 'Edit your property');
$this->Unit->id = $id;
if (empty($this->request->data)) {
$this->request->data = $this->Unit->read();
} else {
if ($this->Unit->saveAll($this->request->data)) {
$this->Session->setFlash('Your property has been updated.', 'success');
}
}
}
I will say that every one of my db tables has a user_id field so the logged in user can be matched with the user_id of each model.
I thought that this SO question was what I was looking for but they ended up getting off on a tangent in it and never answered the original question the user asked.
If you where using cakes acl and auth, then no, you wouldn't have to write a bunch of code, checking the user ids for each action, but you'd have to write the code to tie together the acl's. You'd tell the Component that your controller and actions require acl privelages. And it doesnt the look ups in the aros and acos tables to make sure that your object requesting the content has the proper permissions.
I HIGHLY recommend you take a look at the tutorial and figure out how to get it to work
If you don't go that route, then you will have to add in the checking to every action that loads dependent content. Basically you'll, when a action is requested, you'll feature the object, then get the user associated to that object and check to see if the id of the user the same as the id as the requesting the object.
if ( $this->Unit->User->uid != $this->Session->User->uid ) {
throw new NotFoundException('Could not find that Unit');
} else {
...
}
The other thing you can do, for pages that are the same, but customized, is not use the url /user/dashboard/17 and instead just use /user/dashboard then in the dashboard action, pull the user id from the session data and load the profile for the user that is authenticated
I think you will need to use CRUD authorization for adding EditOwn actions. The answer described in CakePHP ACL Database Setup: ARO / ACO structure? handles much of the logic that you need.
Please note that the solution is still not complete and you will get access to actions that can render other users' data. Example: scaffold 'index' methods. To restrict access to other users' data here, you can modify the query to add filters based on User ID that you get from Session.

CakePHP Auth Component Check User Before Login

I want to prevent banned users from logging in to the site and give them a message that they are banned. I tried to use isAuthorized() for this but it allows the user to login and only after that denies him permission to the unauthorized actions.
So, basically I want to know where to put the condition that would check if the user table as banned = true, before the login process takes place. Right now my login function is empty as its being automatically controlled by the Auth Component.
Finally, I found a solution by going through the API. I wonder if anyone has used this ever, cause nobody pointed me to this, or maybe I wasn't clear enough. Anyways, to add a condition to the login process you just have put it in the variable $this->Auth->userScope
So, to check if a user is banned I just added this line to the beforeFilter() in my AppController,
$this->Auth->userScope = array('User.banned'=>0);
Hope this helps someone.
Alternatively to:
$this->Auth->userScope = array('User.banned'=>0);
This can be done when you include your Auth Component. This probably saves some tiny amount of overhead as $this->Auth->userScope isn't called every time a controller is parsed.
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish',
'scope' => array('User.banned' => 0)
)
),
'authorize' => array('Controller')
)
);
If you have the whole Auth system already up and running, why don't you just follow the KISS principle and revoke their password or alter there username? If they are not longer able to authenticate with your system as they could earlier they should be able to deduce that they are banned.
If that doesn't suffice, then additionally you could add the code below.
function login() {
if ($this->Session->read('Auth.User')) {
$this->Session->setFlash('You are alreadylogged in!~~~~~~~~~~~');
}
$this->Session->setFlash('You have been banned!');
$this->redirect(array('controller'=>'users','action'=>'index'));
}
Edit 1: For a more dynamically approach like you pointed out in your comment, you could check the is_banned column of the user record under concern in your UsersController::beforeFilter() and set your flash message accordingly. Also make a redirect based on the outcome of $this->Session->read('Auth.User.is_banned'). Maybe you want to have a look at the output of <?php debug $this->Session->read('Auth.User) ?> before attacking your problem.
Edit 2: My fault. You could store the is_banned somewhere in the Session via $this->Session->write(...). After you read an is_banned = true you can log the user out.
you have to use:
/** Function is executed after the login*/
function isAuthorized() {
return true;
}
where you can check if the user is banned or no. i.e.
/** Function is executed after the login*/
function isAuthorized() {
if($this->Auth->user('banned') == 1){ //column banned should be in the users table
$this->Session->setFlash('You have been banned!');
return false;
}
return true;
}
I believe this is the correct way.
Having read your last comment on Nik's way, I think that you could just refine your original solution by logging the user out manually via $this->Auth->logout() at the appropriate place in your code (followed by a redirect). This way it should look like he/she never logged in.

Resources