Users: transparently upgrade passwords to Argon2
Passwords that are sha1 will be transparently upgraded to argon2, and future comparisons will use Argon2 Co-authored-by: Graham Christensen <graham@grahamc.com>
This commit is contained in:
parent
29620df85e
commit
1da70030b7
43
flake.nix
43
flake.nix
|
@ -70,6 +70,47 @@
|
|||
};
|
||||
};
|
||||
|
||||
CryptArgon2 = final.perlPackages.buildPerlModule {
|
||||
pname = "Crypt-Argon2";
|
||||
version = "0.010";
|
||||
src = final.fetchurl {
|
||||
url = "mirror://cpan/authors/id/L/LE/LEONT/Crypt-Argon2-0.010.tar.gz";
|
||||
sha256 = "3ea1c006f10ef66fd417e502a569df15c4cc1c776b084e35639751c41ce6671a";
|
||||
};
|
||||
nativeBuildInputs = [ pkgs.ld-is-cc-hook ];
|
||||
meta = {
|
||||
description = "Perl interface to the Argon2 key derivation functions";
|
||||
license = final.lib.licenses.cc0;
|
||||
};
|
||||
};
|
||||
|
||||
CryptPassphrase = final.buildPerlPackage {
|
||||
pname = "Crypt-Passphrase";
|
||||
version = "0.003";
|
||||
src = final.fetchurl {
|
||||
url = "mirror://cpan/authors/id/L/LE/LEONT/Crypt-Passphrase-0.003.tar.gz";
|
||||
sha256 = "685aa090f8179a86d6896212ccf8ccfde7a79cce857199bb14e2277a10d240ad";
|
||||
};
|
||||
meta = {
|
||||
description = "A module for managing passwords in a cryptographically agile manner";
|
||||
license = with final.lib.licenses; [ artistic1 gpl1Plus ];
|
||||
};
|
||||
};
|
||||
|
||||
CryptPassphraseArgon2 = final.buildPerlPackage {
|
||||
pname = "Crypt-Passphrase-Argon2";
|
||||
version = "0.002";
|
||||
src = final.fetchurl {
|
||||
url = "mirror://cpan/authors/id/L/LE/LEONT/Crypt-Passphrase-Argon2-0.002.tar.gz";
|
||||
sha256 = "3906ff81697d13804ee21bd5ab78ffb1c4408b4822ce020e92ecf4737ba1f3a8";
|
||||
};
|
||||
propagatedBuildInputs = with final.perlPackages; [ CryptArgon2 CryptPassphrase ];
|
||||
meta = {
|
||||
description = "An Argon2 encoder for Crypt::Passphrase";
|
||||
license = with final.lib.licenses; [ artistic1 gpl1Plus ];
|
||||
};
|
||||
};
|
||||
|
||||
DirSelf = final.buildPerlPackage {
|
||||
pname = "Dir-Self";
|
||||
version = "0.11";
|
||||
|
@ -267,6 +308,8 @@
|
|||
CatalystViewTT
|
||||
CatalystXScriptServerStarman
|
||||
CatalystXRoleApplicator
|
||||
CryptPassphrase
|
||||
CryptPassphraseArgon2
|
||||
CryptRandPasswd
|
||||
DBDPg
|
||||
DBDSQLite
|
||||
|
|
|
@ -195,6 +195,7 @@ __PACKAGE__->many_to_many("projects", "projectmembers", "project");
|
|||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-02-06 12:22:36
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:4/WZ95asbnGmK+nEHb4sLQ
|
||||
|
||||
use Crypt::Passphrase;
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use String::Compare::ConstantTime;
|
||||
|
||||
|
@ -216,7 +217,28 @@ sub json_hint {
|
|||
sub check_password {
|
||||
my ($self, $password) = @_;
|
||||
|
||||
return String::Compare::ConstantTime::equals($self->password, sha1_hex($password));
|
||||
my $authenticator = Crypt::Passphrase->new(
|
||||
encoder => 'Argon2',
|
||||
validators => [
|
||||
(sub {
|
||||
my ($password, $hash) = @_;
|
||||
|
||||
return String::Compare::ConstantTime::equals($hash, sha1_hex($password));
|
||||
})
|
||||
],
|
||||
);
|
||||
|
||||
if ($authenticator->verify_password($password, $self->password)) {
|
||||
if ($authenticator->needs_rehash($self->password)) {
|
||||
$self->update({
|
||||
"password" => $authenticator->hash_password($password),
|
||||
});
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -11,11 +11,20 @@ use Test2::V0;
|
|||
my $db = Hydra::Model::DB->new;
|
||||
hydra_setup($db);
|
||||
|
||||
# Catalyst's default password checking is not constant time. To improve
|
||||
# the security of the system, we replaced the check password routine.
|
||||
# Verify comparing correct and incorrect passwords work.
|
||||
# Hydra used to store passwords, by default, as plain unsalted sha1 hashes.
|
||||
# We now upgrade these badly stored passwords with much stronger algorithms
|
||||
# when the user logs in. Implementing this meant reimplementing our password
|
||||
# checking ourselves, so also ensure that basic password checking works.
|
||||
#
|
||||
# This test:
|
||||
#
|
||||
# 1. creates a user with the legacy password
|
||||
# 2. validates that the wrong password is not considered valid
|
||||
# 3. validates that the correct password is valid
|
||||
# 4. checks that the checking of the correct password transparently upgraded
|
||||
# the password's storage to a more secure algorithm.
|
||||
|
||||
# Starting the user with a sha1 password
|
||||
# Starting the user with an unsalted sha1 password
|
||||
my $user = $db->resultset('Users')->create({
|
||||
"username" => "alice",
|
||||
"emailaddress" => 'alice@nixos.org',
|
||||
|
@ -24,6 +33,10 @@ my $user = $db->resultset('Users')->create({
|
|||
isnt($user, undef, "My user was created.");
|
||||
|
||||
ok(!$user->check_password("barbaz"), "Checking the password, barbaz, is not right");
|
||||
|
||||
is($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The unsalted sha1 is in the database.");
|
||||
ok($user->check_password("foobar"), "Checking the password, foobar, is right");
|
||||
isnt($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The user has had their password rehashed.");
|
||||
ok($user->check_password("foobar"), "Checking the password, foobar, is still right");
|
||||
|
||||
done_testing;
|
||||
|
|
Loading…
Reference in a new issue