[LON-CAPA-cvs] cvs: loncom /interface lonpreferences.pm resetpw.pm
raeburn
raeburn at source.lon-capa.org
Sat Feb 8 23:43:21 EST 2020
raeburn Sun Feb 9 04:43:21 2020 EDT
Modified files:
/loncom/interface lonpreferences.pm resetpw.pm
Log:
- Rules for length and/or characters in password (internal) checked client-
side when user sets new password via Preferences or Forgot Password utility.
- Prompt retry setting new password after following e-mailed time-limited link
(Forgot Password utility) when invalid username and/or e-mail address
submitted.
-------------- next part --------------
Index: loncom/interface/lonpreferences.pm
diff -u loncom/interface/lonpreferences.pm:1.235 loncom/interface/lonpreferences.pm:1.236
--- loncom/interface/lonpreferences.pm:1.235 Wed Aug 21 22:41:13 2019
+++ loncom/interface/lonpreferences.pm Sun Feb 9 04:43:20 2020
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Preferences
#
-# $Id: lonpreferences.pm,v 1.235 2019/08/21 22:41:13 raeburn Exp $
+# $Id: lonpreferences.pm,v 1.236 2020/02/09 04:43:20 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1273,18 +1273,18 @@
$r->print(Apache::loncommon::start_page('Personal Data'));
$r->print(Apache::lonhtmlcommon::breadcrumbs('Change Password'));
}
- my ($blocked,$blocktext) =
- &Apache::loncommon::blocking_status('passwd');
- if ($blocked) {
- $r->print('<p class="LC_warning">'.$blocktext.'</p>');
- return;
- }
if ((!defined($caller)) || ($caller eq 'preferences')) {
$user = $env{'user.name'};
$domain = $env{'user.domain'};
if (!defined($caller)) {
$caller = 'preferences';
}
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('passwd');
+ if ($blocked) {
+ $r->print('<p class="LC_warning">'.$blocktext.'</p>');
+ return;
+ }
} elsif ($caller eq 'reset_by_email') {
my %data = &Apache::lonnet::tmpget($mailtoken);
if (keys(%data) == 0) {
@@ -1301,6 +1301,12 @@
$user = $data{'username'};
$domain = $data{'domain'};
$currentpass = $data{'temppasswd'};
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('passwd',$user,$domain);
+ if ($blocked) {
+ $r->print('<p class="LC_warning">'.$blocktext.'</p>');
+ return;
+ }
} else {
$r->print(
'<p class="LC_warning">'
@@ -1360,7 +1366,7 @@
my $jsh=Apache::File->new($include."/londes.js");
$r->print(<$jsh>);
}
- $r->print(&jscript_send($caller,$extrafields));
+ $r->print(&jscript_send($caller,$domain,$currentauth,$extrafields));
$r->print(<<ENDFORM);
$errormessage
@@ -1377,11 +1383,105 @@
}
sub jscript_send {
- my ($caller,$extrafields) = @_;
+ my ($caller,$domain,$currentauth,$extrafields) = @_;
+ my ($min,$max,$rulestr,$numrules);
+ $min = $Apache::lonnet::passwdmin;
+ my %js_lt = &Apache::lonlocal::texthash(
+ uc => 'New password needs at least one upper case letter',
+ lc => 'New password needs at least one lower case letter',
+ num => 'New password needs at least one number',
+ spec => 'New password needs at least one non-alphanumeric',
+ blank1 => 'Empty Password field',
+ blank2 => 'Empty Confirm Password field',
+ mismatch => 'Contents of Password and Confirm Password fields must match',
+ fail => 'Please fix the following:',
+ );
+ &js_escape(\%js_lt);
+ if ($currentauth eq 'internal:') {
+ if ($domain ne '') {
+ my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
+ if (keys(%passwdconf)) {
+ if ($passwdconf{min}) {
+ $min = $passwdconf{min};
+ }
+ if ($passwdconf{max}) {
+ $max = $passwdconf{max};
+ $js_lt{'long'} = &js_escape(&mt('Maximum password length: [_1]',$max));
+ }
+ if (ref($passwdconf{chars}) eq 'ARRAY') {
+ if (@{$passwdconf{chars}}) {
+ $rulestr = join('","',@{$passwdconf{chars}});
+ $numrules = scalar(@{$passwdconf{chars}});
+ }
+ }
+ }
+ }
+ }
+ $js_lt{'short'} = &js_escape(&mt('Minimum password length: [_1]',$min));
+
+ my $passwdcheck = <<"ENDJS";
+ var errors = new Array();
+ var min = parseInt("$min") || 0;
+ var currauth = "$currentauth";
+ if (this.document.client.elements.newpass_1.value == '') {
+ errors.push("$js_lt{'blank1'}");
+ }
+ if (this.document.client.elements.newpass_2.value == '') {
+ errors.push("$js_lt{'blank2'}");
+ }
+ if (errors.length == 0) {
+ if (this.document.client.elements.newpass_1.value != this.document.client.elements.newpass_2.value) {
+ errors.push("$js_lt{'mismatch'}");
+ }
+ var posspass = this.document.client.elements.newpass_1.value;
+ if (min > 0) {
+ if (posspass.length < min) {
+ errors.push("$js_lt{'short'}");
+ }
+ }
+ if (currauth == 'internal:') {
+ var max = parseInt("$max") || 0;
+ if (max > 0) {
+ if (posspass.length > max) {
+ errors.push("$js_lt{'long'}");
+ }
+ }
+ var numrules = parseInt("$numrules") || 0;
+ if (numrules > 0) {
+ var rules = new Array("$rulestr");
+ for (var i=0; i<rules.length; i++) {
+ if (rules[i] == 'uc') {
+ if (!posspass.match(/[A-Z]/)) {
+ errors.push("$js_lt{'uc'}");
+ }
+ } else if (rules[i] == 'lc') {
+ if (!posspass.match(/[a-z]/)) {
+ errors.push("$js_lt{'lc'}");
+ }
+ } else if (rules[i] == 'num') {
+ if (!posspass.match(/\\d/)) {
+ errors.push("$js_lt{'num'}");
+ }
+ } else if (rules[i] == 'spec') {
+ var pattern = /^[!@#$%^&*()_+\\-=\\[\\]{};':"\\\|,.<a>\\/?]/;
+ if (!posspass.match(pattern)) {
+ errors.push("$js_lt{'spec'}");
+ }
+ }
+ }
+ }
+ }
+ }
+ if (errors.length > 0) {
+ alert("$js_lt{'fail'}"+"\\n\\n"+errors.join("\\n"));
+ return;
+ }
+ENDJS
my $output = qq|
<script type="text/javascript" language="JavaScript">
function send() {
+$passwdcheck
uextkey=this.document.client.elements.ukey_cpass.value;
lextkey=this.document.client.elements.lkey_cpass.value;
initkeys();
@@ -1522,14 +1622,8 @@
}
sub verify_and_change_password {
- my ($r,$caller,$mailtoken,$ended) = @_;
+ my ($r,$caller,$mailtoken,$timelimit,$extrafields,$ended) = @_;
my ($user,$domain,$homeserver);
- my ($blocked,$blocktext) =
- &Apache::loncommon::blocking_status('passwd');
- if ($blocked) {
- $r->print('<p class="LC_warning">'.$blocktext.'</p>');
- return;
- }
if ($caller eq 'reset_by_email') {
$user = $env{'form.uname'};
$domain = $env{'form.udom'};
@@ -1538,20 +1632,30 @@
if ($homeserver eq 'no_host') {
&passwordchanger($r,"<p>\n<span class='LC_error'>".
&mt("Invalid username and/or domain")."</span>\n</p>",
- $caller,$mailtoken);
- return 1;
+ $caller,$mailtoken,$timelimit,$extrafields);
+ return 'no_host';
}
} else {
&passwordchanger($r,"<p>\n<span class='LC_error'>".
&mt("Username and domain were blank")."</span>\n</p>",
- $caller,$mailtoken);
- return 1;
+ $caller,$mailtoken,$timelimit,$extrafields);
+ return 'missingdata';
}
} else {
$user = $env{'user.name'};
$domain = $env{'user.domain'};
$homeserver = $env{'user.home'};
}
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('passwd',$user,$domain);
+ if ($blocked) {
+ $r->print('<p class="LC_warning">'.$blocktext.'</p>');
+ if ($caller eq 'reset_by_email') {
+ return 'blocked';
+ } else {
+ return;
+ }
+ }
my $currentauth=&Apache::lonnet::queryauthenticate($user,$domain);
# Check for authentication types that allow changing of the password.
if ($currentauth !~ /^(unix|internal):/) {
@@ -1559,8 +1663,8 @@
&passwordchanger($r,"<p>\n<span class='LC_error'>".
&mt("Authentication type for this user can not be changed by this mechanism").
"</span>\n</p>",
- $caller,$mailtoken);
- return 1;
+ $caller,$mailtoken,$timelimit,$extrafields);
+ return 'otherauth';
} else {
return;
}
@@ -1576,8 +1680,12 @@
defined($newpass2) ){
&passwordchanger($r,"<p>\n<span class='LC_error'>".
&mt("One or more password fields were blank").
- "</span>\n</p>",$caller,$mailtoken);
- return;
+ "</span>\n</p>",$caller,$mailtoken,$timelimit,$extrafields);
+ if ($caller eq 'reset_by_email') {
+ return 'missingdata';
+ } else {
+ return;
+ }
}
# Get the keys
my $lonhost = $r->dir_config('lonHostID');
@@ -1595,7 +1703,11 @@
</p>
ENDERROR
# Probably should log an error here
- return 1;
+ if ($caller eq 'reset_by_email') {
+ return 'internalerror';
+ } else {
+ return;
+ }
}
my ($ckey,$n1key,$n2key)=split(/&/,$tmpinfo);
#
@@ -1609,31 +1721,39 @@
&passwordchanger($r,
'<span class="LC_error">'.
&mt('Could not verify current authentication.').' '.
- &mt('Please try again.').'</span>',$caller,$mailtoken);
- return 1;
+ &mt('Please try again.').'</span>',$caller,$mailtoken,$timelimit,$extrafields);
+ return 'emptydata';
}
if ($currentpass ne $data{'temppasswd'}) {
&passwordchanger($r,
'<span class="LC_error">'.
&mt('Could not verify current authentication.').' '.
- &mt('Please try again.').'</span>',$caller,$mailtoken);
- return 1;
+ &mt('Please try again.').'</span>',$caller,$mailtoken,$timelimit,$extrafields);
+ return 'missingtemp';
}
}
if ($newpass1 ne $newpass2) {
&passwordchanger($r,
'<span class="LC_warning">'.
&mt('The new passwords you entered do not match.').' '.
- &mt('Please try again.').'</span>',$caller,$mailtoken);
- return 1;
+ &mt('Please try again.').'</span>',$caller,$mailtoken,$timelimit,$extrafields);
+ if ($caller eq 'reset_by_email') {
+ return 'mismatch';
+ } else {
+ return;
+ }
}
if ($currentauth eq 'unix:') {
if (length($newpass1) < 7) {
&passwordchanger($r,
'<span class="LC_warning">'.
&mt('Passwords must be a minimum of 7 characters long.').' '.
- &mt('Please try again.').'</span>',$caller,$mailtoken);
- return 1;
+ &mt('Please try again.').'</span>',$caller,$mailtoken,$timelimit,$extrafields);
+ if ($caller eq 'reset_by_email') {
+ return 'length';
+ } else {
+ return;
+ }
}
} else {
my $warning = &Apache::loncommon::check_passwd_rules($domain,$newpass1);
@@ -1641,8 +1761,12 @@
&passwordchanger($r,'<span class="LC_warning">'.
$warning.
&mt('Please try again.').'</span>',
- $caller,$mailtoken);
- return 1;
+ $caller,$mailtoken,$timelimit,$extrafields);
+ if ($caller eq 'reset_by_email') {
+ return 'rules';
+ } else {
+ return;
+ }
}
}
#
@@ -1662,8 +1786,12 @@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\`abcdefghijklmnopqrstuvwxyz{|}~
</pre></span>
ENDERROR
- &passwordchanger($r,$errormessage,$caller,$mailtoken);
- return 1;
+ &passwordchanger($r,$errormessage,$caller,$mailtoken,$timelimit,$extrafields);
+ if ($caller eq 'reset_by_email') {
+ return 'badchars';
+ } else {
+ return;
+ }
}
#
# Change the password (finally)
@@ -1686,7 +1814,7 @@
# error error: run in circles, scream and shout
if ($caller eq 'reset_by_email') {
if (!$result) {
- return 1;
+ return 'error';
} else {
return $result;
}
@@ -2318,7 +2446,7 @@
}elsif($env{'form.action'} eq 'changepass'){
&passwordchanger($r);
}elsif($env{'form.action'} eq 'verify_and_change_pass'){
- &verify_and_change_password($r,'preferences','',\$ended);
+ &verify_and_change_password($r,'preferences','','','',\$ended);
}elsif($env{'form.action'} eq 'changescreenname'){
&screennamechanger($r);
}elsif($env{'form.action'} eq 'verify_and_change_screenname'){
Index: loncom/interface/resetpw.pm
diff -u loncom/interface/resetpw.pm:1.46 loncom/interface/resetpw.pm:1.47
--- loncom/interface/resetpw.pm:1.46 Fri Aug 30 00:09:39 2019
+++ loncom/interface/resetpw.pm Sun Feb 9 04:43:20 2020
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Allow access to password changing via a token sent to user's e-mail.
#
-# $Id: resetpw.pm,v 1.46 2019/08/30 00:09:39 raeburn Exp $
+# $Id: resetpw.pm,v 1.47 2020/02/09 04:43:20 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -639,7 +639,9 @@
$invalidinfo = "||$env{'form.uname'}|| ||$env{'form.udom'}|| ";
}
} else {
- unless ((lc($env{'form.uname'}) eq lc($data{'username'})) && (lc($env{'form.udom'}) eq lc($data{'domain'}))) {
+ if ((lc($env{'form.uname'}) eq lc($data{'username'})) && (lc($env{'form.udom'}) eq lc($data{'domain'}))) {
+ $env{'form.uname'} = $data{'username'};
+ } else {
$invalidinfo = "||$env{'form.uname'}|| ||$env{'form.udom'}|| ";
}
}
@@ -661,7 +663,53 @@
}
if ($invalidinfo) {
&Apache::lonnet::logthis("Forgot Password -- token data: ||$data{'username'}|| ||$data{'domain'}|| ||$data{'email'}|| differs from form: $invalidinfo");
- $r->print(&generic_failure_msg($contact_name,$contact_email));
+ my $retry;
+ $r->print(
+ '<p class="LC_warning">'
+ .&mt('A problem occurred when attempting to reset'
+ .' the password for your account.').'</p>');
+ if (($formfields{'username'}) && ($formfields{'email'})) {
+ if ($needscase) {
+ $r->print('<p>'
+ .&mt('Please verify you entered the correct username and e-mail address, '
+ .'including the correct lower and/or upper case letters')
+ .'</p>');
+ } else {
+ $r->print('<p>'
+ .&mt('Please verify you entered the correct username and e-mail address.')
+ .'</p>');
+ }
+ $retry = 1;
+ } elsif ($formfields{'username'}) {
+ if ($needscase) {
+ $r->print('<p>'
+ .&mt('Please verify you entered the correct username, '
+ .'including the correct lower and/or upper case letters')
+ .'</p>');
+ } else {
+ $r->print('<p>'
+ .&mt('Please verify you entered the correct username.')
+ .'</p>');
+ }
+ $retry = 1;
+ } elsif ($formfields{'email'}) {
+ if ($needscase) {
+ $r->print('<p>'
+ .&mt('Please verify you entered the correct e-mail address, '
+ .'including the correct lower and/or upper case letters')
+ .'</p>');
+ } else {
+ $r->print('<p>'
+ .&mt('Please verify you entered the correct e-mail address.')
+ .'</p>');
+ }
+ $retry = 1;
+ }
+ if ($retry) {
+ &Apache::lonpreferences::passwordchanger($r,'','reset_by_email',$token,$timelimit,\%formfields);
+ } else {
+ $r->print(&generic_failure_msg($contact_name,$contact_email));
+ }
unless ($formfields{'username'}) {
delete($env{'form.uname'});
delete($env{'form.udom'});
@@ -669,7 +717,7 @@
return;
}
my $change_failed =
- &Apache::lonpreferences::verify_and_change_password($r,'reset_by_email',$token);
+ &Apache::lonpreferences::verify_and_change_password($r,'reset_by_email',$token,$timelimit,\%formfields);
if (!$change_failed) {
my $delete = &Apache::lonnet::tmpdel($token);
my $now = &Apache::lonlocal::locallocaltime(time);
@@ -729,7 +777,8 @@
.'</p>'
.&display_actions($contact_email,$domdesc,$token)
);
- } else {
+ } elsif (($change_failed eq 'internalerror') || ($change_failed eq 'missingtemp') ||
+ ($change_failed eq 'error')) {
$r->print(&generic_failure_msg($contact_name,$contact_email));
}
unless ($formfields{'username'}) {
@@ -749,7 +798,20 @@
if ($needscase) {
$r->print(' '.&mt('User data entered must match LON-CAPA account information (including case).'));
}
- $r->print(' ');
+ $r->print('<br />');
+ }
+ my ($min,$max,$minrule,$maxrule);
+ if ($passwdconf->{min}) {
+ $min = $passwdconf->{min};
+ } else {
+ $min = $Apache::lonnet::passwdmin;
+ }
+ if ($min) {
+ $minrule = &mt('Minimum password length: [_1]',$min);
+ }
+ if ($passwdconf->{max}) {
+ $max = $passwdconf->{max};
+ $maxrule = &mt('Maximum password length: [_1]',$max);
}
if (ref($passwdconf->{chars}) eq 'ARRAY') {
my %rules;
@@ -766,9 +828,24 @@
$r->print('<li>'.$rulenames{$poss}.'</li>');
}
}
+ if ($min) {
+ $r->print('<li>'.$minrule.'</li>');
+ }
+ if ($max) {
+ $r->print('<li>'.$maxrule.'</li>');
+ }
$r->print('</ul>');
} else {
- $r->print(&mt('The new password must contain at least 7 characters.').' ');
+ if ($min && $max) {
+ $r->print(&mt('The new password must satisfy the following:').'<ul>'."\n".
+ '<li>'.$minrule.'</li>'."\n".
+ '<li>'.$maxrule.'</li>'."\n".
+ '</ul>'."\n");
+ } elsif ($min) {
+ $r->print($minrule.'<br />');
+ } elsif ($max) {
+ $r->print($maxrule.'<br />');
+ }
}
$r->print(&mt('Your new password will be sent to the LON-CAPA server in an encrypted form.').'<br />');
&Apache::lonpreferences::passwordchanger($r,'','reset_by_email',$token,$timelimit,\%formfields);
@@ -776,7 +853,8 @@
} else {
$r->print(
'<p class="LC_warning">'
- .&mt('Sorry, the token generated when you requested a password reset has expired. Please submit a [_1]new request[_2], and follow the link to the web page included in the new e-mail that will be sent to you, to allow you to enter a new password.'
+ .&mt('Sorry, the token generated when you requested a password reset has expired.').'<br />'
+ .&mt('Please submit a [_1]new request[_2], and follow the link to the web page included in the new e-mail that will be sent to you, to allow you to enter a new password.'
,'<a href="/adm/resetpw">','</a>')
.'</p>'
);
More information about the LON-CAPA-cvs
mailing list