diff --git a/Anvil/Tools/Account.pm b/Anvil/Tools/Account.pm index 587e0c6a..953a52f9 100755 --- a/Anvil/Tools/Account.pm +++ b/Anvil/Tools/Account.pm @@ -13,7 +13,7 @@ my $THIS_FILE = "Account.pm"; ### Methods; # encrypt_password -# +# validate_password =pod @@ -208,4 +208,149 @@ sub encrypt_password return($answer); } +=head2 validate_password + +This method takes a user name and password and checks to see if the password matches. + +If the password is wrong, or if the user isn't found, C<< 0 >> is returned. If the password matches, C<< 1 >> is returned. + +Parameters; + +=head3 password (required) + +This is the password to test. + +=head3 user (required) + +This is the user whose password we're testing. + +=cut +sub validate_password +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + + my $password = defined $parameter->{password} ? $parameter->{password} : ""; + my $user = defined $parameter->{user} ? $parameter->{user} : ""; + my $valid = 0; + my $hash = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + password => $anvil->Log->secure ? $password : "--", + user => $user, + }}); + + if (not $password) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Account->validate_password()", parameter => "password" }}); + return($valid); + } + if (not $user) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Account->validate_password()", parameter => "user" }}); + return($valid); + } + + my $query = " +SELECT + user_password, + user_salt, + user_algorithm, + user_hash_count +FROM + users +WHERE + user_name = ".$anvil->data->{sys}{use_db_fh}->quote($user)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); + + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + results => $results, + count => $count, + }}); + + if (not $count) + { + # User not found. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0172", variables => { user => $user }}); + return($valid); + } + + my $user_password = $results->[0]->[0]; + my $user_salt = $results->[0]->[1]; + my $user_algorithm = $results->[0]->[2]; + my $user_hash_count = $results->[0]->[3]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + user_password => $user_password, + user_salt => $user_salt, + user_algorithm => $user_algorithm, + user_hash_count => $user_hash_count, + }}); + + if ($user_algorithm eq "sha256" ) + { + $hash = sha256_base64($password.$user_salt); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hash => $hash }}); + + if ($user_hash_count > 0) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user_hash_count => $user_hash_count }}); + for (1..$user_hash_count) + { + $hash = sha256_base64($hash); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hash => $hash }}); + } + } + elsif ($user_algorithm eq "sha384" ) + { + $hash = sha384_base64($password.$user_salt); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hash => $hash }}); + + if ($user_hash_count > 0) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user_hash_count => $user_hash_count }}); + for (1..$user_hash_count) + { + $hash = sha384_base64($hash); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hash => $hash }}); + } + } + elsif ($user_algorithm eq "sha512" ) + { + $hash = sha512_base64($password.$user_salt); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hash => $hash }}); + + if ($user_hash_count > 0) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user_hash_count => $user_hash_count }}); + for (1..$user_hash_count) + { + $hash = sha512_base64($hash); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { hash => $hash }}); + } + } + else + { + # Bad algorith. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0173", variables => { user_algorithm => $user_algorithm }}); + return($valid); + } + + # Test. + if ($hash eq $user_password) + { + # Good password. + $valid = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { valid => $valid }}); + } + + return($valid); +} + 1; diff --git a/share/words.xml b/share/words.xml index 106ae117..4b7bffbb 100644 --- a/share/words.xml +++ b/share/words.xml @@ -251,6 +251,8 @@ The database connection error was: Failed to copy the file: [#!variable!source_file!#] to: [#!variable!target_file!#] on the target: [#!variable!target!#] as: [#!variable!remote_user!#]. The error (if any) was: [#!variable!error!#] and the output (if any) was: [#!variable!output!#]. copy_file() was asked to copy: [#!variable!source_file!#] to: [#!variable!target_file!#], but the target's parent directory doesn't exist and we were unable to create it.]]> encrypt_password() tried to use the algorithm: [#!variable!algorithm!#], which is not recognized. Only 'sha256', 'sha384' and 'sha512' are currently supported. The desired algorithm can be set via 'sys::password::algorithm'.]]> + + Test diff --git a/tools/anvil-change-password b/tools/anvil-change-password index b60501e1..1c3f8932 100755 --- a/tools/anvil-change-password +++ b/tools/anvil-change-password @@ -58,18 +58,26 @@ if (not $connections) $anvil->nice_exit({exit_code => 2}); } -my $user_uuid = $anvil->Database->insert_or_update_users({ - debug => 2, - user_name => "admin", - user_password => "Initial2", - user_salt => "", - user_algorithm => "", - user_hash_count => "", - user_is_admin => 1, - user_is_experienced => 1, - user_is_trusted => 1, +my $user = "admin"; +my $password = "Initial2"; +# my $user_uuid = $anvil->Database->insert_or_update_users({ +# debug => 2, +# user_name => $user, +# user_password => $password, +# user_salt => "", +# user_algorithm => "", +# user_hash_count => "", +# user_is_admin => 1, +# user_is_experienced => 1, +# user_is_trusted => 1, +# }); +# print "User name: [".$user."], UUID: [".$user_uuid."]\n"; +my $valid = $anvil->Account->validate_password({ + debug => 2, + user => $user, + password => $password, }); -print "User UUID: [".$user_uuid."]\n"; +print "Password validated? [".$valid."].\n"; exit; # The order that we pick up the new password is;