How to: CakePHP logging in without password? - cakephp

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

Related

Laravel 8 Fortify User UUID Login Problem

I am currently setting up a new project using Laravel 8. Out of the box, Laravel is configured to use auto-incrementing ID's for the user's ID. In the past I have overrode this by doing the following.
Updating the ID column in the user table creation migration to
$table->uuid('id');
$table->primary('id');
Adding the following trait
trait UsesUUID
{
protected static function bootUsesUUID()
{
static::creating(function ($model) {
$model->{$model->getKeyName()} = (string) Str::orderedUuid();
});
}
}
Adding the following to the user model file
use UsesUUID;
public $incrementing = false;
protected $primaryKey = 'id';
protected $keyType = 'uuid';
On this new project, I did the same as above. This seems to break the login functionality. When the email and password are entered and submitted, the form clears as though the page has been refreshed. Thing to note is there are no typical validation error messages returned as would be expected if the email and/or password is wrong.
To check that the right account is actually being found and the password is being checked properly, I added the following code to the FortifyServiceProvider boot method. The log file confirms that the user is found and the user object dump is correct too.
Fortify::authenticateUsing(function(Request $request) {
\Log::debug('running login flow...');
$user = User::where('email', $request->email)->first();
if ($user && Hash::check($request->password, $user->password)) {
\Log::debug('user found');
\Log::debug($user);
return $user;
}
\Log::debug('user not found');
return false;
});
Undoing the above changes to the user model fixes the login problem. However, it introduces a new problem that is the login will be successful but it wont be the right account that is logged in. For example, there are 3 accounts, I enter the credentials for the second or third account, but no matter what, the system will always login using the first account.
Anyone have any suggestions or ideas as to what I may be doing wrong, or if anyone has come across the same/similar issue and how you went about resolving it?
Thanks.
After digging around some more, I have found the solution.
Laravel 8 now stores sessions inside the sessions table in the database. The sessions table has got a user_id column that is a foreign key to the id column in the users table.
Looking at the migration file for the sessions table, I found that I had forgot to change the following the problem.
From
$table->foreignId('user_id')->nullable()->index();
To
$table->foreignUuid('user_id')->nullable()->index();
This is because Laravel 8 by default uses auto incrementing ID for user ID. Since I had modified the ID column to the users table to UUID, I had forgotten to update the reference in the sessions table too.

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.

Cakephp & user email confirmation

i'm new to php and cakephp, i was following the Simple Authentication and Authorization Application tutorial from cakephp (http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html). All seem to working good.
I'm add a email confirmation to activate the account when a user subscribe. In the tutorial the password is using the blowfishpassword hasher. And i'm using it as a token in the link for the confirmation.
but i can't seem to be able to compare the link token with the password in the database...
$passwordHasher = new BlowfishPasswordHasher();
$motdepasse = $this->data['Utilisateur']['mot_passe'] = $passwordHasher->hash(
$this->data['Utilisateur']['mot_passe']
);
$link = array('controller'=>'utilisateurs','action'=>'activate',$this->Utilisateur->id
.'-'. $motdepasse);
public function activate($token) {
$token = explode('-',$token);
$user = $this->Utilisateur->find('first',array(
'conditions' => array('id' => $token[0],'Utilisateur.mot_passe' => Security::hash($token[1], 'blowfish', 'Utilisateur.mot_passe'))
));
debug($user);
debug($token[1]);
die();
}
Can you help me? thanks guys!
First of all you shouldn't send the password hash around, no matter how safe the hash possibly might be, confirmation tokens should be generated separately! Simply store it in an extra column or in a separate table.
That being said, in your activate() method you are hashing the hash again, which, in case the hash would actually be generated, would cause the comparison to fail. However the script won't genereate a hash, as you are using an invalid salt value which should result in the following warning:
Invalid salt: Utilisateur.mot_passe for blowfish Please visit http://www.php.net/crypt and read the appropriate section for building blowfish salts.
and Security::hash() will return an empty string. If you don't get such a message, then you'll need to enable the debug mode.
I'd suggest to get familiar with PHP, CakePHP, hashing and stuff first before you try to implement security related functionality!
You may want to check out https://github.com/CakeDC/users, it supports email verification and lot more out of the box.

Hashing a password

I have built a login form but not a sign up form so i am putting the users details directly into the sql database.
I have found out that cakephp automatically hashes the password when the user tries to login, but at the moment I cant login because the password in the database is not hashed.
how does cakephp hash the passwords?
My security salt is Dhhfei38fhDg37dg6Dg208Dh3h380Hrjd3
Could you please walk me through what it does?
Hashed passwords in cakephp are created by:
$hashedPasswords = Security::hash($yourPass, NULL, true);
Check the cakephp manual for more info
debug(AuthComponent::password("your-password"));
That's if you are hashing your password this way inside your UserModel.
public function beforeSave() {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
}
return true;
}
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#hashing-passwords
Add a new user with a password. You can take the hash value of the new user's password and paste it into other user's records.
As of Cakephp 2.0, Cake only hashes passwords in the login process,
on other places (like register-method...), the password won't be hashed automatically, that's because it was considered a strange behaviour to people who where new to cakephp.
If you want to hash the password, you need to use the method Sudhir mentioned.
One of the advantages that cake does not hash passwords automatically anymore is, that you can more easily check the password complexity ( if there are included special characters, numbers, letters ecc).
According to How to – password hashing in cakephp: "Security::hash takes the type sha1."

cakephp authenticate user with repeated entries in the Database table (manual authentication?)

I'm creating an authentication system for a group of websites. The problem is that I have to use a pre-existing Database, which has a users table already full of entries, and that one user can have several accounts. Basically, a user has one account per website he has access to (it's not the best way to do this, but I can't change it). Each account is represented by an entry in the users table, with login, password, name... and the important field: website_id. This field tells the system what website that account has access to.
The big problem is that some users with more than one account have the exact same login/password information for all of them. For example, one user has 3 accounts:
account1: login = charly / pwd = 1234 / name = Charles ... website_id = 1
account2: login = charly / pwd = 1234 / name = Charles ... website_id = 2
account3: login = charly / pwd = 1234 / name = Charles ... website_id = 3
So if he goes to the website that has id = 2 and uses those credentials, he's granted access. If he goes to the website that has id = 4, he's denied access.
My problem is that since CakePHP does the login automatically, when a user tries to login, CakePHP checks only the first entry in the Database that matches the login/password submited in the form. So if a user is currently in the website with website_id = 3 and tries to login, Cake finds the first entry (account1), compares its website_id (1 in this case) to the current website's id (3), and since they're different, the access is not granted, but it should. _Please note that the comparison of the website_id vs the account's website_id is already being made manually in the login() function_.
This how the login() function looks like now:
function login() {
$userInfo = $this->Auth->user();
if ( isset($userInfo) ) {
if ($userInfo['User']['website_id'] == $this->website_id) {
//Users gets access to a website that he has an account for
}
else {
//User is denied access because his account is not registered for the current website
$this->Session->destroy();
$this->Session->setFlash(__('You don't have access to this website', true));
$this->redirect($this->Auth->logout());
}
}
}
What I would like is to be able to manually authorize the access to the current website by using the login/password submitted by the user to manually search in the users table, and if I find a match in one of the user accounts, grant the access, or otherwise deny access. To sum up, avoid all the automagic of Auth's component.
If the Auth component's login method fails, control is transferred back to the custom login action (e.g. UsersController::login()). I've used this to authenticate using either username or email address, but it could be easily adapted for this purpose. Same idea, different criteria. I offered what I think is a reasonably thorough response (with code) to a similar question. It may help you as well.

Resources