hydra-create-user: re-hash sha1 as Argon2

[?]
Apr 16, 2021, 3:28 PM
SNXMD4NOZLKDEFSNO73VGFQPIUBC525FOH2H2WRR4MTKJABJIGRAC

Dependencies

  • [2] BVFH3BWM hydra-create-user now has `--password-hash` option (#504)
  • [3] DNOLOMX7 hydra-send-stats: add a failing test asserting it can run
  • [4] QA7SEIVP Users: password changes via the web UI now use Argon2
  • [5] HY2SSCWG Users: add a validation step which lets the user's password be a Argon2 hashed sha1 hash.
  • [6] XHOZT4WT Add a command `hydra-create-user' for managing user accounts
  • [7] XXHU6BCO hydra-create-user: support Argon2
  • [*] S66BOMVU * Added authentication.
  • [*] ASPD4MDN Passwords: check in constant time

Change contents

  • edit in src/lib/Hydra/Schema/Users.pm at line 260
    [4.420]
    [4.420]
    sub setPasswordHash {
    my ($self, $passwordHash) = @_;;
  • edit in src/lib/Hydra/Schema/Users.pm at line 264
    [4.421]
    [9.4016]
    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 });
    }
    }
  • replacement in src/script/hydra-create-user at line 112
    [2.377][2.377:456]()
    $user->update({ password => $passwordHash }) if defined $passwordHash;
    [2.377]
    [6.3166]
    if (defined $passwordHash) {
    $user->setPasswordHash($passwordHash);
    }
  • edit in t/Schema/Users.t at line 51
    [5.1067]
    [5.1067]
    };
    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.");
  • edit in t/Schema/Users.t at line 63
    [5.1071]
    [10.1730]
    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.");
    };
  • file addition: hydra-create-user.t (----------)
    [3.277]
    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;