Migrating Cakephp2 Authentication to Cakephp 3 - security

I'm moving an app from CakePHP 2 to CakePHP 3. There is a new hashing algorithm for Cake3. I'd like the existing users to be able to login to the app using their old passwords and for those passwords to then be updated to the new algorithm.
Unfortunatly, I can't get the correct hash to match up to what is in the database.
$person = $this->Auth->identify();
if(!$person){ # maybe they have old sha1 password?
$oldhash = Security::hash($this->request->data['password'],
'sha1', "oldsalt");
$person = $this->People->find()->where(['password' => $oldhash])->where(['email' =>$this->request->data['email'] ])->first();
if($person){
$person->password = Security::hash($this->request->data['password']);
$this->People->save($person);
}
}
The user is not found and if i debug the $oldhash out I get a different string than what is stored in the password field for that user.
What am I doing wrong?

Fallback classes
According to the documentation:
CakePHP provides a clean way to migrate your users’ passwords from one algorithm to another, this is achieved through the FallbackPasswordHasher class. Assuming you are migrating your app from CakePHP 2.x which uses sha1 password hashes, you can configure the AuthComponent as follows:
You will have to create an Custom Password Hasher class src/Auth/. A Custom Password hasher wil look something like this:
namespace App\Auth;
use Cake\Auth\AbstractPasswordHasher;
class LegacyPasswordHasher extends AbstractPasswordHasher {
public function hash($password)
{
return sha1($password);
}
public function check($password, $hashedPassword)
{
return sha1($password) === $hashedPassword;
} }
and then add it to passwordhasher in authenticate as fallback like this:
'authenticate' => [
'Form' => [
'passwordHasher' => [
'className' => 'Fallback',
'hashers' => [
'Default',
'Legacy'
]
]
]
]
The first name appearing in the hashers key indicates which of the classes is the preferred one, but it will fallback to the others in the list if the check was unsuccessful.
legacy is the Custom Password Hasher.
Updating the password
To update the users' password to the new hash you only have to add this code to your login procedure:
if ($this->Auth->authenticationProvider()->needsPasswordRehash()) {
$user = $this->Users->get($this->Auth->user('id'));
$user->password = $this->request->data('password');
$this->Users->save($user);
}
Documentation
More information about Changing hashing Algorithms
More information about the Custom Password Hasher

I had a CakePHP 2 app using Blowfish. Here's how I made it work with CakePHP 3:
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
// ...
'fields' => [
'username' => 'email',
'password' => 'pass', // make sure you match this with your corresponding login.ctp input name
],
// ...
'passwordHasher' => [
'className' => 'Fallback',
'hashers' => [
'Default' => ['hashType' => PASSWORD_BCRYPT],
]
],
// ...
]
],
Hope it helps someone googling this issue

Related

Puppet: set default values for nested hashes

I am creating a class which creates a ssh keys pair for users.
In Hiera it looks like this:
ssh::default_user_keys::entries:
root:
privkey: ENC[PKCS7,MIIH/QYJKoZIhvcNAQcDoIIH7jCCB+oCAQAx...]
pubkey: BiQYJKoZIhvcNAQcDoIIBejCCAXYC...
user1:
privkey: ENC[PKCS7,MIIH/Bf0mv0aa7JRbEWWONfVMJBOX2I7x...]
keydir: /srv/data/user1/.ssh
user2:
privkey: ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAx...]
keytype: id_ecdsa
If some values are not specified in Hiera, they must be picked up from default values in the manifest.
So my question is how to write the manifest correctly?
This is my pseudo code I try to make working:
class ssh::default_user_keys_refact (
Hash $entries = lookup('ssh::default_user_keys_refact::entries', "merge" => 'hash'),
) {
$entries.each |String $user, Hash $item = {} | {
set_default { $item:
privkey => undef,
pubkey => undef,
keydir => "/home/${user}/.ssh",
keytype => id_rsa,
comment => undef,
}
$sshpriv = $item[privkey]
file { "${keydir}/$[keytype}":
ensure => file,
owner => $user,
mode => '0600',
content => $sshpriv,
}
}
}
Do you have ideas how to make this pseudo code working? Or in other words, how to set up default values for nested hiera hash in puppet manifest?
puppet versions is 6.
Thank you in advance.
Or in other words, how to set up default values for nested hiera hash in puppet manifest?
The fact that the hashes for which you want to provide defaults are nested inside others in the Hiera data isn't much relevant, because at the point of use they have been plucked out. With that being the case, you can accomplish this fairly easily by leveraging Puppet (not Hiera) hash merging. It might look something like this:
$entries.each |String $user, Hash $props| {
# Merge with default values
$full_props = {
'keydir' => "/home/${user}/.ssh",
'keytype' => 'id_rsa'
} + $props
file { "${full_props['keydir']}/${full_props['keytype']}":
ensure => 'file',
owner => $user,
mode => '0600',
content => $full_props['privkey'],
}
}
That's by no means the only way, but it's clean and clear, and it scales reasonably well.

Set default password management for users in puppet

When declaring a new user creation in Puppet, how can you set the default password management type and encryption?
How can I set one user to be managed independently?
How can I set one to be managed by puppet exclusively?
Independent: Do I just place a deceleration to /etc/passwd, e.g:
user{ "foo":
ensure => present,
managehome => true,
home =>"/home/foo",
password => "/etc/passwd",
uid => "001"
}
I read an example in puppetforge example
accounts::user { 'bob':
uid => 4001,
gid => 4001,
shell => '/bin/bash',
password => '!!',
}
I keep seeing password => !! But I cannot seem to find documentation for password => !! example
SSH managed: Then when it comes to managing directly with SSH Puppet, I just map it to the key? e.g. (from puppetforge)
accounts::user { 'jeff':
comment => 'Jeff McCune',
groups => [
'admin',
'sudonopw',
],
uid => '1112',
gid => '1112',
sshkeys => [
'ssh-rsa AAAAB3Nza...== jeff#puppetlabs.com',
'ssh-dss AAAAB3Nza...== jeff#metamachine.net',
],
}
Where I assume the above RSA AAAAB3Nza... is a generated (externally, copied) and then stored in hard-code? The user can then auth using jeff#puppetlabs.com which is mapped to the RSA?
In puppet, if you don't specify the password, it won't manage the password. If you specify a password, it ensures that value is placed in /etc/shadow. That value really should be an encrypted value. The double exclamation mark is the "not a password" value, and the account is then unable to be authenticated with a password.

How to add meta tags on custom paths in Drupal 8?

Does anybody know how can I add meta tags on custom paths in Drupal 8? I am using the metatags module.
Thank you!
You can add any meta tag programmatically from your custom module using hook_page_attachments() as below.
function MYMODULE_page_attachments(array &$page) {
$ogTitle = [
'#tag' => 'meta',
'#attributes' => [
'property' => 'og:title',
'content' => 'This is my page title',
],
];
$page['#attached']['html_head'][] = [$ogTitle, 'og:title'];
}
I've tested succesfuly Metatag Routes module for Drupal 8. The module adds a button in the default metatag dashboard page. The user can configure metatags for custom controllers generated by code.
Another way to make it in a controller :
public function index()
{
$variables = [];
return [
'#theme' => 'my_theme',
'#variables' => $variables,
'#attached' => [
'library' => [
],
// Added for open graph and SEO.
'html_head' =>
[
[
'#tag' => 'meta',
'#attributes' => [
'name' => 'og:descritpion',
'description' => 'My sublim description',
],
],
'og:descritpion',
],
];
}
The only solution actually with metatag module for Drupal 8, is to use fields in your content type, and use them as metatag element with token possibilities.
It works well like that. I also wait for a better solution.

Symfony2 SonataAdminBundle Password field encryption

I have FOSUserBundle to manage my users, and SonataAdminBundle to manage my website... I have a problem, whenever I try to change/add a password to any user, the password isn't encoded into sha512, but it does when the user register itself inside fosuserbundle registration page...
So there isn't any problem with Symfony2 configuration neither fosuserbundle config, it may be inside SonataAdminBundle somewhere, or maybe into my admin class...
<?php
// src/Acme/DemoBundle/Admin/PostAdmin.php
namespace Web\DificilBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Web;
class UserAdmin extends Admin
{
// Fields to be shown on create/edit forms
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('firstname')
->add('lastname')
->add('username')
->add('email')
->add('password', 'password') // -> I WANT THIS TO BE ENCODED INTO SHA512!
->add('roles','choice',array('choices'=>$this->getConfigurationPool()->getContainer()->getParameter('security.role_hierarchy.roles'),'multiple'=>true ));
//->add('body')
;
}
// Fields to be shown on filter forms
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper
->add('firstname')
->add('lastname')
->add('username')
->add('email')
->add('password')
;
}
// Fields to be shown on lists
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('firstname')
->add('lastname')
->add('username')
->add('password')
->add('email')
->add('facebookid')
->add('roles');
//->add('password', 'password')
;
}
}
Found a solution for everyone who has the same problem as me, just on your admin class, where you define your Create/Update form, use this and your password will be perfectly encrypted and ready to log into your new user ;)
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'))
->add('username', null, array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle'))
->add('plainPassword', 'repeated', array(
'type' => 'password',
'options' => array('translation_domain' => 'FOSUserBundle'),
'first_options' => array('label' => 'form.password'),
'second_options' => array('label' => 'form.password_confirmation'),
'invalid_message' => 'fos_user.password.mismatch',
))
;
}

drupal 6 programmatically log user in

I'm trying to log in a user as part of a form submit, but why is the following not working:
$user = db_fetch_object(db_query("SELECT * FROM users WHERE mail = '%s' AND pass = '%s'", $mail, md5($pass)));
if ($user) {
// Authenticate user and log in
$params = array(
'name' => $user->name,
'pass' => trim($user->pass)
);
// Authenticate user
$account = user_authenticate($params);
}
if I dump $user I can see the correct values, but if I dump the account it's empty.
You are passing the hashed password to ´user_authenticate()´, while the function expects the clear password (it will hash it itself indirectly when loading the account via ´user_load()´).
So changing your $params array declaration to
$params = array(
'name' => $user->name,
'pass' => $pass
);
should make your example work.
BTW, you could use user_load() yourself to avoid querying the database directly:
$user = user_load(array('mail' => $mail, 'pass' => trim($pass), 'status' => 1));
(The 'status' => 1 will restrict results to active users - you can leave that out, of course, if you really want to allow log ins to disabled accounts ;)

Resources