package WebGUI::Auth::WebGUI; #------------------------------------------------------------------- # WebGUI is Copyright 2001-2007 Plain Black Corporation. #------------------------------------------------------------------- # Please read the legal notices (docs/legal.txt) and the license # (docs/license.txt) that came with this distribution before using # this software. #------------------------------------------------------------------- # http://www.plainblack.com info@plainblack.com #------------------------------------------------------------------- use Digest::MD5; use strict; use URI; use WebGUI::Asset::Template; use WebGUI::Auth; use WebGUI::HTMLForm; use WebGUI::Macro; use WebGUI::Mail::Send; use WebGUI::Storage::Image; use WebGUI::User; use WebGUI::Utility; our @ISA = qw(WebGUI::Auth); #------------------------------------------------------------------- sub _hasNonWordCharacters { my $self = shift; my $password = shift; my $numberRequired = shift; return ($password =~ tr/A-Za-z0-9_//c) >= $numberRequired; } #------------------------------------------------------------------- sub _hasNumberCharacters { my $self = shift; my $password = shift; my $numberRequired = shift; return ($password =~ tr/0-9//) >= $numberRequired; } #------------------------------------------------------------------- sub _hasMixedCaseCharacters { my $self = shift; my $password = shift; my $numberRequired = shift; return $password =~ tr/a-z// && ($password =~ tr/A-Z//) >= $numberRequired; } #------------------------------------------------------------------- =head2 _isValidPassword ( ) Validates the password. =cut sub _isValidPassword { my $self = shift; my $password = shift; WebGUI::Macro::negate(\$password); my $confirm = shift; WebGUI::Macro::negate(\$confirm); my $error = ""; my $i18n = WebGUI::International->new($self->session,'AuthWebGUI'); if ($password ne $confirm) { $error .= '
  • '.$i18n->get(3).'
  • '; } if ($password eq "") { $error .= '
  • '.$i18n->get(4).'
  • '; } if ($self->getSetting("passwordLength") && length($password) < $self->getSetting("passwordLength")){ $error .= '
  • '.$i18n->get(7)." ".$self->getSetting("passwordLength").'
  • '; } if ($self->getSetting("requiredDigits") && !$self->_hasNumberCharacters($password, $self->getSetting("requiredDigits"))) { $error .= '
  • '.sprintf($i18n->get('error password requiredDigits'), $self->getSetting("requiredDigits")).'
  • '; } if ($self->getSetting("nonWordCharacters") && !$self->_hasNonWordCharacters($password, $self->getSetting("nonWordCharacters"))) { $error .= '
  • '.sprintf($i18n->get('error password nonWordCharacters'), $self->getSetting("nonWordCharacters")).'
  • '; } if ($self->getSetting("requiredMixedCase") && !$self->_hasMixedCaseCharacters($password, $self->getSetting("requiredMixedCase"))) { $error .= '
  • '. sprintf($i18n->get('error password requiredMixedCase'), $self->getSetting("requiredMixedCase")).'
  • '; } $self->error($error); return $error eq ""; } #------------------------------------------------------------------- =head2 _logSecurityMessage ( ) Logs the successful password change message. =cut sub _logSecurityMessage { my $self = shift; $self->session->errorHandler->security("change password. Password changed successfully"); } #------------------------------------------------------------------- sub authenticate { my $self = shift; my ($identifier, $userData, $auth); $auth = $self->SUPER::authenticate($_[0]); return 0 if !$auth; $identifier = $_[1]; $userData = $self->getParams; if ((Digest::MD5::md5_base64($identifier) eq $$userData{identifier}) && ($identifier ne "")) { return 1; } $self->user(WebGUI::User->new($self->session,1)); my $i18n = WebGUI::International->new($self->session); $self->error($i18n->get(68)); return 0; } #------------------------------------------------------------------- sub createAccount { my $self = shift; my $message = shift; my $confirm = shift || $self->session->form->process("confirm"); my $vars = shift || {}; #$self->session->errorHandler->warn('WebGUI::Auth::createAccount called'); if ($self->session->user->userId ne "1") { return $self->displayAccount; } elsif (!$self->session->setting->get("anonymousRegistration") && !$self->session->setting->get('userInvitationsEnabled')) { return $self->displayLogin; } my $i18n = WebGUI::International->new($self->session); $vars->{'create.message'} = $message if ($message); $vars->{useCaptcha} = $self->session->setting->get("webguiUseCaptcha"); if ($vars->{useCaptcha}) { use WebGUI::Form::Captcha; my $captcha = WebGUI::Form::Captcha->new($self->session,{"name"=>"authWebGUI.captcha"}); $vars->{'create.form.captcha'} = $captcha->toHtml . '' . $captcha->get('subtext').''; $vars->{'create.form.captcha.label'} = $i18n->get("captcha label","AuthWebGUI"); } $vars->{'create.form.username'} = WebGUI::Form::text($self->session, { "name" => "authWebGUI.username", "value" => $self->session->form->process("authWebGUI.username"), }); $vars->{'create.form.username.label'} = $i18n->get(50); $vars->{'create.form.password'} = WebGUI::Form::password($self->session, { "name" => "authWebGUI.identifier" }); $vars->{'create.form.password.label'} = $i18n->get(51); $vars->{'create.form.passwordConfirm'} = WebGUI::Form::password($self->session, { "name" => "authWebGUI.identifierConfirm" }); $vars->{'create.form.passwordConfirm.label'} = $i18n->get(2,'AuthWebGUI'); $vars->{'create.form.hidden'} = WebGUI::Form::hidden($self->session, { "name" => "confirm", "value" => $confirm }); $vars->{'recoverPassword.isAllowed' } = $self->getSetting("passwordRecovery"); $vars->{'recoverPassword.url' } = $self->session->url->page('op=auth;method=recoverPassword'); $vars->{'recoverPassword.label' } = $i18n->get(59); return $self->SUPER::createAccount("createAccountSave",$vars); } #------------------------------------------------------------------- sub createAccountSave { my $self = shift; my $session = $self->session; my $form = $self->session->form; my $setting = $self->session->setting; my $i18n = WebGUI::International->new($session); # Logged in users cannot see this page return $self->displayAccount if ($session->user->userId ne "1"); # Make sure anonymous registration is enabled if (!$setting->get("anonymousRegistration") && !$setting->get("userInvitationsEnabled")) { $session->errorHandler->security($i18n->get("no registration hack", "AuthWebGUI")); return $self->displayLogin; } my $username = $form->process('authWebGUI.username'); my $password = $form->process('authWebGUI.identifier'); my $passConfirm = $form->process('authWebGUI.identifierConfirm'); # Validate input my $error; $error = $self->error unless($self->validUsername($username)); if ($setting->get("webguiUseCaptcha")) { unless ($form->process('authWebGUI.captcha', "Captcha")) { $error .= $i18n->get("captcha failure","AuthWebGUI"); } } $error .= $self->error unless($self->_isValidPassword($password,$passConfirm)); my ($profile, $temp, $warning) = WebGUI::Operation::Profile::validateProfileData($self->session); $error .= $temp; return $self->createAccount($error) unless ($error eq ""); # If Email address is not unique, a warning is displayed if ($warning ne "" && !$self->session->form->process("confirm")) { return $self->createAccount('
  • '.$i18n->get(1078).'
  • ', 1); } # Create the new account my $properties; $properties->{ changeUsername } = $setting->get("webguiChangeUsername"); $properties->{ changePassword } = $setting->get("webguiChangePassword"); $properties->{ identifier } = Digest::MD5::md5_base64($password); $properties->{ passwordLastUpdated } = $session->datetime->time(); $properties->{ passwordTimeout } = $setting->get("webguiPasswordTimeout"); $properties->{ status } = 'Deactivated' if ($setting->get("webguiValidateEmail")); $self->SUPER::createAccountSave($username,$properties,$password,$profile); # Send validation e-mail if required if ($setting->get("webguiValidateEmail")) { my $key = $session->id->generate(); $self->saveParams($self->userId,"WebGUI",{emailValidationKey=>$key}); my $mail = WebGUI::Mail::Send->create($self->session,{ to => $profile->{email}, subject => $i18n->get('email address validation email subject','AuthWebGUI') }); $mail->addText( $i18n->get('email address validation email body','AuthWebGUI') . "\n\n" . $session->url->getSiteURL() . $session->url->page("op=auth;method=validateEmail;key=".$key) ); $mail->addFooter; $mail->send; $self->user->status("Deactivated"); $session->var->end($session->var->get("sessionId")); $session->var->start(1,$session->getId); my $u = WebGUI::User->new($session,1); $self->{user} = $u; $self->logout; return $self->displayLogin($i18n->get('check email for validation','AuthWebGUI')); } return undef; } #------------------------------------------------------------------- sub deactivateAccount { my $self = shift; return $self->displayLogin if($self->userId eq '1'); return $self->SUPER::deactivateAccount("deactivateAccountConfirm"); } #------------------------------------------------------------------- sub deactivateAccountConfirm { my $self = shift; return $self->displayLogin unless ($self->session->setting->get("selfDeactivation")); # Keep the username for a nice message my $username = $self->user->username; # Deactivate the account my $response = $self->SUPER::deactivateAccountConfirm; # If there was a response, it's probably an error return $response if $response; # Otherwise show the login form with a friendly message my $i18n = WebGUI::International->new($self->session); return $self->displayLogin(sprintf( $i18n->get("deactivateAccount success"), $username )); } #------------------------------------------------------------------- sub displayAccount { my $self = shift; my $vars; return $self->displayLogin($_[0]) if ($self->userId eq '1'); my $i18n = WebGUI::International->new($self->session); my $userData = $self->getParams; $vars->{'account.message'} = $_[0] if ($_[0]); $vars->{'account.noform'} = 1; if($userData->{changeUsername} || (!defined $userData->{changeUsername} && $self->session->setting->get("webguiChangeUsername"))){ $vars->{'account.form.username'} = WebGUI::Form::text($self->session,{"name"=>"authWebGUI.username","value"=>$self->username}); $vars->{'account.form.username.label'} = $i18n->get(50); $vars->{'account.noform'} = 0; } if($userData->{changePassword} || (!defined $userData->{changePassword} && $self->session->setting->get("webguiChangePassword"))){ $vars->{'account.form.password'} = WebGUI::Form::password($self->session,{"name"=>"authWebGUI.identifier","value"=>"password"}); $vars->{'account.form.password.label'} = $i18n->get(51); $vars->{'account.form.passwordConfirm'} = WebGUI::Form::password($self->session,{"name"=>"authWebGUI.identifierConfirm","value"=>"password"}); $vars->{'account.form.passwordConfirm.label'} = $i18n->get(2,'AuthWebGUI'); $vars->{'account.noform'} = 0; } $vars->{'account.nofields'} = $i18n->get(22,'AuthWebGUI'); return $self->SUPER::displayAccount("updateAccount",$vars); } #------------------------------------------------------------------- =head2 displayLogin ( ) The initial login screen an unauthenticated user sees =cut sub displayLogin { my $self = shift; my $vars; return $self->displayAccount($_[0]) if ($self->userId ne "1"); my $i18n = WebGUI::International->new($self->session); $vars->{'login.message'} = $_[0] if ($_[0]); $vars->{'recoverPassword.isAllowed'} = $self->getSetting("passwordRecovery"); $vars->{'recoverPassword.url'} = $self->session->url->page('op=auth;method=recoverPassword'); $vars->{'recoverPassword.label'} = $i18n->get(59); return $self->SUPER::displayLogin("login",$vars); } #------------------------------------------------------------------- =head2 editUserForm ( ) Creates user form elements specific to this Auth Method. =cut sub editUserForm { my $self = shift; my $userData = $self->getParams; my $f = WebGUI::HTMLForm->new($self->session); my $i18n = WebGUI::International->new($self->session); $f->password( name=>"authWebGUI.identifier", label=>$i18n->get(51), value=>"password" ); $f->interval( -name=>"authWebGUI.passwordTimeout", -label=>$i18n->get(16,'AuthWebGUI'), -value=>$userData->{passwordTimeout}, -defaultValue=>$self->session->setting->get("webguiPasswordTimeout") ); my $userChange = $self->session->setting->get("webguiChangeUsername"); if($userChange || $userChange eq "0"){ $userChange = $userData->{changeUsername}; } $f->yesNo( -name=>"authWebGUI.changeUsername", -value=>$userChange, -label=>$i18n->get(21,'AuthWebGUI') ); my $passwordChange = $self->session->setting->get("webguiChangePassword"); if($passwordChange || $passwordChange eq "0"){ $passwordChange = $userData->{changePassword}; } $f->yesNo( -name=>"authWebGUI.changePassword", -value=>$passwordChange, -label=>$i18n->get(20,'AuthWebGUI') ); return $f->printRowsOnly; } #------------------------------------------------------------------- =head2 editUserFormSave ( ) Saves user elements unique to this authentication method =cut sub editUserFormSave { my $self = shift; my $userId = $self->session->form->get("uid"); my $properties; my $userData = $self->getParams($userId); my $identifier = $self->session->form->process('authWebGUI.identifier'); unless (!$identifier || $identifier eq "password") { $properties->{identifier} = Digest::MD5::md5_base64($self->session->form->process('authWebGUI.identifier')); if($userData->{identifier} ne $properties->{identifier}){ $properties->{passwordLastUpdated} =$self->session->datetime->time(); } } $properties->{passwordTimeout} = $self->session->form->interval('authWebGUI.passwordTimeout'); $properties->{changeUsername} = $self->session->form->process('authWebGUI.changeUsername'); $properties->{changePassword} = $self->session->form->process('authWebGUI.changePassword'); if($userId eq "new") { $properties->{passwordLastUpdated} =$self->session->datetime->time(); if ($self->session->setting->get("webguiExpirePasswordOnCreation")){ $properties->{passwordLastUpdated} =$self->session->datetime->time() - $properties->{passwordTimeout}; } } $self->SUPER::editUserFormSave($properties); } #------------------------------------------------------------------- =head2 editUserSettingsForm ( ) Creates form elements for user settings page custom to this auth module =cut sub editUserSettingsForm { my $self = shift; my $i18n = WebGUI::International->new($self->session,'AuthWebGUI'); my $f = WebGUI::HTMLForm->new($self->session); $f->integer( -name=>"webguiPasswordLength", -value=>$self->session->setting->get("webguiPasswordLength"), -label=>$i18n->get(15), ); $f->integer( -name => "webguiRequiredDigits", -label => $i18n->get('setting webguiRequiredDigits'), -value => $self->session->setting->get("webguiRequiredDigits") ); $f->integer( -name => "webguiNonWordCharacters", -label => $i18n->get('setting webguiNonWordCharacters'), -value => $self->session->setting->get("webguiNonWordCharacters") ); $f->integer( -name => "webguiRequiredMixedCase", -label => $i18n->get('setting webguiRequiredMixedCase'), -value => $self->session->setting->get("webguiRequiredMixedCase") ); $f->interval( -name=>"webguiPasswordTimeout", -label=>$i18n->get(16), -value=>$self->session->setting->get("webguiPasswordTimeout") ); $f->yesNo( -name=>"webguiExpirePasswordOnCreation", -value=>$self->session->setting->get("webguiExpirePasswordOnCreation"), -label=>$i18n->get(9) ); $f->yesNo( -name=>"webguiSendWelcomeMessage", -value=>$self->session->setting->get("webguiSendWelcomeMessage"), -label=>$i18n->get(868,'WebGUI') ); $f->textarea( -name=>"webguiWelcomeMessage", -value=>$self->session->setting->get("webguiWelcomeMessage"), -label=>$i18n->get(869,'WebGUI') ); $f->yesNo( -name=>"webguiChangeUsername", -value=>$self->session->setting->get("webguiChangeUsername"), -label=>$i18n->get(19) ); $f->yesNo( -name=>"webguiChangePassword", -value=>$self->session->setting->get("webguiChangePassword"), -label=>$i18n->get(18) ); $f->selectList( -name => "webguiPasswordRecovery", -value => $self->session->setting->get("webguiPasswordRecovery"), -label => $i18n->get(6), -hoverHelp => $i18n->get('webguiPasswordRecovery hoverHelp'), -options => $self->getPasswordRecoveryTypesAvailable, -size => 1, -multiple => 0, ); $f->yesNo( -name => "webguiPasswordRecoveryRequireUsername", -value => $self->session->setting->get("webguiPasswordRecoveryRequireUsername"), -label => $i18n->get('require username for password recovery'), -hoverHelp => $i18n->get('webguiPasswordRecoveryRequireUsername hoverHelp') ); $f->yesNo( -name=>"webguiValidateEmail", -value=>$self->session->setting->get("webguiValidateEmail"), -label=>$i18n->get('validate email') ); $f->yesNo( -name=>"webguiUseCaptcha", -value=>$self->session->setting->get("webguiUseCaptcha"), -label=>$i18n->get('use captcha') ); $f->template( -name=>"webguiAccountTemplate", -value=>$self->session->setting->get("webguiAccountTemplate"), -namespace=>"Auth/WebGUI/Account", -label=>$i18n->get("account template") ); $f->template( -name=>"webguiCreateAccountTemplate", -value=>$self->session->setting->get("webguiCreateAccountTemplate"), -namespace=>"Auth/WebGUI/Create", -label=>$i18n->get("create account template") ); $f->template( -name=>"webguiExpiredPasswordTemplate", -value=>$self->session->setting->get("webguiExpiredPasswordTemplate"), -namespace=>"Auth/WebGUI/Expired", -label=>$i18n->get("expired password template") ); $f->template( -name=>"webguiLoginTemplate", -value=>$self->session->setting->get("webguiLoginTemplate"), -namespace=>"Auth/WebGUI/Login", -label=>$i18n->get("login template") ); $f->template( -name=>"webguiPasswordRecoveryTemplate", -value=>$self->session->setting->get("webguiPasswordRecoveryTemplate"), -namespace=>"Auth/WebGUI/Recovery2", -label=>$i18n->get("password recovery template") ); return $f->printRowsOnly; } #------------------------------------------------------------------- sub editUserSettingsFormSave { my $self = shift; my $f = $self->session->form; my $s = $self->session->setting; my $i18n = WebGUI::International->new($self->session, 'AuthWebGUI'); my @errors; # Array of errors to return, if any. See WebGUI::Operation::Settings->www_saveSettings $s->set("webguiPasswordLength", $f->process("webguiPasswordLength","integer")); $s->set("webguiRequiredDigits", $f->process("webguiRequiredDigits","integer")); $s->set("webguiNonWordCharacters", $f->process("webguiNonWordCharacters","integer")); $s->set("webguiRequiredMixedCase", $f->process("webguiRequiredMixedCase","integer")); $s->set("webguiPasswordTimeout", $f->process("webguiPasswordTimeout","interval")); $s->set("webguiExpirePasswordOnCreation", $f->process("webguiExpirePasswordOnCreation","yesNo")); $s->set("webguiSendWelcomeMessage", $f->process("webguiSendWelcomeMessage","yesNo")); $s->set("webguiWelcomeMessage", $f->process("webguiWelcomeMessage","textarea")); $s->set("webguiChangeUsername", $f->process("webguiChangeUsername","yesNo")); $s->set("webguiChangePassword", $f->process("webguiChangePassword","yesNo")); # Make sure we have the ability to recover a password if we're trying to # enable password recovery my $passwordRecoveryType = $f->process("webguiPasswordRecovery", "selectList"); if ($passwordRecoveryType eq "profile") { # Profile recovery requires at least one field set to required my ($passwordRecoveryFields) = $self->session->db->quickArray( "SELECT COUNT(*) FROM userProfileField WHERE requiredForPasswordRecovery = 1" ); if ($passwordRecoveryFields <= 0) { push @errors, $i18n->get("error passwordRecoveryType no profile fields required"); } else { $s->set("webguiPasswordRecovery", $passwordRecoveryType); } } # Recovery types that need no error checking else { $s->set("webguiPasswordRecovery", $passwordRecoveryType); } $s->set("webguiPasswordRecoveryRequireUsername", $f->process("webguiPasswordRecoveryRequireUsername","yesNo")); $s->set("webguiValidateEmail", $f->process("webguiValidateEmail","yesNo")); $s->set("webguiUseCaptcha", $f->process("webguiUseCaptcha","yesNo")); $s->set("webguiAccountTemplate", $f->process("webguiAccountTemplate","template")); $s->set("webguiCreateAccountTemplate", $f->process("webguiCreateAccountTemplate","template")); $s->set("webguiExpiredPasswordTemplate", $f->process("webguiExpiredPasswordTemplate","template")); $s->set("webguiLoginTemplate", $f->process("webguiLoginTemplate","template")); $s->set("webguiPasswordRecoveryTemplate", $f->process("webguiPasswordRecoveryTemplate","template")); if (@errors) { return \@errors; } else { return; } } #------------------------------------------------------------------- sub getAccountTemplateId { my $self = shift; return $self->session->setting->get("webguiAccountTemplate") || "PBtmpl0000000000000010"; } #------------------------------------------------------------------- sub getCreateAccountTemplateId { my $self = shift; return $self->session->setting->get("webguiCreateAccountTemplate") || "PBtmpl0000000000000011"; } #------------------------------------------------------------------- sub getExpiredPasswordTemplateId { my $self = shift; return $self->session->setting->get("webguiExpiredPasswordTemplate") || "PBtmpl0000000000000012"; } #------------------------------------------------------------------- sub getLoginTemplateId { my $self = shift; return $self->session->setting->get("webguiLoginTemplate") || "PBtmpl0000000000000013"; } #------------------------------------------------------------------- sub getPasswordRecoveryTemplateId { my $self = shift; return $self->session->setting->get("webguiPasswordRecoveryTemplate") || "PBtmpl0000000000000014"; } #------------------------------------------------------------------- sub getPasswordRecoveryType { my $self = shift; return $self->session->setting->get("webguiPasswordRecovery"); } #---------------------------------------------------------------------------- =head2 getPasswordRecoveryTypesAvailable Returns a hash reference of password recovery types. Keys are the type, values are an i18n label for the user. =cut sub getPasswordRecoveryTypesAvailable { my $self = shift; my $i18n = WebGUI::International->new($self->session, 'AuthWebGUI'); tie my %types, 'Tie::IxHash', ( "" => $i18n->get("setting passwordRecoveryType none"), profile => $i18n->get("setting passwordRecoveryType profile"), email => $i18n->get("setting passwordRecoveryType email"), ); return \%types; } #------------------------------------------------------------------- sub getUserIdByPasswordRecoveryToken { my $self = shift; my $session = shift; my $token = shift; return $session->db->quickScalar("select userId from authentication where fieldName = 'emailRecoverPasswordVerificationNumber' and fieldData = ?", [$token]); } #------------------------------------------------------------------- sub login { my $self = shift; if(!$self->authenticate($self->session->form->process("username"),$self->session->form->process("identifier"))){ $self->session->http->setStatus("401","Incorrect Credentials"); $self->session->errorHandler->security("login to account ".$self->session->form->process("username")." with invalid information."); my $i18n = WebGUI::International->new($self->session); return $self->displayLogin("

    ".$i18n->get(70)."

    ".$self->error); } my $userData = $self->getParams; if($self->getSetting("passwordTimeout") && $userData->{passwordTimeout}){ my $expireTime = $userData->{passwordLastUpdated} + $userData->{passwordTimeout}; if ($self->session->datetime->time() >= $expireTime){ my $userId = $self->userId; $self->logout; return $self->resetExpiredPassword($userId); } } return $self->SUPER::login(); } #------------------------------------------------------------------- sub new { my $class = shift; my $session = shift; my $authMethod = $_[0]; my $userId = $_[1]; my @callable = ('validateEmail','createAccount','deactivateAccount','displayAccount','displayLogin','login','logout','recoverPassword','resetExpiredPassword','recoverPasswordFinish','createAccountSave','deactivateAccountConfirm','resetExpiredPasswordSave','updateAccount', 'emailResetPassword', 'emailResetPasswordFinish'); my $self = WebGUI::Auth->new($session,$authMethod,$userId,\@callable); bless $self, $class; } #------------------------------------------------------------------- =head2 recoverPassword ( ) Initiates the password recovery process. Checks for recovery type, and then runs the appropriate method. =cut sub recoverPassword { my $self = shift; return $self->displayLogin unless ($self->session->setting->get('webguiPasswordRecovery') ne '') and $self->userId eq '1'; my $type = $self->getPasswordRecoveryType; #$self->session->errorHandler->warn("recovery type: $type"); if ($type eq 'profile') { $self->profileRecoverPassword; } elsif ($type eq 'email') { $self->emailRecoverPassword; } } #------------------------------------------------------------------- sub emailRecoverPassword { my $self = shift; my $i18n = WebGUI::International->new($self->session); my $output = "

    " . $i18n->get('recover password banner', 'AuthWebGUI') . "



    " . "

    " . $i18n->get('email recover password start message', 'AuthWebGUI') ."

    " ; my $f = WebGUI::HTMLForm->new($self->session); $f->hidden( name => 'op', value => 'auth', ); $f->hidden( name => "method", value => "recoverPasswordFinish", ); $f->text( name => "username", label => $i18n->get('password recovery login label', 'AuthWebGUI'), hoverHelp => $i18n->get('password recovery login help', 'AuthWebGUI'), ); $f->email( name =>"email", label => $i18n->get('password recovery email label', 'AuthWebGUI'), hoverHelp => $i18n->get('password recovery email help', 'AuthWebGUI'), ); $f->submit(); $output .= $f->print; return $output; } #------------------------------------------------------------------- sub profileRecoverPassword { my $self = shift; my @fields = @{WebGUI::ProfileField->getPasswordRecoveryFields($self->session)}; return $self->displayLogin unless @fields; my $vars = {}; my $i18n = WebGUI::International->new($self->session); $vars->{title} = $i18n->get(71); $vars->{'recoverFormHeader'} = "\n\n".WebGUI::Form::formHeader($self->session,{}); $vars->{'recoverFormHidden'} = WebGUI::Form::hidden($self->session,{"name"=>"op","value"=>"auth"}); $vars->{'recoverFormHidden'} .= WebGUI::Form::hidden($self->session,{"name"=>"method","value"=>"recoverPasswordFinish"}); $vars->{'recoverFormSubmit'} = WebGUI::Form::submit($self->session,{}); $vars->{'recoverFormFooter'} = WebGUI::Form::formFooter($self->session,); $vars->{'loginUrl'} = $self->session->url->page('op=auth;method=init'); $vars->{'loginLabel'} = $i18n->get(58); $vars->{'anonymousRegistrationIsAllowed'} = ($self->session->setting->get("anonymousRegistration")); $vars->{'createAccountUrl'} = $self->session->url->page('op=auth;method=createAccount'); $vars->{'createAccountLabel'} = $i18n->get(67); $vars->{'recoverMessage'} = $_[0] if ($_[0]); # Semi-duplication with WebGUI::Auth::createAccount. -.- $vars->{'recoverFormProfile'} = []; foreach my $field (@fields) { my ($id, $formField, $label) = ($field->getId, $field->formField, $field->getLabel); push @{$vars->{'recoverFormProfile'}}, +{ 'id' => $id, 'formElement' => $formField, 'label' => $label }; my $prefix = 'recoverFormProfileField' . ucfirst($id); $vars->{$prefix.'FormElement'} = $formField; $vars->{$prefix.'Label'} = $label; } if ($self->getSetting('passwordRecoveryRequireUsername')) { $vars->{'recoverFormUsername'} = WebGUI::Form::text($self->session, {name => 'authWebGUI.username'}); $vars->{'recoverFormUsernameLabel'} = $i18n->get(50); } return WebGUI::Asset::Template->new($self->session,$self->getPasswordRecoveryTemplateId)->process($vars); } #------------------------------------------------------------------- =head2 recoverPasswordFinish ( ) Handles data for recovery of password. Gets password recovery type, and then runs the appropriate method. =cut sub recoverPasswordFinish { my $self = shift; my $type = $self->getPasswordRecoveryType; if ($type eq 'profile') { $self->profileRecoverPasswordFinish; } elsif ($type eq 'email') { $self->emailRecoverPasswordFinish; } } #------------------------------------------------------------------- sub profileRecoverPasswordFinish { my $self = shift; my $i18n = WebGUI::International->new($self->session); my $i18n2 = WebGUI::International->new($self->session, 'AuthWebGUI'); return $self->displayLogin unless ($self->session->setting->get('webguiPasswordRecovery') ne '') and $self->userId eq '1'; my $username; if ($self->getSetting('passwordRecoveryRequireUsername')) { $username = $self->session->form->process('authWebGUI.username'); return $self->recoverPassword($i18n2->get('password recovery no username')) unless defined $username; } my @fields = @{WebGUI::ProfileField->getPasswordRecoveryFields($self->session)}; return $self->displayLogin unless @fields; my %fieldValues; my @failedRequiredFields; foreach my $field (@fields) { my $value = $field->formProcess; $fieldValues{$field->getId} = $value; push @failedRequiredFields, $field unless defined $value; } if (@failedRequiredFields) { my $errorMessage = ''; return $self->recoverPassword($errorMessage); } my @fieldNames = keys %fieldValues; my @fieldValues = values %fieldValues; my $wheres = join(' ', map{"AND upd.$fieldNames[$_] = ?"} (0..$#fieldNames)); $wheres .= ' AND u.username = ?' if defined $username; my $sql = "SELECT u.userId FROM users AS u JOIN userProfileData AS upd ON u.userId=upd.userId WHERE u.authMethod = 'WebGUI' $wheres"; my @userIds = $self->session->db->buildArray($sql, [@fieldValues, (defined($username)? ($username) : ())]); if (@userIds == 0) { return $self->recoverPassword($i18n2->get('password recovery no results')); } elsif (@userIds > 1) { return $self->recoverPassword($i18n2->get('password recovery multiple results')); } # Exactly one result. my $userId = $userIds[0]; my ($password, $passwordConfirm) = ($self->session->form->process('authWebGUI.identifier'), $self->session->form->process('authWebGUI.identifierConfirm')); unless (defined $password and defined $passwordConfirm) { my $vars = {}; $vars->{title} = $i18n->get(71); $vars->{'recoverFormHeader'} = "\n\n" . WebGUI::Form::formHeader($self->session, {}); $vars->{'recoverFormHidden'} = (WebGUI::Form::hidden($self->session, {name => 'op', value => 'auth'}) . WebGUI::Form::hidden($self->session, {name => 'method', value => 'recoverPasswordFinish'}) . (defined($username)? WebGUI::Form::hidden($self->session, {name => 'authWebGUI.username', value => $username}) : '') . join('', map{WebGUI::Form::hidden($self->session, {name => $_, value => $fieldValues{$_}})} keys %fieldValues)); $vars->{'recoverFormSubmit'} = WebGUI::Form::submit($self->session, {}); $vars->{'recoverFormFooter'} = WebGUI::Form::formFooter($self->session); # Duplication with above in recoverPassword. $vars->{'loginUrl'} = $self->session->url->page('op=auth;method=init'); $vars->{'loginLabel'} = $i18n->get(58); $vars->{'anonymousRegistrationIsAllowed'} = ($self->session->setting->get("anonymousRegistration")); $vars->{'createAccountUrl'} = $self->session->url->page('op=auth;method=createAccount'); $vars->{'createAccountLabel'} = $i18n->get(67); # End duplication. $vars->{'recoverFormPassword'} = WebGUI::Form::password($self->session, {name => 'authWebGUI.identifier'}); $vars->{'recoverFormPasswordConfirm'} = WebGUI::Form::password($self->session, {name => 'authWebGUI.identifierConfirm'}); $vars->{'recoverFormPasswordLabel'} = $i18n->get(51); $vars->{'recoverFormPasswordConfirmLabel'} = $i18n2->get(2); # Mrgh. z.z $vars->{'doingRecovery'} = 1; return WebGUI::Asset::Template->new($self->session, $self->getPasswordRecoveryTemplateId)->process($vars); } if ($self->_isValidPassword($password, $passwordConfirm)) { $self->user(WebGUI::User->new($self->session, $userId)); $self->saveParams($userId, $self->authMethod, { identifier => Digest::MD5::md5_base64($password), passwordLastUpdated => $self->session->datetime->time }); $self->_logSecurityMessage; return $self->SUPER::login; } else { return $self->recoverPassword(''); } } #------------------------------------------------------------------- sub emailRecoverPasswordFinish { my $self = shift; return $self->displayLogin unless ($self->session->setting->get('webguiPasswordRecovery') ne '') and $self->userId eq '1'; my $i18n = WebGUI::International->new($self->session); my $session = $self->session; my ($form) = $session->quick(qw/form/); my $email = $form->param('email'); my $username = $form->param('username'); my $user; # get user from email $user = WebGUI::User->newByEmail($session, $email) if $email; # get user from username if ($username) { $user = WebGUI::User->newByUsername($session, $username) unless $user; } # return error unless we get a valid user. unless ($user) { return $i18n->get('recover password not found', 'AuthWebGUI'); } # generate information necessry to proceed my $recoveryGuid = $session->id->generate(); my $url = $session->url->getSiteURL; my $userId = $user->userId; #get the user guid $email = $user->profileField('email') unless $email; #get email address from the profile, unless we already have it my $authsettings = $self->getParams; $authsettings->{emailRecoverPasswordVerificationNumber} = $recoveryGuid; $self->saveParams($userId, 'WebGUI', $authsettings); my $mail = WebGUI::Mail::Send->create($session, { to=>$email, subject=>'WebGUI password recovery'}); $mail->addText($i18n->get('recover password email text1', 'AuthWebGUI') . $url. ". \n\n".$i18n->get('recover password email text2', 'AuthWebGUI')." \n\n ".$url."?op=auth;method=emailResetPassword;token=$recoveryGuid"."\n\n ". $i18n->get('recover password email text3', 'AuthWebGUI')); $mail->send; return "

    ". $i18n->get('recover password banner', 'AuthWebGUI')."



    ". $i18n->get('email recover password finish message1', 'AuthWebGUI'). $email . $i18n->get('email recover password finish message2', 'AuthWebGUI') . "

    "; } #------------------------------------------------------------------- # handler for the link generated and mailed by emailRecoverPasswordFinish sub emailResetPassword { my $self = shift; my $errormsg = shift; my $session = $self->session; my ($form) = $session->quick(qw/form/); my $passwordRecoveryToken = $form->param('token'); my $i18n = WebGUI::International->new($self->session); my $userId = $self->getUserIdByPasswordRecoveryToken($session, $passwordRecoveryToken); my $u = $self->user(WebGUI::User->new($self->session, $userId)); $self->session->user({user=>$u}); # do not proceed unless we have an incoming guid from the email, and that guid corresponds to a valid user. unless ($passwordRecoveryToken && $userId) { return $session->privilege->insufficient; } # login the user and take them to a page where they can change their password. my $output = "

    ".$i18n->get('recover password banner', 'AuthWebGUI') ."



    ". $i18n->get('email password recovery end message', 'AuthWebGUI')."

    "; $output .= $errormsg if $errormsg; my $f = WebGUI::HTMLForm->new($self->session); $f->hidden( name => 'op', value => 'auth', ); $f->hidden( name => "method", value => "emailResetPasswordFinish", ); $f->hidden( name => "token", value => "$passwordRecoveryToken", ); $f->password( name=>"newpassword", label=> $i18n->get('new password label', 'AuthWebGUI'), hoverHelp=> $i18n->get('new password help', 'AuthWebGUI'), ); $f->password( name=>"newpwdverify", label => $i18n->get('new password verify', 'AuthWebGUI'), hoverHelp=> $i18n->get('new password verify help', 'AuthWebGUI'), ); $f->submit( value => 'submit' ); $output .= $f->print; return $output; } #------------------------------------------------------------------- sub emailResetPasswordFinish { my $self = shift; my $session = $self->session; my ($form) = $session->quick(qw/form/); my $password = $form->param('newpassword'); my $passwordConfirm = $form->param('newpwdverify'); my $passwordRecoveryToken = $form->param('token'); my $userId = $self->getUserIdByPasswordRecoveryToken($session, $passwordRecoveryToken); return $session->privilege->insufficient unless $userId; if ($self->_isValidPassword($password, $passwordConfirm)) { $self->user(WebGUI::User->new($self->session, $userId)); $self->saveParams($userId, $self->authMethod, { identifier => Digest::MD5::md5_base64($password), passwordLastUpdated => $self->session->datetime->time }); $self->_logSecurityMessage; # delete the emailRecoverPasswordVerificationNumber $self->deleteSingleParam($userId, $self->authMethod, 'emailRecoverPasswordVerificationNumber'); return $self->SUPER::login; } else { return $self->emailResetPassword($self->error); } } #------------------------------------------------------------------- sub resetExpiredPassword { my $self = shift; my $uid = shift || $self->session->form->process("uid"); my $vars; my $i18n = WebGUI::International->new($self->session); $vars->{displayTitle} = '

    '.$i18n->get(8,'AuthWebGUI').'

    '; $vars->{'expired.message'} = $_[0] if($_[0]); $vars->{'expired.form.header'} = "\n\n".WebGUI::Form::formHeader($self->session,{}); $vars->{'expired.form.hidden'} = WebGUI::Form::hidden($self->session,{"name"=>"op","value"=>"auth"}); $vars->{'expired.form.hidden'} .= WebGUI::Form::hidden($self->session,{"name"=>"method","value"=>"resetExpiredPasswordSave"}); $vars->{'expired.form.hidden'} .= WebGUI::Form::hidden($self->session,{"name"=>"uid","value"=>$uid}); $vars->{'expired.form.oldPassword'} = WebGUI::Form::password($self->session,{"name"=>"oldPassword"}); $vars->{'expired.form.oldPassword.label'} = $i18n->get(10,'AuthWebGUI'); $vars->{'expired.form.password'} = WebGUI::Form::password($self->session,{"name"=>"identifier"}); $vars->{'expired.form.password.label'} = $i18n->get(11,'AuthWebGUI'); $vars->{'expired.form.passwordConfirm'} = WebGUI::Form::password($self->session,{"name"=>"identifierConfirm"}); $vars->{'expired.form.passwordConfirm.label'} = $i18n->get(2,'AuthWebGUI'); $vars->{'expired.form.submit'} = WebGUI::Form::submit($self->session,{}); $vars->{'expired.form.footer'} = WebGUI::Form::formFooter($self->session,); return WebGUI::Asset::Template->new($self->session,$self->getExpiredPasswordTemplateId)->process($vars); } #------------------------------------------------------------------- sub resetExpiredPasswordSave { my $self = shift; my ($error,$u,$properties,$msg); $u = WebGUI::User->new($self->session,$self->session->form->process("uid")); my $i18n = WebGUI::International->new($self->session); $error .= $self->error if(!$self->authenticate($u->username,$self->session->form->process("oldPassword"))); $error .= '
  • '.$i18n->get(5,'AuthWebGUI').'
  • ' if($self->session->form->process("identifier") eq "password"); $error .= '
  • '.$i18n->get(12,'AuthWebGUI').'
  • ' if ($self->session->form->process("oldPassword") eq $self->session->form->process("identifier")); $error .= $self->error if(!$self->_isValidPassword($self->session->form->process("identifier"),$self->session->form->process("identifierConfirm"))); return $self->resetExpiredPassword($u->userId, "

    ".$i18n->get(70)."

    ".$error) if($error ne ""); $properties->{identifier} = Digest::MD5::md5_base64($self->session->form->process("identifier")); $properties->{passwordLastUpdated} =$self->session->datetime->time(); $self->saveParams($u->userId,$self->authMethod,$properties); $self->_logSecurityMessage(); return $self->SUPER::login(); } #------------------------------------------------------------------- sub validateEmail { my $self = shift; my ($userId) = $self->session->db->quickArray("select userId from authentication where fieldData=? and fieldName='emailValidationKey' and authMethod='WebGUI'", [$self->session->form->process("key")]); if (defined $userId) { my $u = WebGUI::User->new($self->session,$userId); $u->status("Active"); $self->session->db->write("DELETE FROM authentication WHERE userId = ? AND fieldName = 'emailValidationKey'", [$userId]); } return $self->displayLogin; } #------------------------------------------------------------------- =head2 updateAccount ( ) Sets properties to update and passes them to the superclass =cut sub updateAccount { my $self = shift; my $i18n = WebGUI::International->new($self->session); my $username = $self->session->form->process('authWebGUI.username'); my $password = $self->session->form->process('authWebGUI.identifier'); my $passConfirm = $self->session->form->process('authWebGUI.identifierConfirm'); my $display = '
  • '.$i18n->get(81).'
  • '; my $error = ""; if($self->userId eq '1'){ return $self->displayLogin; } if($username){ if($self->_isDuplicateUsername($username)){ $error .= $self->error; } if(!$self->_isValidUsername($username)){ $error .= $self->error; } } if($password){ if(!$self->_isValidPassword($password,$passConfirm)){ $error .= $self->error; } } if($error){ $display = $error; } my $properties; my $u = $self->user; if(!$error){ if($username){ $u->username($username); } if($password){ my $userData = $self->getParams; unless ($password eq "password") { $properties->{identifier} = Digest::MD5::md5_base64($password); $self->_logSecurityMessage(); if($userData->{identifier} ne $properties->{identifier}){ $properties->{passwordLastUpdated} =$self->session->datetime->time(); } } } } $self->saveParams($u->userId,$self->authMethod,$properties); $self->session->user(undef,undef,$u); return $self->displayAccount($display); } 1;