[LON-CAPA-cvs] cvs: loncom / lonsql /interface loncommon.pm lonpreferences.pm resetpw.pm /lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Tue Apr 23 21:44:46 EDT 2019
raeburn Wed Apr 24 01:44:46 2019 EDT
Modified files:
/loncom/interface resetpw.pm lonpreferences.pm loncommon.pm
/loncom lonsql
/loncom/lonnet/perl lonnet.pm
Log:
- Forgot Password utility
- Support configurable: link lifetime, case sensitivity (for username and
e-mail address), information required, e-mail types, and custom text.
- Bug 6648: captcha can be enabled for public-facing web form.
-------------- next part --------------
Index: loncom/interface/resetpw.pm
diff -u loncom/interface/resetpw.pm:1.43 loncom/interface/resetpw.pm:1.44
--- loncom/interface/resetpw.pm:1.43 Fri Feb 8 19:57:29 2019
+++ loncom/interface/resetpw.pm Wed Apr 24 01:44:30 2019
@@ -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.43 2019/02/08 19:57:29 raeburn Exp $
+# $Id: resetpw.pm,v 1.44 2019/04/24 01:44:30 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -55,6 +55,7 @@
use Apache::lonacc;
use Apache::lonnet;
use Apache::loncommon;
+use Apache::lonpreferences;
use Apache::lonlocal;
use LONCAPA;
use HTML::Entities;
@@ -92,22 +93,80 @@
$uname =~ s/^\s+|\s+$//g;
$uname = &LONCAPA::clean_username($uname);
my $udom = &LONCAPA::clean_domain($env{'form.udom'});
- my ($domdesc,$otherinst);
+ my ($domdesc,$otherinst,$lookup);
if ($udom) {
$domdesc = &Apache::lonnet::domain($udom,'description');
if ($domdesc) {
$otherinst = 1;
my @ids=&Apache::lonnet::current_machine_ids();
my %servers = &Apache::lonnet::internet_dom_servers($udom);
- foreach my $server (keys(%servers)) {
- if (grep(/^\Q$server\E$/, at ids)) {
+ foreach my $hostid (keys(%servers)) {
+ if (grep(/^\Q$hostid\E$/, at ids)) {
$otherinst = 0;
last;
}
}
}
}
+ my $dom_in_effect = $defdom;
+ if (($udom ne '') && ($domdesc ne '')) {
+ unless ($otherinst) {
+ $dom_in_effect = $udom;
+ }
+ }
+ my %passwdconf = &Apache::lonnet::get_passwdconf($dom_in_effect);
my $token = $env{'form.token'};
+ my $useremail = $env{'form.useremail'};
+ if (($udom ne '') && (!$otherinst) && (!$token)) {
+ if ($uname ne '') {
+ my $uhome = &Apache::lonnet::homeserver($uname,$udom);
+ if ($uhome eq 'no_host') {
+ my %srch = (srchby => 'uname_ci',
+ srchdomain => $udom,
+ srchterm => $uname,
+ srchtype => 'exact');
+ my %srch_results = &Apache::lonnet::usersearch(\%srch);
+ if (keys(%srch_results) > 1) {
+ $lookup = 'nonunique';
+ if ($useremail =~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) {
+ foreach my $key (keys(%srch_results)) {
+ if (ref($srch_results{$key}) eq 'HASH') {
+ if ($srch_results{$key}{permanentemail} =~ /^\Q$useremail\E$/i) {
+ ($uname) = split(/:/,$key);
+ undef($lookup);
+ last;
+ }
+ }
+ }
+ }
+ } elsif (keys(%srch_results) == 1) {
+ my $match = (keys(%srch_results))[0];
+ ($uname) = split(/:/,$match);
+ } else {
+ $lookup = 'nomatch';
+ }
+ }
+ }
+ if (($lookup eq 'nomatch') || ($uname eq '')) {
+ if (($useremail =~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) &&
+ ($passwdconf{'resetprelink'} eq 'either')) {
+ my %srch = (srchby => 'email',
+ srchdomain => $udom,
+ srchterm => $useremail,
+ srchtype => 'exact');
+ my %srch_results = &Apache::lonnet::usersearch(\%srch);
+ if (keys(%srch_results) > 1) {
+ $lookup = 'nonunique';
+ } elsif (keys(%srch_results) == 1) {
+ my $match = (keys(%srch_results))[0];
+ ($uname) = split(/:/,$match);
+ undef($lookup);
+ } else {
+ $lookup = 'nomatch';
+ }
+ }
+ }
+ }
my $brcrum = [];
if ($token) {
push (@{$brcrum},
@@ -157,12 +216,11 @@
thdo => 'The domain you have selected is for another institution.',
yowi => 'You will be switched to the Forgot Password utility at that institution.',
unam => 'You must enter a username.',
- mail => 'You must enter an e-mail address.'
+ mail => 'You must enter an e-mail address.',
+ eith => 'Enter a username and/or an e-mail address.',
);
&js_escape(\%js_lt);
$js = <<"END";
-<script type="text/javascript">
-// <![CDATA[
function verifyDomain(caller,form) {
var redirect = 1;
var instdoms = new Array($instdomstr);
@@ -174,14 +232,43 @@
}
}
}
+ if (redirect == 0) {
+ if (caller.options[caller.selectedIndex].value != '$dom_in_effect') {
+ document.forgotpw.uname.value = '';
+ document.forgotpw.useremail.value = '';
+ form.submit();
+ }
+ }
if (redirect == 1) {
if (confirm('$js_lt{thdo}\\n$js_lt{yowi}')) {
form.submit();
+ } else {
+ for (var i=0; i<caller.options.length; i++) {
+ if (caller.option[i].value == '$dom_in_effect') {
+ caller.selectedIndex = i;
+ break;
+ }
+ }
}
}
return;
}
+END
+ if ($passwdconf{resetprelink} eq 'either') {
+ $js .= <<"END";
+function validInfo() {
+ if ((document.forgotpw.uname.value == '') &&
+ (document.forgotpw.useremail.value == '')) {
+ alert("$js_lt{'eith'}");
+ return false;
+ }
+ return true;
+}
+END
+ } else {
+ $js .= <<"END";
+
function validInfo() {
if (document.forgotpw.uname.value == '') {
alert("$js_lt{'unam'}");
@@ -193,16 +280,19 @@
}
return true;
}
-// ]]>
-</script>
END
+ }
+ }
+ $js = &Apache::lonhtmlcommon::scripttag($js);
+ if (($passwdconf{'captcha'} eq 'recaptcha') && ($passwdconf{'recaptchaversion'} >=2)) {
+ $js.= "\n".'<script src="https://www.google.com/recaptcha/api.js"></script>'."\n";
}
my $header = &Apache::loncommon::start_page('Reset password',$js,$args).
'<h2>'.&mt('Reset forgotten LON-CAPA password').'</h2>';
my $output;
if ($token) {
$r->print($header);
- &reset_passwd($r,$token,$contact_name,$contact_email);
+ &reset_passwd($r,$token,$contact_name,$contact_email,\%passwdconf);
$r->print(&Apache::loncommon::end_page());
return OK;
} elsif ($udom) {
@@ -211,66 +301,121 @@
$contact_name,$contact_email);
} elsif ($otherinst) {
($header,$output) = &homeserver_redirect($uname,$udom,$domdesc,$brcrum);
- } elsif ($uname) {
- my $authtype = &Apache::lonnet::queryauthenticate($uname,$udom);
- if ($authtype =~ /^internal/) {
- my $useremail = $env{'form.useremail'};
- my ($blocked,$blocktext) =
- &Apache::loncommon::blocking_status('passwd',$uname,$udom);
- if ($blocked) {
- $output = '<p class="LC_warning">'.$blocktext.'</p>'
- .&display_actions($contact_email,$domdesc);
- } elsif ($useremail !~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) {
- $output = &invalid_state('baduseremail',$domdesc,
+ } elsif (($uname) || ($useremail)) {
+ my $earlyout;
+ unless ($passwdconf{'captcha'} eq 'unused') {
+ my ($captcha_chk,$captcha_error) =
+ &Apache::loncommon::captcha_response('passwords',$server);
+ if ($captcha_chk != 1) {
+ my $error = 'captcha';
+ if ($passwdconf{'captcha'} eq 'recaptcha') {
+ $error = 'recaptcha';
+ }
+ $output = &invalid_state($error,$domdesc,
$contact_name,$contact_email);
- } else {
- my %userinfo =
- &Apache::lonnet::get('environment',\@emailtypes,
- $udom,$uname);
- my @allemails;
- foreach my $type (@emailtypes) {
- my $email = $userinfo{$type};
- my @items;
- if ($email =~ /,/) {
- @items = split(',',$userinfo{$type});
- } else {
- @items = ($email);
- }
- foreach my $item (@items) {
- if ($item =~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) {
- unless(grep(/^\Q$item\E$/, at allemails)) {
- push(@allemails,$item);
+ $earlyout = 1;
+ }
+ }
+ unless ($earlyout) {
+ if ($lookup) {
+ $output = &invalid_state($lookup,$domdesc,
+ $contact_name,$contact_email);
+ $earlyout = 1;
+ }
+ }
+ unless ($earlyout) {
+ my $authtype = &Apache::lonnet::queryauthenticate($uname,$udom);
+ if ($authtype =~ /^internal/) {
+ my ($blocked,$blocktext) =
+ &Apache::loncommon::blocking_status('passwd',$uname,$udom);
+ if ($blocked) {
+ $output = '<p class="LC_warning">'.$blocktext.'</p>'
+ .&display_actions($contact_email,$domdesc);
+ } elsif (($passwdconf{'resetprelink'} ne 'either') &&
+ ($useremail !~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/)) {
+ $output = &invalid_state('baduseremail',$domdesc,
+ $contact_name,$contact_email);
+ } else {
+ my %userinfo =
+ &Apache::lonnet::get('environment',\@emailtypes,
+ $udom,$uname);
+ my @allemails;
+ foreach my $type (@emailtypes) {
+ if (ref($passwdconf{resetemail}) eq 'ARRAY') {
+ if ($type eq 'permanentemail') {
+ next unless (grep(/^permanent$/,@{$passwdconf{resetemail}}));
+ } elsif ($type eq 'critnotification') {
+ next unless (grep(/^critical$/,@{$passwdconf{resetemail}}));
+ } elsif ($type eq 'notification') {
+ next unless (grep(/^notify$/,@{$passwdconf{resetemail}}));
+ }
+ }
+ my $email = $userinfo{$type};
+ my @items;
+ if ($email =~ /,/) {
+ @items = split(',',$userinfo{$type});
+ } else {
+ @items = ($email);
+ }
+ foreach my $item (@items) {
+ if ($item =~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) {
+ unless (grep(/^\Q$item\E$/i, at allemails)) {
+ push(@allemails,$item);
+ }
}
}
}
- }
- if (@allemails > 0) {
- if (grep(/^\Q$useremail\E$/, at allemails)) {
- $output = &send_token($uname,$udom,$useremail,$server,
- $domdesc,$contact_name,
- $contact_email);
+ if (@allemails > 0) {
+ my ($sendto,$warning,$timelimit);
+ my $timelimit = 2;
+ if ($passwdconf{'resetlink'} =~ /^\d+(|\.\d*)$/) {
+ $timelimit = $passwdconf{'resetlink'};
+ }
+ if ($passwdconf{'resetprelink'} eq 'either') {
+ if ($useremail ne '') {
+ if (grep(/^\Q$useremail\E$/i, at allemails)) {
+ $sendto = $useremail;
+ } else {
+ $warning = &mt('The e-mail address you entered did not match the expected e-mail address.');
+ }
+ } elsif (@allemails > 1) {
+ $warning = &mt('More than one e-mail address is associated with your username, and one has been selected to receive the message sent by LON-CAPA.');
+ }
+ unless ($sendto) {
+ $sendto = $allemails[0];
+ }
+ } else {
+ if (grep(/^\Q$useremail\E$/i, at allemails)) {
+ $sendto = $useremail;
+ } else {
+ $output = &invalid_state('mismatch',$domdesc,
+ $contact_name,
+ $contact_email);
+ }
+ }
+ if ($sendto) {
+ $output = &send_token($uname,$udom,$sendto,$server,
+ $domdesc,$contact_name,
+ $contact_email,$timelimit,$warning);
+ }
} else {
- $output = &invalid_state('mismatch',$domdesc,
- $contact_name,
- $contact_email);
+ $output = &invalid_state('missing',$domdesc,
+ $contact_name,$contact_email);
}
- } else {
- $output = &invalid_state('missing',$domdesc,
- $contact_name,$contact_email);
}
- }
- } elsif ($authtype =~ /^(krb|unix|local)/) {
- $output = &invalid_state('authentication',$domdesc,
- $contact_name,$contact_email);
- } else {
- $output = &invalid_state('invalid',$domdesc,
+ } elsif ($authtype =~ /^(krb|unix|local)/) {
+ $output = &invalid_state('authentication',$domdesc,
$contact_name,$contact_email);
+ } else {
+ $output = &invalid_state('invalid',$domdesc,
+ $contact_name,$contact_email);
+ }
}
} else {
- $output = &get_uname($defdom);
+ $output = &get_uname($server,$dom_in_effect,\%passwdconf);
}
} else {
- $output = &get_uname($defdom);
+ $output = &get_uname($server,$defdom,\%passwdconf);
}
$r->print($header.$output);
$r->print(&Apache::loncommon::end_page());
@@ -278,44 +423,58 @@
}
sub get_uname {
- my ($defdom) = @_;
+ my ($server,$defdom,$passwdconf) = @_;
+ return unless (ref($passwdconf) eq 'HASH');
my %lt = &Apache::lonlocal::texthash(
- unam => 'LON-CAPA username',
- udom => 'LON-CAPA domain',
- uemail => 'E-mail address in LON-CAPA',
- proc => 'Proceed');
-
- my $msg = &mt('If you use the same account for other campus services besides LON-CAPA, (e.g., e-mail, course registration, etc.), a separate centrally managed mechanism likely exists to reset a password. However, if your account is used for just LON-CAPA access you will probably be able to reset a password from this page.');
- $msg .= '<br /><br />'.&mt('Three conditions must be met:')
+ unam => 'LON-CAPA username',
+ udom => 'LON-CAPA domain',
+ uemail => 'E-mail address in LON-CAPA',
+ vali => 'Validation',
+ proc => 'Proceed');
+ my $msg;
+ unless ($passwdconf->{'resetremove'}) {
+ $msg = '<p>'.&mt('If you use the same account for other campus services besides LON-CAPA, (e.g., e-mail, course registration, etc.), a separate centrally managed mechanism likely exists to reset a password. However, if your account is used for just LON-CAPA access you will probably be able to reset a password from this page.').'</p>';
+ }
+ if ($passwdconf->{'resetcustom'} eq "/res/$defdom/$defdom-domainconfig/customtext/resetpw/resetpw.html") {
+ my $contents = &Apache::lonnet::getfile(&Apache::lonnet::filelocation('',$passwdconf->{'resetcustom'}));
+ unless ($contents eq '-1') {
+ $msg .= $contents;
+ }
+ }
+ $msg .= '<p>'.&mt('Three conditions must be met:')
.'<ul><li>'.&mt('An e-mail address must have previously been associated with your LON-CAPA username.').'</li>'
.'<li>'.&mt('You must be able to access e-mail sent to that address.').'</li>'
.'<li>'.&mt('Your LON-CAPA account must be of a type for which LON-CAPA can reset a password.')
- .'</ul>';
- my $mobileargs;
- (undef,undef,undef,undef,undef,undef,my $clientmobile) =
- &Apache::loncommon::decode_user_agent();
- if ($clientmobile) {
- $mobileargs = 'autocapitalize="off" autocorrect="off" ';
- }
+ .'</ul></p>';
my $onchange = 'javascript:verifyDomain(this,this.form);';
$msg .= '<form name="forgotpw" method="post" action="/adm/resetpw" onsubmit="return validInfo();">'.
- &Apache::lonhtmlcommon::start_pick_box().
- &Apache::lonhtmlcommon::row_title($lt{'unam'}).
- '<input type="text" name="uname" size="20" '.$mobileargs.'/>'.
- &Apache::lonhtmlcommon::row_closure(1).
+ &Apache::lonhtmlcommon::start_pick_box().
&Apache::lonhtmlcommon::row_title($lt{'udom'}).
&Apache::loncommon::select_dom_form($defdom,'udom',undef,undef,$onchange).
&Apache::lonhtmlcommon::row_closure(1).
+ &Apache::lonhtmlcommon::row_title($lt{'unam'}).
+ '<input type="text" name="uname" size="20" autocapitalize="off" autocorrect="off" />'.
+ &Apache::lonhtmlcommon::row_closure(1).
&Apache::lonhtmlcommon::row_title($lt{'uemail'}).
- '<input type="text" name="useremail" size="30" '.$mobileargs.'/>'.
- &Apache::lonhtmlcommon::end_pick_box().
+ '<input type="text" name="useremail" size="30" autocapitalize="off" autocorrect="off" />'.
+ &Apache::lonhtmlcommon::row_closure(1);
+ unless ($passwdconf->{'captcha'} eq 'notused') {
+ my ($captcha_form,$captcha_error,$captcha,$recaptcha_version) =
+ &Apache::loncommon::captcha_display('passwords',$server,$defdom);
+ if ($captcha_form) {
+ $msg .= &Apache::lonhtmlcommon::row_title($lt{'vali'}).
+ $captcha_form."\n".
+ &Apache::lonhtmlcommon::row_closure(1);
+ }
+ }
+ $msg .= &Apache::lonhtmlcommon::end_pick_box().
'<br /><br /><input type="submit" name="resetter" value="'.$lt{'proc'}.'" /></form>';
return $msg;
}
sub send_token {
my ($uname,$udom,$email,$server,$domdesc,$contact_name,
- $contact_email) = @_;
+ $contact_email,$timelimit,$warning) = @_;
my $msg =
'<p class="LC_info">'
.&mt('Thank you for your request to reset the password for your LON-CAPA account.')
@@ -342,7 +501,7 @@
$msg .=
&mt('An e-mail sent to the e-mail address associated with your LON-CAPA account includes the web address for the link you should use to complete the reset process.')
.'<br /><br />'
- .&mt('The link included in the message will be valid for the next [_1]two[_2] hours.','<b>','</b>');
+ .&mt('The link included in the message will be valid for the next [_1][quant,_2,hour][_3].','<b>',$timelimit,'</b>');
} else {
$msg .=
'<p class="LC_error">'
@@ -393,7 +552,15 @@
.'</p>';
$msg .= &display_actions($contact_email,$domdesc);
} else {
- if ($error eq 'baduseremail') {
+ if ($error eq 'captcha') {
+ $msg = &mt('Validation of the code you entered failed');
+ } elsif ($error eq 'recaptcha') {
+ $msg = &mt('Validation of human, not robot, failed');
+ } elsif ($error eq 'nonunique') {
+ $msg = &mt('More than one username was identified from the information you provided; try providing both a username and e-mail address');
+ } elsif ($error eq 'nomatch') {
+ $msg = &mt('A valid user could not be identified from the username and/or e-mail address you provided');
+ } elsif ($error eq 'baduseremail') {
$msg = &mt('The e-mail address you provided does not appear to be a valid address.');
} elsif ($error eq 'mismatch') {
$msg = &mt('The e-mail address you provided does not match the address recorded in the LON-CAPA system for the username and domain you provided.');
@@ -434,7 +601,8 @@
}
sub reset_passwd {
- my ($r,$token,$contact_name,$contact_email) = @_;
+ my ($r,$token,$contact_name,$contact_email,$passwdconf) = @_;
+ return unless (ref($passwdconf) eq 'HASH');
my %data = &Apache::lonnet::tmpget($token);
my $now = time;
if (keys(%data) == 0) {
@@ -448,23 +616,59 @@
($data{'domain'} ne '') &&
($data{'email'} =~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) &&
($data{'temppasswd'} =~/^\w+$/)) {
+ my $timelimit = 7200;
+ if ($passwdconf->{resetlink} =~ /^\d+(|\.\d*)$/) {
+ $timelimit = 3600 * $passwdconf->{resetlink};
+ }
my $reqtime = &Apache::lonlocal::locallocaltime($data{'time'});
my ($blocked,$blocktext) =
&Apache::loncommon::blocking_status('passwd',$data{'username'},$data{'domain'});
if ($blocked) {
$r->print('<p class="LC_warning">'.$blocktext.'</p>');
return;
- } elsif ($now - $data{'time'} < 7200) {
+ } elsif ($now - $data{'time'} < $timelimit) {
+ my ($needscase,%formfields) = &reset_requires($data{'username'},$data{'domain'},
+ $passwdconf);
if ($env{'form.action'} eq 'verify_and_change_pass') {
- $env{'form.uname'} =~ s/^\s+|\s+$//g;
- $env{'form.udom'} =~ s/^\s+|\s+$//g;
- $env{'form.email'} =~ s/^\s+|\s+$//g;
- unless (($env{'form.uname'} eq $data{'username'}) && ($env{'form.udom'} eq $data{'domain'}) && ($env{'form.email'} eq $data{'email'})) {
- &Apache::lonnet::logthis("Forgot Password -- token data: ||$data{'username'}|| ||$data{'domain'}|| ||$data{'email'}|| differs from form: ||$env{'form.uname'}|| ||$env{'form.udom'}|| ||$env{'form.email'}||");
+ my $invalidinfo;
+ if ($formfields{'username'}) {
+ $env{'form.uname'} =~ s/^\s+|\s+$//g;
+ $env{'form.udom'} =~ s/^\s+|\s+$//g;
+ if ($needscase) {
+ unless (($env{'form.uname'} eq $data{'username'}) && ($env{'form.udom'} eq $data{'domain'})) {
+ $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'}))) {
+ $invalidinfo = "||$env{'form.uname'}|| ||$env{'form.udom'}|| ";
+ }
+ }
+ } else {
+ $env{'form.uname'} = $data{'username'};
+ $env{'form.udom'} = $data{'domain'};
+ }
+ if ($formfields{'email'}) {
+ $env{'form.email'} =~ s/^\s+|\s+$//g;
+ if ($needscase) {
+ unless ($env{'form.email'} eq $data{'email'}) {
+ $invalidinfo .= "||$env{'form.email'}||";
+ }
+ } else {
+ unless (lc($env{'form.email'}) eq lc($data{'email'})) {
+ $invalidinfo = "||$env{'form.email'}||";
+ }
+ }
+ }
+ 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));
+ unless ($formfields{'username'}) {
+ delete($env{'form.uname'});
+ delete($env{'form.udom'});
+ }
return;
}
- my $change_failed =
+ my $change_failed =
&Apache::lonpreferences::verify_and_change_password($r,'reset_by_email',$token);
if (!$change_failed) {
my $delete = &Apache::lonnet::tmpdel($token);
@@ -519,10 +723,46 @@
} else {
$r->print(&generic_failure_msg($contact_name,$contact_email));
}
+ unless ($formfields{'username'}) {
+ delete($env{'form.uname'});
+ delete($env{'form.udom'});
+ }
} else {
$r->print(&mt('The token included in an e-mail sent to you [_1] has been verified, so you may now proceed to reset the password for your LON-CAPA account.',$reqtime).'<br /><br />');
- $r->print(&mt('Please enter the username and domain of the LON-CAPA account, and the associated e-mail address, for which you are setting a password. The new password must contain at least 7 characters.').' '.&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);
+ if (keys(%formfields)) {
+ if (($formfields{'username'}) && ($formfields{'email'})) {
+ $r->print(&mt('Please enter the username and domain of the LON-CAPA account, and the associated e-mail address, for which you are setting a password.'));
+ } elsif ($formfields{'username'}) {
+ $r->print(&mt('Please enter the username and domain of the LON-CAPA account for which you are setting a password.'));
+ } elsif ($formfields{'email'}) {
+ $r->print(&mt('Please enter the e-mail address associated with the LON-CAPA account for which you are setting a password.'));
+ }
+ if ($needscase) {
+ $r->print(' '.&mt('User data entered must match LON-CAPA account information (including case).'));
+ }
+ $r->print(' ');
+ }
+ if (ref($passwdconf->{chars}) eq 'ARRAY') {
+ my %rules;
+ map { $rules{$_} = 1; } @{$passwdconf->{chars}};
+ my %rulenames = &Apache::lonlocal::texthash(
+ uc => 'At least one upper case letter',
+ lc => 'At least one lower case letter',
+ num => 'At least one number',
+ spec => 'At least one non-alphanumeric',
+ );
+ $r->print(&mt('The new password must satisfy the following:').'<ul>');
+ foreach my $poss ('uc','lc','num','spec') {
+ if ($rules{$poss}) {
+ $r->print('<li>'.$rulenames{$poss}.'</li>');
+ }
+ }
+ $r->print('</ul>');
+ } else {
+ $r->print(&mt('The new password must contain at least 7 characters.').' ');
+ }
+ $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);
}
} else {
$r->print(
@@ -593,9 +833,41 @@
'<i>'.$domdesc.'</i>')
.'</p>';
}
-
return &Apache::lonhtmlcommon::actionbox(\@msg).$msg2;
+}
+sub reset_requires {
+ my ($username,$domain,$passwdconf) = @_;
+ my (%fields,$needscase);
+ return ($needscase,%fields) unless (ref($passwdconf) eq 'HASH');
+ my (%postlink,%resetcase);
+ if (ref($passwdconf->{resetpostlink}) eq 'HASH') {
+ %postlink = %{$passwdconf->{resetpostlink}};
+ }
+ if (ref($passwdconf->{resetcase}) eq 'ARRAY') {
+ map { $resetcase{$_} = 1; } (@{$passwdconf->{resetcase}});
+ } else {
+ $needscase = 1;
+ }
+ my %userenv =
+ &Apache::lonnet::get('environment',['inststatus'],$domain,$username);
+ my @inststatuses;
+ if ($userenv{'inststatus'} ne '') {
+ @inststatuses = split(/:/,$userenv{'inststatus'});
+ } else {
+ @inststatuses = ('default');
+ }
+ foreach my $status (@inststatuses) {
+ if (ref($postlink{$status}) eq 'ARRAY') {
+ map { $fields{$_} = 1; } (@{$postlink{$status}});
+ } else {
+ map { $fields{$_} = 1; } ('username','email');
+ }
+ if ($resetcase{$status}) {
+ $needscase = 1;
+ }
+ }
+ return ($needscase,%fields);
}
1;
Index: loncom/interface/lonpreferences.pm
diff -u loncom/interface/lonpreferences.pm:1.227 loncom/interface/lonpreferences.pm:1.228
--- loncom/interface/lonpreferences.pm:1.227 Fri Apr 27 22:42:20 2018
+++ loncom/interface/lonpreferences.pm Wed Apr 24 01:44:30 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Preferences
#
-# $Id: lonpreferences.pm,v 1.227 2018/04/27 22:42:20 raeburn Exp $
+# $Id: lonpreferences.pm,v 1.228 2019/04/24 01:44:30 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1263,7 +1263,7 @@
# password handler subroutines #
######################################################
sub passwordchanger {
- my ($r,$errormessage,$caller,$mailtoken) = @_;
+ my ($r,$errormessage,$caller,$mailtoken,$timelimit,$extrafields) = @_;
# This function is a bit of a mess....
# Passwords are encrypted using londes.js (DES encryption)
$errormessage = ($errormessage || '');
@@ -1299,7 +1299,7 @@
return;
}
if (defined($data{time})) {
- if (time - $data{'time'} < 7200) {
+ if (time - $data{'time'} < $timelimit) {
$user = $data{'username'};
$domain = $data{'domain'};
$currentpass = $data{'temppasswd'};
@@ -1362,7 +1362,7 @@
my $jsh=Apache::File->new($include."/londes.js");
$r->print(<$jsh>);
}
- $r->print(&jscript_send($caller));
+ $r->print(&jscript_send($caller,$extrafields));
$r->print(<<ENDFORM);
$errormessage
@@ -1371,15 +1371,15 @@
ensure that unencrypted passwords will not be sent out by a
crappy browser -->
ENDFORM
- $r->print(&server_form($logtoken,$caller,$mailtoken));
- $r->print(&client_form($caller,\%hexkey,$currentpass,$domain));
+ $r->print(&server_form($logtoken,$caller,$mailtoken,$extrafields));
+ $r->print(&client_form($caller,\%hexkey,$currentpass,$domain,$extrafields));
#
return;
}
sub jscript_send {
- my ($caller) = @_;
+ my ($caller,$extrafields) = @_;
my $output = qq|
<script type="text/javascript" language="JavaScript">
@@ -1401,14 +1401,20 @@
=getCrypted(this.document.client.elements.newpass_2.value);
|;
if ($caller eq 'reset_by_email') {
- $output .= qq|
+ if ((ref($extrafields) eq 'HASH') && ($extrafields->{'username'})) {
+ $output .= qq|
this.document.pserver.elements.uname.value =
this.document.client.elements.uname.value;
this.document.pserver.elements.udom.value =
this.document.client.elements.udom.options[this.document.client.elements.udom.selectedIndex].value;
+|;
+ }
+ if ((ref($extrafields) eq 'HASH') && ($extrafields->{'email'})) {
+ $output .= qq|
this.document.pserver.elements.email.value =
this.document.client.elements.email.value;
|;
+ }
}
$ output .= qq|
this.document.pserver.submit();
@@ -1419,7 +1425,7 @@
}
sub client_form {
- my ($caller,$hexkey,$currentpass,$defdom) = @_;
+ my ($caller,$hexkey,$currentpass,$defdom,$extrafields) = @_;
my %lt=&Apache::lonlocal::texthash(
'email' => 'E-mail Address',
'username' => 'Username',
@@ -1433,25 +1439,22 @@
my $output = '<form name="client" action="">'
.&Apache::lonhtmlcommon::start_pick_box();
if ($caller eq 'reset_by_email') {
- my $mobileargs;
- (undef,undef,undef,undef,undef,undef,my $clientmobile) =
- &Apache::loncommon::decode_user_agent();
- if ($clientmobile) {
- $mobileargs = 'autocapitalize="off" autocorrect="off" ';
- }
- $output .= &Apache::lonhtmlcommon::row_title(
+ if ((ref($extrafields) eq 'HASH') && ($extrafields->{'email'})) {
+ $output .= &Apache::lonhtmlcommon::row_title(
'<label for="email">'.$lt{'email'}.'</label>')
- .'<input type="text" name="email" size="30" '.$mobileargs.'/>'
- .&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title(
+ .'<input type="text" name="email" size="30" autocapitalize="off" autocorrect="off" />'
+ .&Apache::lonhtmlcommon::row_closure();
+ }
+ if ((ref($extrafields) eq 'HASH') && ($extrafields->{'username'})) {
+ $output .= &Apache::lonhtmlcommon::row_title(
'<label for="uname">'.$lt{'username'}.'</label>')
- .'<input type="text" name="uname" size="20" '.$mobileargs.'/>'
- .'<input type="hidden" name="currentpass" value="'.$currentpass.'" />'
- .&Apache::lonhtmlcommon::row_closure()
- .&Apache::lonhtmlcommon::row_title(
+ .'<input type="text" name="uname" size="20" autocapitalize="off" autocorrect="off" />'
+ .&Apache::lonhtmlcommon::row_closure()
+ .&Apache::lonhtmlcommon::row_title(
'<label for="udom">'.$lt{'domain'}.'</label>')
- .&Apache::loncommon::select_dom_form($defdom,'udom')
- .&Apache::lonhtmlcommon::row_closure();
+ .&Apache::loncommon::select_dom_form($defdom,'udom')
+ .&Apache::lonhtmlcommon::row_closure();
+ }
} else {
$output .= &Apache::lonhtmlcommon::row_title(
'<label for="currentpass">'.$lt{'currentpass'}.'</label>')
@@ -1467,6 +1470,9 @@
.'<input type="password" name="newpass_2" size="20" />'
.&Apache::lonhtmlcommon::row_closure(1)
.&Apache::lonhtmlcommon::end_pick_box();
+ if ($caller eq 'reset_by_email') {
+ $output .= '<input type="hidden" name="currentpass" value="'.$currentpass.'" />';
+ }
$output .= '<p><input type="button" value="'.$lt{'changepass'}.'" onclick="send();" /></p>'
.qq|
<input type="hidden" name="ukey_cpass" value="$hexkey->{'ukey_cpass'}" />
@@ -1482,7 +1488,7 @@
}
sub server_form {
- my ($logtoken,$caller,$mailtoken) = @_;
+ my ($logtoken,$caller,$mailtoken,$extrafields) = @_;
my $action = '/adm/preferences';
if ($caller eq 'reset_by_email') {
$action = '/adm/resetpw';
@@ -1493,15 +1499,22 @@
<input type="hidden" name="currentpass" value="" />
<input type="hidden" name="newpass_1" value="" />
<input type="hidden" name="newpass_2" value="" />
- |;
+|;
if ($caller eq 'reset_by_email') {
$output .= qq|
<input type="hidden" name="token" value="$mailtoken" />
+|;
+ if ((ref($extrafields) eq 'HASH') && ($extrafields->{'username'})) {
+ $output .= qq|
<input type="hidden" name="uname" value="" />
<input type="hidden" name="udom" value="" />
+|;
+ }
+ if ((ref($extrafields) eq 'HASH') && ($extrafields->{'email'})) {
+ $output .= qq|
<input type="hidden" name="email" value="" />
-
|;
+ }
}
$output .= qq|
<input type="hidden" name="action" value="verify_and_change_pass" />
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1326 loncom/interface/loncommon.pm:1.1327
--- loncom/interface/loncommon.pm:1.1326 Thu Apr 11 14:47:14 2019
+++ loncom/interface/loncommon.pm Wed Apr 24 01:44:30 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1326 2019/04/11 14:47:14 raeburn Exp $
+# $Id: loncommon.pm,v 1.1327 2019/04/24 01:44:30 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -17710,10 +17710,10 @@
}
sub captcha_display {
- my ($context,$lonhost) = @_;
+ my ($context,$lonhost,$defdom) = @_;
my ($output,$error);
my ($captcha,$pubkey,$privkey,$version) =
- &get_captcha_config($context,$lonhost);
+ &get_captcha_config($context,$lonhost,$defdom);
if ($captcha eq 'original') {
$output = &create_captcha();
unless ($output) {
@@ -17729,9 +17729,9 @@
}
sub captcha_response {
- my ($context,$lonhost) = @_;
+ my ($context,$lonhost,$defdom) = @_;
my ($captcha_chk,$captcha_error);
- my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost);
+ my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost,$defdom);
if ($captcha eq 'original') {
($captcha_chk,$captcha_error) = &check_captcha();
} elsif ($captcha eq 'recaptcha') {
@@ -17743,7 +17743,7 @@
}
sub get_captcha_config {
- my ($context,$lonhost) = @_;
+ my ($context,$lonhost,$dom_in_effect) = @_;
my ($captcha,$pubkey,$privkey,$version,$hashtocheck);
my $hostname = &Apache::lonnet::hostname($lonhost);
my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
@@ -17791,7 +17791,28 @@
} elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
$captcha = 'original';
}
- }
+ } elsif ($context eq 'passwords') {
+ if ($dom_in_effect) {
+ my %passwdconf = &Apache::lonnet::get_passwdconf($dom_in_effect);
+ if ($passwdconf{'captcha'} eq 'recaptcha') {
+ if (ref($passwdconf{'recaptchakeys'}) eq 'HASH') {
+ $pubkey = $passwdconf{'recaptchakeys'}{'public'};
+ $privkey = $passwdconf{'recaptchakeys'}{'private'};
+ }
+ if ($privkey && $pubkey) {
+ $captcha = 'recaptcha';
+ $version = $passwdconf{'recaptchaversion'};
+ if ($version ne '2') {
+ $version = 1;
+ }
+ } else {
+ $captcha = 'original';
+ }
+ } elsif ($passwdconf{'captcha'} ne 'notused') {
+ $captcha = 'original';
+ }
+ }
+ }
return ($captcha,$pubkey,$privkey,$version);
}
Index: loncom/lonsql
diff -u loncom/lonsql:1.97 loncom/lonsql:1.98
--- loncom/lonsql:1.97 Mon Oct 29 02:57:30 2018
+++ loncom/lonsql Wed Apr 24 01:44:38 2019
@@ -3,7 +3,7 @@
# The LearningOnline Network
# lonsql - LON TCP-MySQL-Server Daemon for handling database requests.
#
-# $Id: lonsql,v 1.97 2018/10/29 02:57:30 raeburn Exp $
+# $Id: lonsql,v 1.98 2019/04/24 01:44:38 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -540,6 +540,7 @@
}
} else {
my %srchfield = (
+ uname_ci => 'username collate latin1_general_ci',
uname => 'username',
lastname => 'lastname',
email => 'permanentemail',
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1406 loncom/lonnet/perl/lonnet.pm:1.1407
--- loncom/lonnet/perl/lonnet.pm:1.1406 Tue Feb 26 14:42:27 2019
+++ loncom/lonnet/perl/lonnet.pm Wed Apr 24 01:44:46 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1406 2019/02/26 14:42:27 raeburn Exp $
+# $Id: lonnet.pm,v 1.1407 2019/04/24 01:44:46 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -2721,6 +2721,29 @@
return $firsturl;
}
+# --------------------------------------------- Get domain config for passwords
+
+sub get_passwdconf {
+ my ($dom) = @_;
+ my (%passwdconf,$gotconf,$lookup);
+ my ($result,$cached)=&is_cached_new('passwdconf',$dom);
+ if (defined($cached)) {
+ if (ref($result) eq 'HASH') {
+ %passwdconf = %{$result};
+ $gotconf = 1;
+ }
+ }
+ unless ($gotconf) {
+ my %domconfig = &get_dom('configuration',['passwords'],$dom);
+ if (ref($domconfig{'passwords'}) eq 'HASH') {
+ %passwdconf = %{$domconfig{'passwords'}};
+ }
+ my $cachetime = 24*60*60;
+ &do_cache_new('passwdconf',$dom,\%passwdconf,$cachetime);
+ }
+ return %passwdconf;
+}
+
# --------------------------------------------------- Assign a key to a student
sub assign_access_key {
More information about the LON-CAPA-cvs
mailing list