So any one who has used perl dancer knows that to authenticate a user on login you can call authenticate_user
authenticate_user(
params->{username}, params->{password}
);
This is part of the Auth::Extensible plugin.
To me it looks like it encourages the use of storing passwords in plain text! Sure you can hash the password first then make sure the stored password is the same hash but this seems to be more of a work around and i found isn't guaranteed to work. I have only got this to work using sha1 which shouldn't be used. I want to use Bcrypt but the passphrase simply wont match. Possibly odd characters not matching i'm not sure.
The thing is using the dancer Passphrase plugin i can already validate the username and password without even needing to rely on authenticate_user to verify them. But for the dancer framework to consider the user logged in you still have to call authenticate_user which must be passed the password.
I'm completely stuck. I'm curious how other people have managed to use proper password management in dancer2?
Firstly, I'll echo the "you almost certainly don't need to be using authenticate_user()
" comments. The plugin can handle all that for you.
However, "it doesn't hash it" is wrong; here's how it works. The
authenticate_user
keyword loops through all auth realms configured, and for
each one, asks that provider's authenticate_user()
method to see if it accepts
the username and password. The Database
provider (and the others) fetch the
record from the DB, and use $self->match_password()
(which comes from the
Provider role) to validate it; that code checks if the stored password from
the database starts with {scheme}
and if so, uses
Crypt::SaltedHash->validate
to validate that the user-supplied password (in
plain text, as it's just come in over the wire) matches the stored, hashed
passsword ($correct
in the code below is the stored password):
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 );
}
So, yes, if your stored password in the database is hashed, then it will match it if the password supplied matches that hash.
For an example of what a stored hashed password should look like, here's
the output of the bundled generate-crypted-password
utility:
[davidp@supernova:~]$ generate-crypted-password
Enter plain-text password ?> hunter2
Result: {SSHA}z9llSLkkAXENw8FerEchzRxABeuJ6OPs
See the Crypt::SaltedHash doco for details on which algorhythms are supported by it, and the format it uses (which "comes from RFC-3112 and is extended by the use of different digital algorithms").
Do bear in mind that the code behind authenticate_user
is exactly what's used
under the hood for you.
For an example of just letting the plugin do the work for you, consider:
get '/secret' => require_login sub {
my $user = logged_in_user();
return "Hi, $user->{username}, let me tell you a secret";
};
... that's it. The require_login
means that the plugin will check
if the user is logged in, and if not, redirect them to the login page
to log in. You don't need to call authenticate_user
yourself, you
don't need to set any session variables or anything. logged_in_user()
will return a hashref of information about the logged in user (and because
the route code has require_login
, there's guaranteed to be one at this
point, so you don't need to check).
If you need to check they have a suitable role, instead of just that they
are logged in, then look at require_role
in the documentation instead.