From 79b0ddc27dec968dd7d7754320d3c57f69fe8344 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 16 Apr 2021 11:28:00 -0400 Subject: [PATCH] hydra-create-user: re-hash sha1 as Argon2 --- src/lib/Hydra/Schema/Users.pm | 11 +++++++ src/script/hydra-create-user | 5 +++- t/Schema/Users.t | 19 ++++++++++++ t/scripts/hydra-create-user.t | 56 +++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 t/scripts/hydra-create-user.t diff --git a/src/lib/Hydra/Schema/Users.pm b/src/lib/Hydra/Schema/Users.pm index 72686367..9f2e1bc0 100644 --- a/src/lib/Hydra/Schema/Users.pm +++ b/src/lib/Hydra/Schema/Users.pm @@ -258,4 +258,15 @@ sub setPassword { }); } +sub setPasswordHash { + my ($self, $passwordHash) = @_;; + + if ($passwordHash =~ /^[a-f0-9]{40}$/) { + # This is (probably) a sha1 password, re-hash it and we'll check for a hashed sha1 in Users.pm + $self->setPassword($passwordHash); + } else { + $self->update({ password => $passwordHash }); + } +} + 1; diff --git a/src/script/hydra-create-user b/src/script/hydra-create-user index 6e837270..0ed51bd8 100755 --- a/src/script/hydra-create-user +++ b/src/script/hydra-create-user @@ -109,7 +109,10 @@ $db->txn_do(sub { if (defined $password && !(defined $passwordHash)) { $user->setPassword($password); } - $user->update({ password => $passwordHash }) if defined $passwordHash; + + if (defined $passwordHash) { + $user->setPasswordHash($passwordHash); + } } $user->userroles->delete if $wipeRoles; diff --git a/t/Schema/Users.t b/t/Schema/Users.t index d8cbaf8c..fd1a66e1 100644 --- a/t/Schema/Users.t +++ b/t/Schema/Users.t @@ -50,4 +50,23 @@ subtest "Hashing their sha1 as Argon2 still lets them log in with their password isnt($user->password, $hashedHashPassword, "The user's hashed hash was replaced with just Argon2."); }; + +subtest "Setting the user's passwordHash to a sha1 stores the password as a hashed sha1" => sub { + $user->setPasswordHash("8843d7f92416211de9ebb963ff4ce28125932878"); + isnt($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The password was not saved in plain text."); + + my $storedPassword = $user->password; + ok($user->check_password("foobar"), "Their password validates"); + isnt($storedPassword, $user->password, "The password was upgraded."); +}; + +subtest "Setting the user's passwordHash to an argon2 password stores the password as given" => sub { + $user->setPasswordHash('$argon2id$v=19$m=262144,t=3,p=1$tMnV5paYjmIrUIb6hylaNA$M8/e0i3NGrjhOliVLa5LqQ'); + isnt($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The password was not saved in plain text."); + is($user->password, '$argon2id$v=19$m=262144,t=3,p=1$tMnV5paYjmIrUIb6hylaNA$M8/e0i3NGrjhOliVLa5LqQ', "The password was saved as-is."); + + my $storedPassword = $user->password; + ok($user->check_password("foobar"), "Their password validates"); + is($storedPassword, $user->password, "The password was not upgraded."); +}; done_testing; diff --git a/t/scripts/hydra-create-user.t b/t/scripts/hydra-create-user.t new file mode 100644 index 00000000..3706d911 --- /dev/null +++ b/t/scripts/hydra-create-user.t @@ -0,0 +1,56 @@ +use feature 'unicode_strings'; +use strict; +use Setup; + +my %ctx = test_init(); + +require Hydra::Schema; +require Hydra::Model::DB; + +use Test2::V0; + +my $db = Hydra::Model::DB->new; +hydra_setup($db); + +subtest "Handling password and password hash creation" => sub { + subtest "Creating a user with a plain text password (insecure) stores the password securely" => sub { + my ($res, $stdout, $stderr) = captureStdoutStderr(5, ("hydra-create-user", "plain-text-user", "--password", "foobar")); + is($res, 0, "hydra-create-user should exit zero"); + + my $user = $db->resultset('Users')->find({ username => "plain-text-user" }); + isnt($user, undef, "The user exists"); + isnt($user->password, "foobar", "The password was not saved in plain text."); + + my $storedPassword = $user->password; + ok($user->check_password("foobar"), "Their password validates"); + is($storedPassword, $user->password, "The password was not upgraded."); + }; + + subtest "Creating a user with a sha1 password (still insecure) stores the password as a hashed sha1" => sub { + my ($res, $stdout, $stderr) = captureStdoutStderr(5, ("hydra-create-user", "plain-text-user", "--password-hash", "8843d7f92416211de9ebb963ff4ce28125932878")); + is($res, 0, "hydra-create-user should exit zero"); + + my $user = $db->resultset('Users')->find({ username => "plain-text-user" }); + isnt($user, undef, "The user exists"); + isnt($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The password was not saved in plain text."); + + my $storedPassword = $user->password; + ok($user->check_password("foobar"), "Their password validates"); + isnt($storedPassword, $user->password, "The password was upgraded."); + }; + + subtest "Creating a user with an argon2 password stores the password as given" => sub { + my ($res, $stdout, $stderr) = captureStdoutStderr(5, ("hydra-create-user", "plain-text-user", "--password-hash", '$argon2id$v=19$m=262144,t=3,p=1$tMnV5paYjmIrUIb6hylaNA$M8/e0i3NGrjhOliVLa5LqQ')); + is($res, 0, "hydra-create-user should exit zero"); + + my $user = $db->resultset('Users')->find({ username => "plain-text-user" }); + isnt($user, undef, "The user exists"); + is($user->password, '$argon2id$v=19$m=262144,t=3,p=1$tMnV5paYjmIrUIb6hylaNA$M8/e0i3NGrjhOliVLa5LqQ', "The password was saved as-is."); + + my $storedPassword = $user->password; + ok($user->check_password("foobar"), "Their password validates"); + is($storedPassword, $user->password, "The password was not upgraded."); + }; +}; + +done_testing;