@ -13,6 +13,7 @@ my $THIS_FILE = "Account.pm";
### Methods;
### Methods;
# encrypt_password
# encrypt_password
# read_details
# validate_password
# validate_password
@ -80,10 +81,10 @@ This takes a string (a new password from a user), generates a salt, appends the
This method returns a hash reference with the following keys ;
This method returns a hash reference with the following keys ;
* hash: The final encrypted hash .
* user_password_ hash: The final encrypted hash .
* salt: The salt created ( or used ) to generate the hash .
* user_ salt: The salt created ( or used ) to generate the hash .
* algorithm: The algorithm used to compute the hash .
* user_ algorithm: The algorithm used to compute the hash .
* loops: The number of re - encryptions of the initial hash .
* user_hash_count: The number of re - encryptions of the initial hash .
If anything goes wrong , all four keys will have empty strings .
If anything goes wrong , all four keys will have empty strings .
@ -93,10 +94,6 @@ Parameters
This is the password ( string ) to encrypt .
This is the password ( string ) to encrypt .
= head3 salt ( optional )
If passed , this string will be appended to the password to salt the string . If this is not passed , a random , new hash
= cut
= cut
sub encrypt_password
sub encrypt_password
{
{
@ -105,109 +102,200 @@ sub encrypt_password
my $ anvil = $ self - > parent ;
my $ anvil = $ self - > parent ;
my $ debug = defined $ parameter - > { debug } ? $ parameter - > { debug } : 3 ;
my $ debug = defined $ parameter - > { debug } ? $ parameter - > { debug } : 3 ;
my $ password = defined $ parameter - > { password } ? $ parameter - > { password } : "" ;
my $ user_password_hash = defined $ parameter - > { password } ? $ parameter - > { password } : "" ;
my $ salt = defined $ parameter - > { salt } ? $ parameter - > { target } : "" ;
my $ user_hash_count = $ anvil - > data - > { sys } { password } { hash_count } =~ /^\d+$/ ? $ anvil - > data - > { sys } { password } { hash_count } : 500000 ;
my $ hash = "" ;
my $ user_algorithm = $ anvil - > data - > { sys } { password } { algorithm } ? $ anvil - > data - > { sys } { password } { algorithm } : "sha512" ;
my $ loops = $ anvil - > data - > { sys } { password } { hash_count } =~ /^\d+$/ ? $ anvil - > data - > { sys } { password } { hash_count } : 500000 ;
my $ algorithm = $ anvil - > data - > { sys } { password } { algorithm } ? $ anvil - > data - > { sys } { password } { algorithm } : "sha512" ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
password = > $ anvil - > Log - > secure ? $ password : "--" ,
password = > $ anvil - > Log - > secure ? $ user_password_hash : "--" ,
salt = > $ salt ,
} } ) ;
} } ) ;
# We'll fill these out below if we succeed.
# We'll fill these out below if we succeed.
my $ answer = {
my $ answer = {
hash = > "" ,
user_password_ hash = > "" ,
salt = > "" ,
user_ salt = > "" ,
loops = > "" ,
user_hash_count = > "" ,
algorithm = > "" ,
user_ algorithm = > "" ,
} ;
} ;
# Make sure we got a string
# Make sure we got a string
if ( not $ password )
if ( not $ user_ password_hash )
{
{
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Account->encrypt_password()" , parameter = > "password" } } ) ;
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0020" , variables = > { method = > "Account->encrypt_password()" , parameter = > "password" } } ) ;
return ( $ answer ) ;
return ( $ answer ) ;
}
}
# If we weren't passed a salt, generate one node.
# Generate a salt.
if ( not $ salt )
my $ user_salt = $ anvil - > Get - > _salt ;
{
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_salt = > $ user_salt } } ) ;
$ salt = $ anvil - > Get - > _salt ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { salt = > $ salt } } ) ;
}
### TODO: Look at using/support bcrypt as the default algorithm. Needed RPMs are already in the el7 AN!Repo.
### TODO: Look at using/support bcrypt as the default algorithm. Needed RPMs are already in the el7 AN!Repo.
# We support sha256, sha384 and sha512, possible new ones later.
# We support sha256, sha384 and sha512, possible new ones later.
if ( $ algorithm eq "sha256" )
if ( $ user_ algorithm eq "sha256" )
{
{
$ hash = sha256_base64 ( $ password . $ salt ) ;
$ user_password_ hash = sha256_base64 ( $ user_ password_hash . $ user_ salt) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { hash = > $ hash } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_password_ hash = > $ user_password_ hash } } ) ;
if ( $ loops > 0 )
if ( $ user_hash_count > 0 )
{
{
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { loops = > $ loops } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_hash_count = > $ user_hash_count } } ) ;
for ( 1 .. $ loops )
for ( 1 .. $ user_hash_count )
{
{
$ hash = sha256_base64 ( $ hash ) ;
$ user_password_ hash = sha256_base64 ( $ user_password_ hash) ;
}
}
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { hash = > $ hash } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_password_ hash = > $ user_password_ hash } } ) ;
}
}
}
}
elsif ( $ algorithm eq "sha384" )
elsif ( $ user_ algorithm eq "sha384" )
{
{
$ hash = sha384_base64 ( $ password . $ salt ) ;
$ user_password_ hash = sha384_base64 ( $ user_ password_hash . $ user_ salt) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { hash = > $ hash } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_password_ hash = > $ user_password_ hash } } ) ;
if ( $ loops > 0 )
if ( $ user_hash_count > 0 )
{
{
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { loops = > $ loops } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_hash_count = > $ user_hash_count } } ) ;
for ( 1 .. $ loops )
for ( 1 .. $ user_hash_count )
{
{
$ hash = sha384_base64 ( $ hash ) ;
$ user_password_ hash = sha384_base64 ( $ user_password_ hash) ;
}
}
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { hash = > $ hash } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_password_ hash = > $ user_password_ hash } } ) ;
}
}
}
}
elsif ( $ algorithm eq "sha512" )
elsif ( $ user_ algorithm eq "sha512" )
{
{
$ hash = sha512_base64 ( $ password . $ salt ) ;
$ user_password_ hash = sha512_base64 ( $ user_ password_hash . $ user_ salt) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { hash = > $ hash } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_password_ hash = > $ user_password_ hash } } ) ;
if ( $ loops > 0 )
if ( $ user_hash_count > 0 )
{
{
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { loops = > $ loops } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_hash_count = > $ user_hash_count } } ) ;
for ( 1 .. $ loops )
for ( 1 .. $ user_hash_count )
{
{
$ hash = sha512_base64 ( $ hash ) ;
$ user_password_ hash = sha512_base64 ( $ user_password_ hash) ;
}
}
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { hash = > $ hash } } ) ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_password_ hash = > $ user_password_ hash } } ) ;
}
}
}
}
else
else
{
{
# Bash algorith.
# Bash algorith.
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0171" , variables = > { algorithm = > $ algorithm } } ) ;
$ anvil - > Log - > entry ( { source = > $ THIS_FILE , line = > __LINE__ , level = > 0 , priority = > "err" , key = > "log_0171" , variables = > { user_ algorithm = > $ user_ algorithm } } ) ;
return ( $ answer ) ;
return ( $ answer ) ;
}
}
$ answer = {
$ answer = {
hash = > $ hash ,
user_password_ hash = > $ user_password_ hash,
salt = > $ salt ,
user_ salt = > $ user_ salt,
loops = > $ loops ,
user_hash_count = > $ user_hash_count ,
algorithm = > $ algorithm ,
user_ algorithm = > $ user_ algorithm,
} ;
} ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
'answer->hash' = > $ answer - > { hash } ,
'answer->user_password_ hash' = > $ answer - > { user_password_ hash} ,
'answer->salt' = > $ answer - > { salt } ,
'answer->user_ salt' = > $ answer - > { user_ salt} ,
'answer->loops' = > $ answer - > { loops } ,
'answer->user_hash_count' = > $ answer - > { user_hash_count } ,
'answer->algorithm' = > $ answer - > { algorithm } ,
'answer->user_ algorithm' = > $ answer - > { user_ algorithm} ,
} } ) ;
} } ) ;
return ( $ answer ) ;
return ( $ answer ) ;
}
}
= head2 read_details
This method takes a user name and , if the user is found , reads in the details and sets C << sys::user:: < column names > >> . If the user is found , C << 1 >> is returned . If not , C << 0 >> is returned .
Parameters ;
= head3 user_name ( required )
This is the user name being searched for . It is case sensitive .
= cut
sub read_details
{
my $ self = shift ;
my $ parameter = shift ;
my $ anvil = $ self - > parent ;
my $ debug = defined $ parameter - > { debug } ? $ parameter - > { debug } : 3 ;
my $ user_name = defined $ parameter - > { user_name } ? $ parameter - > { user_name } : "" ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > { user_name = > $ user_name } } ) ;
my $ query = "
SELECT
user_uuid ,
user_password_hash ,
user_salt ,
user_algorithm ,
user_hash_count ,
user_language ,
user_is_admin ,
user_is_experienced ,
user_is_trusted
FROM
users
WHERE
user_name = ".$anvil->data->{sys}{use_db_fh}->quote($user_name)."
; " ;
$ 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 doesn't exist.
return ( 0 ) ;
}
my $ user_uuid = $ results - > [ 0 ] - > [ 0 ] ;
my $ user_password_hash = $ results - > [ 0 ] - > [ 1 ] ;
my $ user_salt = $ results - > [ 0 ] - > [ 2 ] ;
my $ user_algorithm = $ results - > [ 0 ] - > [ 3 ] ;
my $ user_hash_count = $ results - > [ 0 ] - > [ 4 ] ;
my $ user_language = $ results - > [ 0 ] - > [ 5 ] ;
my $ user_is_admin = $ results - > [ 0 ] - > [ 6 ] ;
my $ user_is_experienced = $ results - > [ 0 ] - > [ 7 ] ;
my $ user_is_trusted = $ results - > [ 0 ] - > [ 8 ] ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
user_uuid = > $ user_uuid ,
user_password_hash = > $ user_password_hash ,
user_salt = > $ user_salt ,
user_algorithm = > $ user_algorithm ,
user_hash_count = > $ user_hash_count ,
user_language = > $ user_language ,
user_is_admin = > $ user_is_admin ,
user_is_experienced = > $ user_is_experienced ,
user_is_trusted = > $ user_is_trusted ,
} } ) ;
$ anvil - > data - > { sys } { user } { user_name } = $ user_name ;
$ anvil - > data - > { sys } { user } { user_uuid } = $ user_uuid ;
$ anvil - > data - > { sys } { user } { user_password_hash } = $ user_password_hash ,
$ anvil - > data - > { sys } { user } { user_salt } = $ user_salt ,
$ anvil - > data - > { sys } { user } { user_algorithm } = $ user_algorithm ,
$ anvil - > data - > { sys } { user } { user_hash_count } = $ user_hash_count ,
$ anvil - > data - > { sys } { user } { user_language } = $ user_language ,
$ anvil - > data - > { sys } { user } { user_is_admin } = $ user_is_admin ,
$ anvil - > data - > { sys } { user } { user_is_experienced } = $ user_is_experienced ,
$ anvil - > data - > { sys } { user } { user_is_trusted } = $ user_is_trusted ,
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
'sys::user::user_name' = > $ anvil - > data - > { sys } { user } { user_name } ,
'sys::user::user_uuid' = > $ anvil - > data - > { sys } { user } { user_uuid } ,
'sys::user::user_password_hash' = > $ anvil - > data - > { sys } { user } { user_password_hash } ,
'sys::user::user_salt' = > $ anvil - > data - > { sys } { user } { user_salt } ,
'sys::user::user_algorithm' = > $ anvil - > data - > { sys } { user } { user_algorithm } ,
'sys::user::user_hash_count' = > $ anvil - > data - > { sys } { user } { user_hash_count } ,
'sys::user::user_language' = > $ anvil - > data - > { sys } { user } { user_language } ,
'sys::user::user_is_admin' = > $ anvil - > data - > { sys } { user } { user_is_admin } ,
'sys::user::user_is_experienced' = > $ anvil - > data - > { sys } { user } { user_is_experienced } ,
'sys::user::user_is_trusted' = > $ anvil - > data - > { sys } { user } { user_is_trusted } ,
} } ) ;
return ( 1 ) ;
}
= head2 validate_password
= head2 validate_password
This method takes a user name and password and checks to see if the password matches .
This method takes a user name and password and checks to see if the password matches .
@ -254,7 +342,7 @@ sub validate_password
my $ query = "
my $ query = "
SELECT
SELECT
user_password ,
user_password_hash ,
user_salt ,
user_salt ,
user_algorithm ,
user_algorithm ,
user_hash_count
user_hash_count
@ -279,15 +367,15 @@ WHERE
return ( $ valid ) ;
return ( $ valid ) ;
}
}
my $ user_password = $ results - > [ 0 ] - > [ 0 ] ;
my $ user_password_hash = $ results - > [ 0 ] - > [ 0 ] ;
my $ user_salt = $ results - > [ 0 ] - > [ 1 ] ;
my $ user_salt = $ results - > [ 0 ] - > [ 1 ] ;
my $ user_algorithm = $ results - > [ 0 ] - > [ 2 ] ;
my $ user_algorithm = $ results - > [ 0 ] - > [ 2 ] ;
my $ user_hash_count = $ results - > [ 0 ] - > [ 3 ] ;
my $ user_hash_count = $ results - > [ 0 ] - > [ 3 ] ;
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
$ anvil - > Log - > variables ( { source = > $ THIS_FILE , line = > __LINE__ , level = > $ debug , list = > {
user_password = > $ user_password ,
user_password_hash = > $ user_password_hash ,
user_salt = > $ user_salt ,
user_salt = > $ user_salt ,
user_algorithm = > $ user_algorithm ,
user_algorithm = > $ user_algorithm ,
user_hash_count = > $ user_hash_count ,
user_hash_count = > $ user_hash_count ,
} } ) ;
} } ) ;
if ( $ user_algorithm eq "sha256" )
if ( $ user_algorithm eq "sha256" )
@ -343,7 +431,7 @@ WHERE
}
}
# Test.
# Test.
if ( $ hash eq $ user_password )
if ( $ hash eq $ user_password_hash )
{
{
# Good password.
# Good password.
$ valid = 1 ;
$ valid = 1 ;