Merge pull request #915 from grahamc/hydra-auth
Hydra auth: support Argon2, transparently upgrade hashes
This commit is contained in:
@ -27,27 +27,25 @@ our $VERSION = '0.01';
|
||||
__PACKAGE__->config(
|
||||
name => 'Hydra',
|
||||
default_view => "TT",
|
||||
authentication => {
|
||||
'Plugin::Authentication' => {
|
||||
default_realm => "dbic",
|
||||
realms => {
|
||||
dbic => {
|
||||
credential => {
|
||||
class => "Password",
|
||||
password_field => "password",
|
||||
password_type => "hashed",
|
||||
password_hash_type => "SHA-1",
|
||||
},
|
||||
store => {
|
||||
class => "DBIx::Class",
|
||||
user_class => "DB::Users",
|
||||
role_relation => "userroles",
|
||||
role_field => "role",
|
||||
},
|
||||
|
||||
dbic => {
|
||||
credential => {
|
||||
class => "Password",
|
||||
password_field => "password",
|
||||
password_type => "self_check",
|
||||
},
|
||||
store => {
|
||||
class => "DBIx::Class",
|
||||
user_class => "DB::Users",
|
||||
role_relation => "userroles",
|
||||
role_field => "role",
|
||||
},
|
||||
ldap => $ENV{'HYDRA_LDAP_CONFIG'} ? LoadFile(
|
||||
file($ENV{'HYDRA_LDAP_CONFIG'})
|
||||
) : undef
|
||||
},
|
||||
ldap => $ENV{'HYDRA_LDAP_CONFIG'} ? LoadFile(
|
||||
file($ENV{'HYDRA_LDAP_CONFIG'})
|
||||
) : undef
|
||||
},
|
||||
'Plugin::Static::Simple' => {
|
||||
send_etag => 1,
|
||||
|
@ -6,7 +6,6 @@ use base 'Catalyst::Controller';
|
||||
use Hydra::Helper::Nix;
|
||||
use Hydra::Helper::CatalystUtils;
|
||||
use Data::Dump qw(dump);
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use Config::General;
|
||||
|
||||
|
||||
|
@ -7,7 +7,6 @@ use base 'Hydra::Base::Controller::ListBuilds';
|
||||
use Hydra::Helper::Nix;
|
||||
use Hydra::Helper::CatalystUtils;
|
||||
use Hydra::View::TT;
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use Nix::Store;
|
||||
use Nix::Config;
|
||||
use Encode;
|
||||
|
@ -229,12 +229,6 @@ sub isValidPassword {
|
||||
}
|
||||
|
||||
|
||||
sub setPassword {
|
||||
my ($user, $password) = @_;
|
||||
$user->update({ password => sha1_hex($password) });
|
||||
}
|
||||
|
||||
|
||||
sub register :Local Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
@ -294,7 +288,7 @@ sub updatePreferences {
|
||||
error($c, "The passwords you specified did not match.")
|
||||
if $password ne trim $c->stash->{params}->{password2};
|
||||
|
||||
setPassword($user, $password);
|
||||
$user->setPassword($password);
|
||||
}
|
||||
|
||||
my $emailAddress = trim($c->stash->{params}->{emailaddress} // "");
|
||||
@ -394,7 +388,7 @@ sub reset_password :Chained('user') :PathPart('reset-password') :Args(0) {
|
||||
unless $user->emailaddress;
|
||||
|
||||
my $password = Crypt::RandPasswd->word(8,10);
|
||||
setPassword($user, $password);
|
||||
$user->setPassword($password);
|
||||
sendEmail(
|
||||
$c->config,
|
||||
$user->emailaddress,
|
||||
|
@ -195,6 +195,10 @@ __PACKAGE__->many_to_many("projects", "projectmembers", "project");
|
||||
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2020-02-06 12:22:36
|
||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:4/WZ95asbnGmK+nEHb4sLQ
|
||||
|
||||
use Crypt::Passphrase;
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use String::Compare::ConstantTime;
|
||||
|
||||
my %hint = (
|
||||
columns => [
|
||||
"fullname",
|
||||
@ -210,4 +214,42 @@ sub json_hint {
|
||||
return \%hint;
|
||||
}
|
||||
|
||||
sub _authenticator() {
|
||||
my $authenticator = Crypt::Passphrase->new(
|
||||
encoder => 'Argon2',
|
||||
validators => [
|
||||
(sub {
|
||||
my ($password, $hash) = @_;
|
||||
|
||||
return String::Compare::ConstantTime::equals($hash, sha1_hex($password));
|
||||
})
|
||||
],
|
||||
);
|
||||
|
||||
return $authenticator;
|
||||
}
|
||||
|
||||
sub check_password {
|
||||
my ($self, $password) = @_;
|
||||
|
||||
my $authenticator = _authenticator();
|
||||
if ($authenticator->verify_password($password, $self->password)) {
|
||||
if ($authenticator->needs_rehash($self->password)) {
|
||||
$self->setPassword($password);
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub setPassword {
|
||||
my ($self, $password) = @_;;
|
||||
|
||||
$self->update({
|
||||
"password" => _authenticator()->hash_password($password),
|
||||
});
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -5,17 +5,16 @@ use Hydra::Schema;
|
||||
use Hydra::Helper::Nix;
|
||||
use Hydra::Model::DB;
|
||||
use Getopt::Long qw(:config gnu_getopt);
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
|
||||
sub showHelp {
|
||||
print <<EOF;
|
||||
Usage: $0 NAME
|
||||
print q%
|
||||
Usage: hydra-create-user NAME
|
||||
[--rename-from NAME]
|
||||
[--type hydra|google|github]
|
||||
[--full-name FULLNAME]
|
||||
[--email-address EMAIL-ADDRESS]
|
||||
[--password PASSWORD]
|
||||
[--password-hash SHA1-HASH]
|
||||
[--password-hash HASH]
|
||||
[--wipe-roles]
|
||||
[--role ROLE]...
|
||||
|
||||
@ -25,9 +24,31 @@ exists, roles are added to the existing roles unless --wipe-roles is
|
||||
specified. If --rename-from is given, the specified account is
|
||||
renamed.
|
||||
|
||||
Example:
|
||||
\$ hydra-create-user alice --password foobar --role admin
|
||||
EOF
|
||||
* PASSWORD HASH
|
||||
The password hash should be an Argon2id hash, which can be generated
|
||||
via:
|
||||
|
||||
$ nix-shell -p libargon2
|
||||
[nix-shell]$ argon2 "$(LC_ALL=C tr -dc '[:alnum:]' < /dev/urandom | head -c16)" -id -t 3 -k 262144 -p 1 -l 16 -e
|
||||
foobar
|
||||
Ctrl^D
|
||||
$argon2id$v=19$m=262144,t=3,p=1$NFU1QXJRNnc4V1BhQ0NJQg$6GHqjqv5cNDDwZqrqUD0zQ
|
||||
|
||||
SHA1 is also accepted, but SHA1 support is deprecated and the user's
|
||||
password will be upgraded to Argon2id on first login.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
Create a user with an argon2 password:
|
||||
|
||||
$ hydra-create-user alice --password-hash '$argon2id$v=19$m=262144,t=3,p=1$NFU1QXJRNnc4V1BhQ0NJQg$6GHqjqv5cNDDwZqrqUD0zQ' --role admin
|
||||
|
||||
Create a user with a password insecurely provided on the commandline:
|
||||
|
||||
$ hydra-create-user alice --password foobar --role admin
|
||||
|
||||
%;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
@ -84,8 +105,9 @@ $db->txn_do(sub {
|
||||
$user->update({ emailaddress => $userName, password => "!" });
|
||||
} else {
|
||||
$user->update({ emailaddress => $emailAddress }) if defined $emailAddress;
|
||||
|
||||
if (defined $password && !(defined $passwordHash)) {
|
||||
$passwordHash = sha1_hex($password);
|
||||
$user->setPassword($password);
|
||||
}
|
||||
$user->update({ password => $passwordHash }) if defined $passwordHash;
|
||||
}
|
||||
|
Reference in New Issue
Block a user