--- loncom/interface/resetpw.pm 2019/04/24 01:44:30 1.44 +++ loncom/interface/resetpw.pm 2021/11/30 15:55:37 1.50 @@ -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.44 2019/04/24 01:44:30 raeburn Exp $ +# $Id: resetpw.pm,v 1.50 2021/11/30 15:55:37 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -115,6 +115,7 @@ sub handler { } } my %passwdconf = &Apache::lonnet::get_passwdconf($dom_in_effect); + my $clientip = &Apache::lonnet::get_requestor_ip($r); my $token = $env{'form.token'}; my $useremail = $env{'form.useremail'}; if (($udom ne '') && (!$otherinst) && (!$token)) { @@ -292,7 +293,7 @@ END my $output; if ($token) { $r->print($header); - &reset_passwd($r,$token,$contact_name,$contact_email,\%passwdconf); + &reset_passwd($r,$token,$contact_name,$contact_email,$clientip,\%passwdconf); $r->print(&Apache::loncommon::end_page()); return OK; } elsif ($udom) { @@ -300,12 +301,12 @@ END $output = &invalid_state('baddomain',$domdesc, $contact_name,$contact_email); } elsif ($otherinst) { - ($header,$output) = &homeserver_redirect($uname,$udom,$domdesc,$brcrum); + ($header,$output) = &homeserver_redirect($r,$uname,$udom,$domdesc,$brcrum); } elsif (($uname) || ($useremail)) { my $earlyout; unless ($passwdconf{'captcha'} eq 'unused') { my ($captcha_chk,$captcha_error) = - &Apache::loncommon::captcha_response('passwords',$server); + &Apache::loncommon::captcha_response('passwords',$server,$dom_in_effect); if ($captcha_chk != 1) { my $error = 'captcha'; if ($passwdconf{'captcha'} eq 'recaptcha') { @@ -327,7 +328,7 @@ END my $authtype = &Apache::lonnet::queryauthenticate($uname,$udom); if ($authtype =~ /^internal/) { my ($blocked,$blocktext) = - &Apache::loncommon::blocking_status('passwd',$uname,$udom); + &Apache::loncommon::blocking_status('passwd',$clentip,$uname,$udom); if ($blocked) { $output = '

'.$blocktext.'

' .&display_actions($contact_email,$domdesc); @@ -359,7 +360,7 @@ END } foreach my $item (@items) { if ($item =~ /^[^\@]+\@[^\@]+\.[^\@\.]+$/) { - unless (grep(/^\Q$item\E$/i,@allemails)) { + unless (grep(/^\Q$item\E$/i,@allemails)) { push(@allemails,$item); } } @@ -482,7 +483,8 @@ sub send_token { my $now = time; my $temppasswd = &create_passwd(); - my %info = ('ip' => $ENV{'REMOTE_ADDR'}, + my $ip = &Apache::lonnet::get_requestor_ip(); + my %info = ('ip' => $ip, 'time' => $now, 'domain' => $udom, 'username' => $uname, @@ -578,7 +580,7 @@ sub invalid_state { } sub homeserver_redirect { - my ($uname,$udom,$domdesc,$brcrum) = @_; + my ($r,$uname,$udom,$domdesc,$brcrum) = @_; my $uhome; if (($uname ne '') && ($udom ne '')) { $uhome = &Apache::lonnet::homeserver($uname,$udom); @@ -589,6 +591,8 @@ sub homeserver_redirect { my $hostname = &Apache::lonnet::hostname($uhome); my $protocol = $Apache::lonnet::protocol{$uhome}; $protocol = 'http' if ($protocol ne 'https'); + my $alias = &Apache::lonnet::use_proxy_alias($r,$uhome); + $hostname = $alias if ($alias ne ''); my $url = $protocol.'://'.$hostname.'/adm/resetpw'; # Breadcrumbs my $start_page = &Apache::loncommon::start_page('Switching Server',undef, @@ -601,7 +605,7 @@ sub homeserver_redirect { } sub reset_passwd { - my ($r,$token,$contact_name,$contact_email,$passwdconf) = @_; + my ($r,$token,$contact_name,$contact_email,$clientip,$passwdconf) = @_; return unless (ref($passwdconf) eq 'HASH'); my %data = &Apache::lonnet::tmpget($token); my $now = time; @@ -622,7 +626,7 @@ sub reset_passwd { } my $reqtime = &Apache::lonlocal::locallocaltime($data{'time'}); my ($blocked,$blocktext) = - &Apache::loncommon::blocking_status('passwd',$data{'username'},$data{'domain'}); + &Apache::loncommon::blocking_status('passwd',$clientip,$data{'username'},$data{'domain'}); if ($blocked) { $r->print('

'.$blocktext.'

'); return; @@ -639,7 +643,9 @@ sub reset_passwd { $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 +667,53 @@ sub reset_passwd { } 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( + '

' + .&mt('A problem occurred when attempting to reset' + .' the password for your account.').'

'); + if (($formfields{'username'}) && ($formfields{'email'})) { + if ($needscase) { + $r->print('

' + .&mt('Please verify you entered the correct username and e-mail address, ' + .'including the correct lower and/or upper case letters') + .'

'); + } else { + $r->print('

' + .&mt('Please verify you entered the correct username and e-mail address.') + .'

'); + } + $retry = 1; + } elsif ($formfields{'username'}) { + if ($needscase) { + $r->print('

' + .&mt('Please verify you entered the correct username, ' + .'including the correct lower and/or upper case letters') + .'

'); + } else { + $r->print('

' + .&mt('Please verify you entered the correct username.') + .'

'); + } + $retry = 1; + } elsif ($formfields{'email'}) { + if ($needscase) { + $r->print('

' + .&mt('Please verify you entered the correct e-mail address, ' + .'including the correct lower and/or upper case letters') + .'

'); + } else { + $r->print('

' + .&mt('Please verify you entered the correct e-mail address.') + .'

'); + } + $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,13 +721,14 @@ sub reset_passwd { 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); my $domdesc = &Apache::lonnet::domain($data{'domain'},'description'); - my $mailmsg = &mt('The password for your LON-CAPA account in the [_1] domain was changed [_2] from IP address: [_3]. If you did not perform this change or authorize it, please contact the [_4] ([_5]).',$domdesc,$now,$ENV{'REMOTE_ADDR'},$contact_name,$contact_email)."\n"; + my $ip = &Apache::lonnet::get_requestor_ip(); + my $mailmsg = &mt('The password for your LON-CAPA account in the [_1] domain was changed [_2] from IP address: [_3]. If you did not perform this change or authorize it, please contact the [_4] ([_5]).',$domdesc,$now,$ip,$contact_name,$contact_email)."\n"; my $result = &send_mail($domdesc,$data{'email'},$mailmsg, $contact_name,$contact_email); my $confirm_msg; @@ -705,6 +758,8 @@ sub reset_passwd { my $hostname = &Apache::lonnet::hostname($homeserver); my $protocol = $Apache::lonnet::protocol{$homeserver}; $protocol = 'http' if ($protocol ne 'https'); + my $alias = &Apache::lonnet::use_proxy_alias($r,$homeserver); + $hostname = $alias if ($alias ne ''); my $url = $protocol.'://'.$hostname.'/adm/resetpw'; my ($opentag,$closetag); if ($url) { @@ -720,7 +775,17 @@ sub reset_passwd { .'

' ); } - } else { + } elsif (($change_failed eq 'prioruse') && ($passwdconf->{'numsaved'})) { + my $domdesc = + &Apache::lonnet::domain($data{'domain'},'description'); + $r->print( + '

' + .&mt('Please enter a password that you have not used recently.') + .'

' + .&display_actions($contact_email,$domdesc,$token) + ); + } 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'}) { @@ -728,6 +793,7 @@ sub reset_passwd { delete($env{'form.udom'}); } } else { +#FIXME $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).'

'); if (keys(%formfields)) { if (($formfields{'username'}) && ($formfields{'email'})) { @@ -740,7 +806,20 @@ sub reset_passwd { if ($needscase) { $r->print(' '.&mt('User data entered must match LON-CAPA account information (including case).')); } - $r->print(' '); + $r->print('
'); + } + 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; @@ -757,9 +836,24 @@ sub reset_passwd { $r->print('
  • '.$rulenames{$poss}.'
  • '); } } + if ($min) { + $r->print('
  • '.$minrule.'
  • '); + } + if ($max) { + $r->print('
  • '.$maxrule.'
  • '); + } $r->print(''); } 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:').''."\n"); + } elsif ($min) { + $r->print($minrule.'
    '); + } elsif ($max) { + $r->print($maxrule.'
    '); + } } $r->print(&mt('Your new password will be sent to the LON-CAPA server in an encrypted form.').'
    '); &Apache::lonpreferences::passwordchanger($r,'','reset_by_email',$token,$timelimit,\%formfields); @@ -767,7 +861,8 @@ sub reset_passwd { } else { $r->print( '

    ' - .&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.').'
    ' + .&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.' ,'','') .'

    ' ); @@ -815,9 +910,13 @@ sub create_passwd { } sub display_actions { - my ($contact_email, $domdesc) = @_; + my ($contact_email,$domdesc,$token) = @_; + my $url = '/adm/resetpw'; + if ($token) { + $url .= '?token='.&escape($token); + } my @msg = (&mt('[_1]Go back[_2] and try again', - '','')); + '','')); my $msg2 = ''; if ($contact_email ne '') { my $escuri = &HTML::Entities::encode('/adm/resetpw','&<>"');