Index: lib/WebGUI/Auth/WebGUI.pm =================================================================== --- lib/WebGUI/Auth/WebGUI.pm (revision 11396) +++ lib/WebGUI/Auth/WebGUI.pm (working copy) @@ -24,6 +24,9 @@ use WebGUI::Form::Captcha; use Encode (); +use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash); +use MIME::Base64; + our @ISA = qw(WebGUI::Auth); #------------------------------------------------------------------- @@ -120,16 +123,27 @@ return 0 if !$auth; $identifier = $_[1]; - $userData = $self->getParams; - if (($self->hashPassword($identifier) eq $$userData{identifier}) && ($identifier ne "")) { - return 1; - } + + if ($identifier ne '') { + $userData = $self->getParams; + my $hashed = $self->hashPassword($identifier, $userData->{salt}); + return 1 if ($hashed eq $userData->{identifier}); + } + $self->user(WebGUI::User->new($self->session,1)); $self->SUPER::authenticationError; return 0; } #------------------------------------------------------------------- +sub bcryptSalt { + my $length = 16; + my @octets = map { int( rand(256) ) } (1..$length); + my $binary = pack("C[$length]", @octets); + return encode_base64($binary, ''); +} + +#------------------------------------------------------------------- sub createAccount { my $self = shift; my $session = $self->session; @@ -265,7 +279,8 @@ my $properties; $properties->{ changeUsername } = $setting->get("webguiChangeUsername"); $properties->{ changePassword } = $setting->get("webguiChangePassword"); - $properties->{ identifier } = $self->hashPassword($password); + my $salt = $properties->{ salt } = bcryptSalt(); + $properties->{ identifier } = $self->hashPassword($password, $salt); $properties->{ passwordLastUpdated } = $session->datetime->time(); $properties->{ passwordTimeout } = $setting->get("webguiPasswordTimeout"); $properties->{ status } = 'Deactivated' if ($setting->get("webguiValidateEmail")); @@ -431,10 +446,10 @@ my $userData = $self->getParams($userId); my $identifier = $self->session->form->process('authWebGUI.identifier'); unless (!$identifier || $identifier eq "password") { - $properties->{identifier} = $self->hashPassword($self->session->form->process('authWebGUI.identifier')); - if($userData->{identifier} ne $properties->{identifier}){ - $properties->{passwordLastUpdated} =$self->session->datetime->time(); - } + my $newPass = $self->session->form->process('authWebGUI.identifier'); + my $salt = $properties->{salt} = bcryptSalt(); + $properties->{identifier} = $self->hashPassword($newPass, $salt); + $properties->{passwordLastUpdated} = $self->session->datetime->time(); } $properties->{passwordTimeout} = $self->session->form->interval('authWebGUI.passwordTimeout'); $properties->{changeUsername} = $self->session->form->process('authWebGUI.changeUsername'); @@ -735,8 +750,20 @@ #------------------------------------------------------------------- sub hashPassword { - my ($self, $password) = @_; - return Digest::MD5::md5_base64(Encode::encode_utf8($password)); + my ($self, $password, $salt) = @_; + + # If we weren't given salt, we'll use a backwards compatible hash. + unless ($salt) { + return Digest::MD5::md5_base64(Encode::encode_utf8($password)); + } + + # If we were though, let's use bcrypt. + my %settings = ( + key_nul => 1, + cost => 8, + salt => decode_base64($salt), + ); + return encode_base64(bcrypt_hash(\%settings, $password), ''); } @@ -1029,9 +1056,11 @@ if ($self->_isValidPassword($password, $passwordConfirm)) { $self->user( $user ); - $self->saveParams($userId, $self->authMethod, - { identifier => $self->hashPassword($password), - passwordLastUpdated => $self->session->datetime->time }); + my %params; + my $salt = $params{salt } = bcryptSalt(); + $params{identifier } = $self->hashPassword($password, $salt); + $params{passwordLastUpdated} = $self->session->datetime->time; + $self->saveParams($userId, $self->authMethod, \%params); $self->_logSecurityMessage; return $self->SUPER::login; } else { @@ -1180,9 +1209,11 @@ if ($self->_isValidPassword($password, $passwordConfirm)) { $self->user(WebGUI::User->new($self->session, $userId)); - $self->saveParams($userId, $self->authMethod, - { identifier => $self->hashPassword($password), - passwordLastUpdated => $self->session->datetime->time }); + my %params; + my $salt = $params{salt} = bcryptSalt(); + $params{identifier } = $self->hashPassword($password, $salt); + $params{passwordLastUpdated} = $self->session->datetime->time; + $self->saveParams($userId, $self->authMethod, \%params); $self->_logSecurityMessage; # delete the emailRecoverPasswordVerificationNumber @@ -1235,8 +1266,10 @@ return $self->resetExpiredPassword($u->userId, "