Articulate
view release on metacpan or search on metacpan
lib/Articulate/Authentication/Internal.pm view on Meta::CPAN
package Articulate::Authentication::Internal;
use strict;
use warnings;
use Moo;
use Digest::SHA;
use Time::HiRes; # overrides time()
=head1 NAME
Articulate::Authentication::Internal
=cut
=head1 METHODS
=cut
=head3 authenticate
$self->authenticate( $credentials );
Accepts and returns the credentials if the C<password> matches the C<user_id>. Always returns the credentials passed in.
=cut
has extra_salt => (
is => 'rw',
default => "If you haven't already, try powdered vegetable bouillon"
);
sub authenticate {
my $self = shift;
my $credentials = shift;
my $user_id = $credentials->fields->{user_id} // return;
my $password = $credentials->fields->{password} // return;
if ( $self->verify_password( $user_id, $password ) ) {
return $credentials->accept('Passwords match');
}
# if we ever need to know if the user does not exist, now is the time to ask,
# but we do not externally expose the difference between
# "user not found" and "password doesn't match"
return $credentials;
}
sub _password_salt_and_hash {
my $self = shift;
return Digest::SHA::sha512_base64(
$_[0] . $_[1] #:5.10 doesn't like shift . shift
);
}
sub _generate_salt {
# pseudorandom salt
my $self = shift;
return Digest::SHA::sha512_base64(
time . (
$self->extra_salt # don't allow the admin not to set a salt:
)
);
}
=head3 verify_password
$self->verify_password( $user_id, $password );
Hashes the password provided with the user's salt and checks to see if the string matches the encrypted password in the user's meta.
Returns the result of C<eq>.
=cut
sub verify_password {
my ( $self, $user_id, $plaintext_password ) = @_;
my $user_meta = $self->storage->get_meta("/users/$user_id");
my $real_encrypted_password = $user_meta->{encrypted_password};
my $salt = $user_meta->{salt};
return undef
unless defined $real_encrypted_password and defined $plaintext_password;
return ( $real_encrypted_password eq
$self->_password_salt_and_hash( $plaintext_password, $salt ) );
}
=head3 set_password
$self->set_password( $user_id, $password );
Creates a new pseudorandom salt and uses it to hash the password provided.
Amends the C<encrypted_password> and C<salt> fields of the user's meta.
=cut
# note: currently this implicitly creates a user. Should set/patch create new content, or just edit it?
# maybe a create verb - but is is this going to be compatible with kvp stores? How will this work when you have content and meta and settings all to be created?
sub set_password {
my ( $self, $user_id, $plaintext_password ) = @_;
return undef
unless $plaintext_password; # as empty passwords will only cause trouble.
( run in 1.733 second using v1.01-cache-2.11-cpan-524268b4103 )