Users: transparently upgrade passwords to Argon2

[?]
Apr 15, 2021, 2:55 PM
56Q5PJPG6ASJV5OFPJZYBSFGDL3G55CDQE3JBKK7KTEBGXSAXAXAC

Dependencies

  • [2] 2G37UFZF flake: add TestPostgreSQL for per-test DBs
  • [3] ASPD4MDN Passwords: check in constant time
  • [4] S66BOMVU * Added authentication.
  • [5] SYLVCTT6 Start api cleanup with the User model
  • [*] RWNXH3H2 lastModified -> lastModifiedDate

Change contents

  • edit in flake.nix at line 70
    [2.1554]
    [2.1554]
    };
    };
    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;
  • edit in flake.nix at line 87
    [2.1583]
    [2.1583]
    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 ];
    };
    };
  • edit in flake.nix at line 311
    [7.1996]
    [7.1996]
    CryptPassphrase
    CryptPassphraseArgon2
  • edit in src/lib/Hydra/Schema/Users.pm at line 198
    [4.1839]
    [3.632]
    use Crypt::Passphrase;
  • replacement in src/lib/Hydra/Schema/Users.pm at line 220
    [3.754][3.754:842]()
    return String::Compare::ConstantTime::equals($self->password, sha1_hex($password));
    [3.754]
    [3.842]
    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;
    }
  • replacement in t/Schema/Users.t at line 14
    [3.1081][3.1081:1280]()
    # 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.
    [3.1081]
    [3.1280]
    # 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.
  • replacement in t/Schema/Users.t at line 27
    [3.1281][3.1281:1322]()
    # Starting the user with a sha1 password
    [3.1281]
    [3.1322]
    # Starting the user with an unsalted sha1 password
  • edit in t/Schema/Users.t at line 36
    [3.1649]
    [3.1649]
    is($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The unsalted sha1 is in the database.");
  • edit in t/Schema/Users.t at line 39
    [3.1729]
    [3.1729]
    isnt($user->password, "8843d7f92416211de9ebb963ff4ce28125932878", "The user has had their password rehashed.");
    ok($user->check_password("foobar"), "Checking the password, foobar, is still right");