add: Settings can now return errors and messages to the user

add: WebGUI Auth password recovery can now be done by profile fields or just e-mail address
This commit is contained in:
Doug Bell 2007-07-09 21:23:11 +00:00
parent efd1e6705b
commit 8674572035
6 changed files with 530 additions and 57 deletions

View file

@ -400,9 +400,10 @@ sub editUserFormSave {
=cut
sub editUserSettingsForm {
my $self = shift;
my $i18n = WebGUI::International->new($self->session,'AuthWebGUI');
my $f = WebGUI::HTMLForm->new($self->session);
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"),
@ -453,11 +454,14 @@ sub editUserSettingsForm {
-value=>$self->session->setting->get("webguiChangePassword"),
-label=>$i18n->get(18)
);
$f->yesNo(
$f->selectList(
-name => "webguiPasswordRecovery",
-value => $self->session->setting->get("webguiPasswordRecovery"),
-label => $i18n->get(6),
-hoverHelp => $i18n->get('webguiPasswordRecovery hoverHelp')
-hoverHelp => $i18n->get('webguiPasswordRecovery hoverHelp'),
-options => $self->getPasswordRecoveryTypesAvailable,
-size => 1,
-multiple => 0,
);
$f->yesNo(
-name => "webguiPasswordRecoveryRequireUsername",
@ -510,9 +514,11 @@ sub editUserSettingsForm {
#-------------------------------------------------------------------
sub editUserSettingsFormSave {
my $self = shift;
my $f = $self->session->form;
my $s = $self->session->setting;
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"));
@ -524,9 +530,27 @@ sub editUserSettingsFormSave {
$s->set("webguiChangeUsername", $f->process("webguiChangeUsername","yesNo"));
$s->set("webguiChangePassword", $f->process("webguiChangePassword","yesNo"));
# Special case to make sure we have at least one field enabled before allowing
# password recovery to be turned on.
$s->set("webguiPasswordRecovery", $f->process("webguiPasswordRecovery","yesNo") && ($self->session->db->quickArray("SELECT COUNT(*) FROM userProfileField WHERE requiredForPasswordRecovery = 1"))[0] > 0);
# 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"));
@ -536,6 +560,13 @@ sub editUserSettingsFormSave {
$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;
}
}
#-------------------------------------------------------------------
@ -564,10 +595,45 @@ sub getLoginTemplateId {
#-------------------------------------------------------------------
sub getPasswordRecoveryTemplateId {
my $self = shift;
return $self->session->setting->get("webguiPasswordRecoveryTemplate") || "PBtmpl0000000000000014";
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 {
@ -594,22 +660,88 @@ sub 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');
my $self = WebGUI::Auth->new($session,$authMethod,$userId,\@callable);
bless $self, $class;
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') and $self->userId eq '1';
my @fields = @{WebGUI::ProfileField->getPasswordRecoveryFields($self->session)};
return $self->displayLogin unless @fields;
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
= "<h1>" . $i18n->get('recover password banner', 'AuthWebGUI') . " </h1> <br /> <br /> "
. "<h3>" . $i18n->get('email recover password start message', 'AuthWebGUI') ."</h3>"
;
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);
@ -647,16 +779,37 @@ sub recoverPassword {
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 $i18n = WebGUI::International->new($self->session);
my $i18n2 = WebGUI::International->new($self->session, 'AuthWebGUI');
return $self->displayLogin unless $self->session->setting->get('webguiPasswordRecovery') and $self->userId eq '1';
my $self = shift;
my $username;
if ($self->getSetting('passwordRecoveryRequireUsername')) {
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;
}
@ -742,6 +895,146 @@ sub recoverPasswordFinish {
}
}
#-------------------------------------------------------------------
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 "<h1>". $i18n->get('recover password banner', 'AuthWebGUI')." </h1> <br> <br> <h3>". $i18n->get('email recover password finish message1', 'AuthWebGUI'). $email . $i18n->get('email recover password finish message2', 'AuthWebGUI') . "</h3>";
}
#-------------------------------------------------------------------
# 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 = "<h1>".$i18n->get('recover password banner', 'AuthWebGUI') ."</h1> <br><br><h3>". $i18n->get('email password recovery end message', 'AuthWebGUI')."</h3>";
$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;