From 031351861c5d74588a3188caf2f5039c33dae44d Mon Sep 17 00:00:00 2001 From: Pawel Date: Wed, 14 Jan 2026 12:48:01 +0000 Subject: [PATCH 1/2] Updated match_password/encrypt_password methods to use Crypt::Passphrase for validation/encryption --- .../Plugin/Auth/Extensible/Role/Provider.pm | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm b/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm index 4c77ffb..9876175 100644 --- a/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm +++ b/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm @@ -1,10 +1,12 @@ package Dancer2::Plugin::Auth::Extensible::Role::Provider; use Crypt::SaltedHash; +use Crypt::Passphrase; +use Crypt::Passphrase::Argon2; use Moo::Role; requires qw(authenticate_user); -our $VERSION = '0.710'; +our $VERSION = '0.712'; =head1 NAME @@ -49,13 +51,15 @@ has disable_roles => ( The encryption_algorithm used by L. -Defaults to 'SHA-512'; +Defaults to 'Argon2'; =cut has encryption_algorithm => ( is => 'ro', - default => 'SHA-512', + default => sub { + Crypt::Passphrase::Argon2->new; + }, ); =head1 METHODS @@ -71,35 +75,34 @@ sub match_password { # If $correct is undefined, then do not attempt a match, otherwise an # uninnitialized warning will be thrown. If stack trace warnings are - # enabled and if the user is using a password that is correct for another - # system, then the user's attempted password may be written in logs. This - # is certainly an edge-case, but it has happened :) - # Also as a safety check, do not allow blank passwords, in case a user has - # not set a password yet and a blank password is submitted for - # authentication. + # enabled, the user's attempted password may be written in logs. + # Also as a safety check, do not allow blank passwords. $correct or return; - - # TODO: perhaps we should accept a configuration option to state whether - # passwords are crypted or not, rather than guessing by looking for the - # {...} tag at the start. - # I wanted to let it try straightforward comparison first, then try - # Crypt::SaltedHash->validate, but that has a weakness: if a list of hashed - # passwords got leaked, you could use the hashed password *as it is* to log - # in, rather than cracking it first. That's obviously Not Fucking Good. - # TODO: think about this more. This shit is important. I'm thinking a - # config option to indicate whether passwords are crypted - yes, no, auto + + # TODO: A config option to indicate whether passwords are crypted - yes, no, auto # (where auto would do the current guesswork, and yes/no would just do as # told.) + if ( $correct =~ /^{.+}/ ) { - - # Looks like a crypted password starting with the scheme, so try to - # validate it with Crypt::SaltedHash: - return Crypt::SaltedHash->validate( $correct, $given ); - } - else { - # Straightforward comparison, then: - return $given eq $correct; + # Looks like a legacy crypted password starting with the scheme, so try to + # validate it with Crypt::SaltedHash. + return { + valid => Crypt::SaltedHash->validate( $correct, $given ), + legacy => 1, + }; } + + # Not validated by legacy validator, so now check with Crypt::Passphrase. + # If unsuccessful, valid will return false. + + my $passphrase = Crypt::Passphrase->new( + encoder => $self->encryption_algorithm, + ); + + return { + valid => $passphrase->verify_password( $given, $correct ), + legacy => 0, + }; } =head2 encrypt_password $password @@ -111,10 +114,10 @@ and returns the encrypted password. sub encrypt_password { my ( $self, $password ) = @_; - my $crypt = - Crypt::SaltedHash->new( algorithm => $self->encryption_algorithm ); - $crypt->add($password); - $crypt->generate; + my $passphrase = Crypt::Passphrase->new( + encoder => $self->encryption_algorithm, + ); + return $passphrase->hash_password($password); } =head1 METHODS IMPLEMENTED BY PROVIDER From 7f9d2f59c61d2bd536b1982678a7cd0fae2ba336 Mon Sep 17 00:00:00 2001 From: Pawel Date: Tue, 14 Apr 2026 10:24:01 +0100 Subject: [PATCH 2/2] Added stricter regex and return values upon failure --- lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm b/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm index 9876175..bd51f80 100644 --- a/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm +++ b/lib/Dancer2/Plugin/Auth/Extensible/Role/Provider.pm @@ -77,13 +77,15 @@ sub match_password { # uninnitialized warning will be thrown. If stack trace warnings are # enabled, the user's attempted password may be written in logs. # Also as a safety check, do not allow blank passwords. - $correct or return; + return { valid => 0, legacy => undef } + unless defined $correct && length $correct; # TODO: A config option to indicate whether passwords are crypted - yes, no, auto # (where auto would do the current guesswork, and yes/no would just do as # told.) - if ( $correct =~ /^{.+}/ ) { + if ( $correct =~ /^\{\w+\}/ ) + { # Looks like a legacy crypted password starting with the scheme, so try to # validate it with Crypt::SaltedHash. return {