use MIME::Base64; use Test::More; use strict; use IO::String; require 't/test-lib.pm'; my $res; my $maintests = 6; my $userdb = tempdb(); SKIP: { eval 'require DBD::SQLite; use Digest::SHA; use Lemonldap::NG::Portal::Lib::DBI'; if ($@) { skip 'DBI/DBD::SQLite not found', $maintests; } eval q` no warnings 'redefine'; sub Lemonldap::NG::Portal::Lib::DBI::hash_password_from_database { # Remark: database function must get hexadecimal input # and send back hexadecimal output my $self = shift; my $dbh = shift; my $dbmethod = shift; my $dbsalt = shift; my $password = shift; # Create functions use Digest::SHA; $dbh->sqlite_create_function( 'sha256', 1, sub { my $p = shift; return unpack( 'H*', Digest::SHA->new(256)->add( pack( 'H*', $p ) )->digest ); } ); $dbh->sqlite_create_function( 'sha512', 1, sub { my $p = shift; return unpack( 'H*', Digest::SHA->new(512)->add( pack( 'H*', $p ) )->digest ); } ); # convert password to hexa my $passwordh = unpack "H*", $password; my @rows = (); eval { my $sth = $dbh->prepare("SELECT $dbmethod('$passwordh$dbsalt')"); $sth->execute(); @rows = $sth->fetchrow_array(); }; if ($@) { $self->logger->error( "DBI error while hashing with '$dbmethod' hash function: $@"); $self->userLogger->warn("Unable to check password"); return ""; } if ( @rows == 1 ) { $self->logger->debug( "Successfully hashed password with $dbmethod hash function in database" ); # convert salt to binary my $dbsaltb = pack 'H*', $dbsalt; # convert result to binary my $res = pack 'H*', $rows[0]; return encode_base64( $res . $dbsaltb, '' ); } else { $self->userLogger->warn( "Unable to check password with '$dbmethod'"); return ""; } # Return encode_base64(SQL_METHOD(password + salt) + salt) } `; my $dbh = DBI->connect("dbi:SQLite:dbname=$userdb"); $dbh->do('CREATE TABLE users (user text,password text,name text)'); # password secret1 $dbh->do("INSERT INTO users VALUES ('dwho','secret1','Doctor who')"); # password secret2 $dbh->do( "INSERT INTO users VALUES ('rtyler','{sha256}NSJNDTRl106FX41poTbnnHROo1pnXTOTNgoyfL9jWaI=','Rose Tyler')" ); # password secret3 $dbh->do( "INSERT INTO users VALUES ('jsmith','{ssha512}wr0zU/I6f7U4bVoeOlJnNFbhF0a9np59LUeNnhokohVI/wiNzt8Y4JujfOfNQiGuiVgY+xrYggfmgpke6KdjxKS7W0GR1ZCe','John Smith')" ); my $client = LLNG::Manager::Test->new( { ini => { logLevel => 'error', useSafeJail => 1, authentication => 'DBI', userDB => 'Same', dbiAuthChain => "dbi:SQLite:dbname=$userdb", dbiAuthUser => '', dbiAuthPassword => '', dbiAuthTable => 'users', dbiAuthLoginCol => 'user', dbiAuthPasswordCol => 'password', dbiAuthPasswordHash => '', dbiDynamicHashEnabled => 1, dbiDynamicHashValidSchemes => 'sha sha256 sha512', dbiDynamicHashValidSaltedSchemes => 'ssha ssha256 ssha512', dbiDynamicHashNewPasswordScheme => 'ssha256', passwordDB => 'DBI', portalRequireOldPassword => 1, } } ); # Try to authenticate against plaintext password ok( $res = $client->_post( '/', IO::String->new('user=dwho&password=secret1'), length => 26 ), 'Authentication against plaintext password' ); expectOK($res); my $id = expectCookie($res); $client->logout($id); # Try to authenticate against static hashed password ok( $res = $client->_post( '/', IO::String->new('user=rtyler&password=secret2'), length => 28 ), 'Authentication against static SHA-256 hashed password' ); expectOK($res); $id = expectCookie($res); $client->logout($id); # Try to authenticate against salted password ok( $res = $client->_post( '/', IO::String->new('user=jsmith&password=secret3'), length => 28 ), 'Authentication against salted SHA-512 password' ); expectOK($res); $id = expectCookie($res); # Try to modify password ok( $res = $client->_post( '/', IO::String->new( 'oldpassword=secret3&newpassword=secret4&confirmpassword=secret4' ), cookie => "lemonldap=$id", accept => 'application/json', length => 63 ), 'Change password' ); expectOK($res); $client->logout($id); # Try to authenticate against new salted password ok( $res = $client->_post( '/', IO::String->new('user=jsmith&password=secret4'), length => 28 ), 'Authentication against newly-modified password' ); expectOK($res); $id = expectCookie($res); # Verify that password is hashed with correct scheme (dbiDynamicHashNewPasswordScheme) my $sth = $dbh->prepare("SELECT password FROM users WHERE user='jsmith';"); $sth->execute(); my $row = $sth->fetchrow_array; ok( $row =~ /^{ssha256}/, 'Verify that password is hashed with correct scheme' ); clean_sessions(); } count($maintests); done_testing( count() );