[LON-CAPA-cvs] cvs: loncom /interface domainprefs.pm
raeburn
raeburn at source.lon-capa.org
Sun Apr 21 21:55:17 EDT 2019
raeburn Mon Apr 22 01:55:17 2019 EDT
Modified files:
/loncom/interface domainprefs.pm
Log:
- Domain Configuration for Passwords for internally authenticated users.
- Options for "Forgot Password" utility: link lifetime, case sensitivity,
information required, e-mail types, custom text.
- Options for encryption of Stored Passwords (moved from "Defaults" menu).
- Rules for LON-CAPA Passwords (length, characters, expiration).
- Option to allow Course Owner to change student's password (with conditions).
-------------- next part --------------
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.353 loncom/interface/domainprefs.pm:1.354
--- loncom/interface/domainprefs.pm:1.353 Mon Apr 22 00:38:45 2019
+++ loncom/interface/domainprefs.pm Mon Apr 22 01:55:17 2019
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: domainprefs.pm,v 1.353 2019/04/22 00:38:45 raeburn Exp $
+# $Id: domainprefs.pm,v 1.354 2019/04/22 01:55:17 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -219,7 +219,7 @@
'serverstatuses','requestcourses','helpsettings',
'coursedefaults','usersessions','loadbalancing',
'requestauthor','selfenrollment','inststatus',
- 'ltitools','ssl','trust','lti'],$dom);
+ 'ltitools','ssl','trust','lti','passwords'],$dom);
my %encconfig =
&Apache::lonnet::get_dom('encconfig',['ltitools','lti'],$dom);
if (ref($domconfig{'ltitools'}) eq 'HASH') {
@@ -246,7 +246,7 @@
}
}
}
- my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',
+ my @prefs_order = ('rolecolors','login','defaults','passwords','quotas','autoenroll',
'autoupdate','autocreate','directorysrch','contacts',
'usercreation','selfcreation','usermodification','scantron',
'requestcourses','requestauthor','coursecategories',
@@ -291,13 +291,25 @@
help => 'Domain_Configuration_LangTZAuth',
header => [{col1 => 'Setting',
col2 => 'Value'},
- {col1 => 'Internal Authentication',
- col2 => 'Value'},
{col1 => 'Institutional user types',
col2 => 'Name displayed'}],
print => \&print_defaults,
modify => \&modify_defaults,
},
+ 'passwords' =>
+ { text => 'Passwords (Internal authentication)',
+ help => 'Domain_Configuration_Passwords',
+ header => [{col1 => 'Resetting Forgotten Password',
+ col2 => 'Settings'},
+ {col1 => 'Encryption of Stored Passwords (Internal Auth)',
+ col2 => 'Settings'},
+ {col1 => 'Rules for LON-CAPA Passwords',
+ col2 => 'Settings'},
+ {col1 => 'Course Owner Changing Student Passwords',
+ col2 => 'Settings'}],
+ print => \&print_passwords,
+ modify => \&modify_passwords,
+ },
'quotas' =>
{ text => 'Blogs, personal web pages, webDAV/quotas, portfolios',
help => 'Domain_Configuration_Quotas',
@@ -759,6 +771,8 @@
$output = &modify_trust($dom,$lastactref,%domconfig);
} elsif ($action eq 'lti') {
$output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
+ } elsif ($action eq 'passwords') {
+ $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
}
return $output;
}
@@ -771,6 +785,8 @@
$output = &coursecategories_javascript($settings);
} elsif ($action eq 'defaults') {
$output = &defaults_javascript($settings);
+ } elsif ($action eq 'passwords') {
+ $output = &passwords_javascript();
} elsif ($action eq 'helpsettings') {
my (%privs,%levelscurrent);
my %full=();
@@ -830,6 +846,8 @@
($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
($action eq 'contacts')) {
$output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
+ } elsif ($action eq 'passwords') {
+ $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'coursecategories') {
$output .= $item->{'print'}->('top',$dom,$item,$settings,\$rowtotal);
} elsif ($action eq 'scantron') {
@@ -861,12 +879,14 @@
if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
($action eq 'usersessions') || ($action eq 'coursecategories') ||
- ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults')) {
+ ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'passwords')) {
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
$colspan = ' colspan="2"';
} elsif ($action eq 'trust') {
$output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
+ } elsif ($action eq 'passwords') {
+ $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);
} else {
$output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
}
@@ -912,8 +932,13 @@
</tr>'."\n";
if ($action eq 'coursecategories') {
$output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
- } elsif ($action eq 'contacts') {
- $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal).'
+ } elsif (($action eq 'contacts') || ($action eq 'passwords')) {
+ if ($action eq 'passwords') {
+ $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);
+ } else {
+ $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);
+ }
+ $output .= '
</tr>
</table>
</td>
@@ -923,8 +948,13 @@
<table class="LC_nested">
<tr class="LC_info_row">
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
- <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
- $item->{'print'}->('bottom',$dom,$settings,\$rowtotal).'
+ <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n";
+ if ($action eq 'passwords') {
+ $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);
+ } else {
+ $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
+ }
+ $output .= '
</table>
</td>
</tr>
@@ -5770,6 +5800,395 @@
return $datatable;
}
+sub print_passwords {
+ my ($position,$dom,$confname,$settings,$rowtotal) = @_;
+ my ($datatable,$css_class);
+ my $itemcount = 0;
+ my %titles = &Apache::lonlocal::texthash (
+ captcha => '"Forgot Password" CAPTCHA validation',
+ link => 'Reset link expiration (hours)',
+ case => 'Case-sensitive usernames/e-mail',
+ prelink => 'Information required (form 1)',
+ postlink => 'Information required (form 2)',
+ emailsrc => 'LON-CAPA e-mail address type(s)',
+ customtext => 'Domain specific text (HTML)',
+ intauth_cost => 'Encryption cost for bcrypt (positive integer)',
+ intauth_check => 'Check bcrypt cost if authenticated',
+ intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',
+ permanent => 'Permanent e-mail address',
+ critical => 'Critical notification address',
+ notify => 'Notification address',
+ min => 'Minimum password length',
+ max => 'Maximum password length',
+ chars => 'Required characters',
+ expire => 'Password expiration (days)',
+ );
+ if ($position eq 'top') {
+ my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
+ my $shownlinklife = 2;
+ my $prelink = 'both';
+ my (%casesens,%postlink,%emailsrc,$nostdtext,$customurl);
+ if (ref($settings) eq 'HASH') {
+ if ($settings->{resetlink} =~ /^\d+(|\.\d*)$/) {
+ $shownlinklife = $settings->{resetlink};
+ }
+ if (ref($settings->{resetcase}) eq 'ARRAY') {
+ map { $casesens{$_} = 1; } (@{$settings->{resetcase}});
+ }
+ if ($settings->{resetprelink} =~ /^(both|either)$/) {
+ $prelink = $settings->{resetprelink};
+ }
+ if (ref($settings->{resetpostlink}) eq 'HASH') {
+ %postlink = %{$settings->{resetpostlink}};
+ }
+ if (ref($settings->{resetemail}) eq 'ARRAY') {
+ map { $emailsrc{$_} = 1; } (@{$settings->{resetemail}});
+ }
+ if ($settings->{resetremove}) {
+ $nostdtext = 1;
+ }
+ if ($settings->{resetcustom}) {
+ $customurl = $settings->{resetcustom};
+ }
+ } else {
+ if (ref($types) eq 'ARRAY') {
+ foreach my $item (@{$types}) {
+ $casesens{$item} = 1;
+ $postlink{$item} = ['username','email'];
+ }
+ }
+ $casesens{'default'} = 1;
+ $postlink{'default'} = ['username','email'];
+ $prelink = 'both';
+ %emailsrc = (
+ permanent => 1,
+ critical => 1,
+ notify => 1,
+ );
+ }
+ $datatable = &captcha_choice('passwords',$settings,$$rowtotal);
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'link'}.'</td>'.
+ '<td class="LC_left_item">'.
+ '<input type="textbox" value="'.$shownlinklife.'" '.
+ 'name="passwords_link" size="3" /></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'case'}.'</td>'.
+ '<td class="LC_left_item">';
+ if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
+ foreach my $item (@{$types}) {
+ my $checkedcase;
+ if ($casesens{$item}) {
+ $checkedcase = ' checked="checked"';
+ }
+ $datatable .= '<span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="passwords_case_sensitive" value="'.
+ $item.'"'.$checkedcase.' />'.$usertypes->{$item}.'</label>'.
+ '<span> ';
+ }
+ }
+ my $checkedcase;
+ if ($casesens{'default'}) {
+ $checkedcase = ' checked="checked"';
+ }
+ $datatable .= '<span class="LC_nobreak"><label><input type="checkbox" '.
+ 'name="passwords_case_sensitive" value="default"'.$checkedcase.' />'.
+ $othertitle.'</label></span></td>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my %checkedpre = (
+ both => ' checked="checked"',
+ either => '',
+ );
+ if ($prelink eq 'either') {
+ $checkedpre{either} = ' checked="checked"';
+ $checkedpre{both} = '';
+ }
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'prelink'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<label><input type="radio" name="passwords_prelink" value="both"'.$checkedpre{'both'}.' />'.
+ &mt('Both username and e-mail address').'</label></span> '.
+ '<span class="LC_nobreak"><label>'.
+ '<input type="radio" name="passwords_prelink" value="either"'.$checkedpre{'either'}.' />'.
+ &mt('Either username or e-mail address').'</label></span></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'postlink'}.'</td>'.
+ '<td class="LC_left_item">';
+ my %postlinked;
+ if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
+ foreach my $item (@{$types}) {
+ undef(%postlinked);
+ $datatable .= '<fieldset style="display: inline-block;">'.
+ '<legend>'.$usertypes->{$item}.'</legend>';
+ if (ref($postlink{$item}) eq 'ARRAY') {
+ map { $postlinked{$_} = 1; } (@{$postlink{$item}});
+ }
+ foreach my $field ('email','username') {
+ my $checked;
+ if ($postlinked{$field}) {
+ $checked = ' checked="checked"';
+ }
+ $datatable .= '<span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="passwords_postlink_'.$item.'" value="'.
+ $field.'"'.$checked.' />'.$field.'</label>'.
+ '<span> ';
+ }
+ $datatable .= '</fieldset>';
+ }
+ }
+ if (ref($postlink{'default'}) eq 'ARRAY') {
+ map { $postlinked{$_} = 1; } (@{$postlink{'default'}});
+ }
+ $datatable .= '<fieldset style="display: inline-block;">'.
+ '<legend>'.$othertitle.'</legend>';
+ foreach my $field ('email','username') {
+ my $checked;
+ if ($postlinked{$field}) {
+ $checked = ' checked="checked"';
+ }
+ $datatable .= '<span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="passwords_postlink_default" value="'.
+ $field.'"'.$checked.' />'.$field.'</label>'.
+ '<span> ';
+ }
+ $datatable .= '</fieldset></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'emailsrc'}.'</td>'.
+ '<td class="LC_left_item">';
+ foreach my $type ('permanent','critical','notify') {
+ my $checkedemail;
+ if ($emailsrc{$type}) {
+ $checkedemail = ' checked="checked"';
+ }
+ $datatable .= '<span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="passwords_emailsrc" value="'.
+ $type.'"'.$checkedemail.' />'.$titles{$type}.'</label>'.
+ '<span> ';
+ }
+ $datatable .= '</td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $switchserver = &check_switchserver($dom,$confname);
+ my ($showstd,$noshowstd);
+ if ($nostdtext) {
+ $noshowstd = ' checked="checked"';
+ } else {
+ $showstd = ' checked="checked"';
+ }
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'customtext'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ &mt('Retain standard text:').
+ '<label><input type="radio" name="passwords_stdtext" value="1"'.$showstd.' />'.
+ &mt('Yes').'</label>'.' '.
+ '<label><input type="radio" name="passwords_stdtext" value="0"'.$noshowstd.' />'.
+ &mt('No').'</label></span><br />'.
+ '<span class="LC_fontsize_small">'.
+ &mt('(If you use the same account ... reset a password from this page.)').'</span><br /><br />'.
+ &mt('Include custom text:');
+ if ($customurl) {
+ my $link = &Apache::loncommon::modal_link($customurl,&mt('Custom text file'),600,500,
+ undef,undef,undef,undef,'background-color:#ffffff');
+ $datatable .= '<span class="LC_nobreak"> '.$link.
+ '<label><input type="checkbox" name="passwords_custom_del"'.
+ ' value="1" />'.&mt('Delete?').'</label></span>'.
+ ' <span class="LC_nobreak"> '.&mt('Replace:').'</span>';
+ }
+ if ($switchserver) {
+ $datatable .= '<span class="LC_nobreak"> '.&mt('Upload to library server: [_1]',$switchserver).'</span>';
+ } else {
+ $datatable .='<span class="LC_nobreak"> '.
+ '<input type="file" name="passwords_customfile" /></span>';
+ }
+ $datatable .= '</td></tr>';
+ } elsif ($position eq 'middle') {
+ my %domconf = &Apache::lonnet::get_dom('configuration',['defaults'],$dom);
+ my @items = ('intauth_cost','intauth_check','intauth_switch');
+ my %defaults;
+ if (ref($domconf{'defaults'}) eq 'HASH') {
+ %defaults = %{$domconf{'defaults'}};
+ if ($defaults{'intauth_cost'} !~ /^\d+$/) {
+ $defaults{'intauth_cost'} = 10;
+ }
+ if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {
+ $defaults{'intauth_check'} = 0;
+ }
+ if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {
+ $defaults{'intauth_switch'} = 0;
+ }
+ } else {
+ %defaults = (
+ 'intauth_cost' => 10,
+ 'intauth_check' => 0,
+ 'intauth_switch' => 0,
+ );
+ }
+ foreach my $item (@items) {
+ if ($itemcount%2) {
+ $css_class = '';
+ } else {
+ $css_class = ' class="LC_odd_row" ';
+ }
+ $datatable .= '<tr'.$css_class.'>'.
+ '<td><span class="LC_nobreak">'.$titles{$item}.
+ '</span></td><td class="LC_left_item" colspan="3">';
+ if ($item eq 'intauth_switch') {
+ my @options = (0,1,2);
+ my %optiondesc = &Apache::lonlocal::texthash (
+ 0 => 'No',
+ 1 => 'Yes',
+ 2 => 'Yes, and copy existing passwd file to passwd.bak file',
+ );
+ $datatable .= '<table width="100%">';
+ foreach my $option (@options) {
+ my $checked = ' ';
+ if ($defaults{$item} eq $option) {
+ $checked = ' checked="checked"';
+ }
+ $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
+ '<label><input type="radio" name="'.$item.
+ '" value="'.$option.'"'.$checked.' />'.
+ $optiondesc{$option}.'</label></span></td></tr>';
+ }
+ $datatable .= '</table>';
+ } elsif ($item eq 'intauth_check') {
+ my @options = (0,1,2);
+ my %optiondesc = &Apache::lonlocal::texthash (
+ 0 => 'No',
+ 1 => 'Yes, allow login then update passwd file using default cost (if higher)',
+ 2 => 'Yes, disallow login if stored cost is less than domain default',
+ );
+ $datatable .= '<table width="100%">';
+ foreach my $option (@options) {
+ my $checked = ' ';
+ my $onclick;
+ if ($defaults{$item} eq $option) {
+ $checked = ' checked="checked"';
+ }
+ if ($option == 2) {
+ $onclick = ' onclick="javascript:warnIntAuth(this);"';
+ }
+ $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
+ '<label><input type="radio" name="'.$item.
+ '" value="'.$option.'"'.$checked.$onclick.' />'.
+ $optiondesc{$option}.'</label></span></td></tr>';
+ }
+ $datatable .= '</table>';
+ } else {
+ $datatable .= '<input type="text" name="'.$item.'" value="'.
+ $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />';
+ }
+ $datatable .= '</td></tr>';
+ $itemcount ++;
+ }
+ } elsif ($position eq 'lower') {
+ my ($min,$max,%chars,$expire);
+ if (ref($settings) eq 'HASH') {
+ if ($settings->{min}) {
+ $min = $settings->{min};
+ }
+ if ($settings->{max}) {
+ $max = $settings->{max};
+ }
+ if (ref($settings->{chars}) eq 'ARRAY') {
+ map { $chars{$_} = 1; } (@{$settings->{chars}});
+ }
+ if ($settings->{expire}) {
+ $expire = $settings->{expire};
+ }
+ } else {
+ $min = '7';
+ }
+ 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',
+ );
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'min'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="passwords_min" value="'.$min.'" size="3" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no minimum)').'</span>'.
+ '</span></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'max'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="passwords_max" value="'.$max.'" size="3" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no maximum)').'</span>'.
+ '</span></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'chars'}.'<br />'.
+ '<span class="LC_nobreak LC_fontsize_small">'.&mt('(Leave unchecked if not required)').
+ '</span></td>';
+ my $numinrow = 2;
+ my @possrules = ('uc','lc','num','spec');
+ $datatable .= '<td class="LC_left_item"><table>';
+ for (my $i=0; $i<@possrules; $i++) {
+ my ($rem,$checked);
+ if ($chars{$possrules[$i]}) {
+ $checked = ' checked="checked"';
+ }
+ $rem = $i%($numinrow);
+ if ($rem == 0) {
+ if ($i > 0) {
+ $datatable .= '</tr>';
+ }
+ $datatable .= '<tr>';
+ }
+ $datatable .= '<td><span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="passwords_chars" value="'.$possrules[$i].'"'.$checked.' />'.
+ $rulenames{$possrules[$i]}.'</label></span></td>';
+ }
+ my $rem = @possrules%($numinrow);
+ my $colsleft = $numinrow - $rem;
+ if ($colsleft > 1 ) {
+ $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
+ ' </td>';
+ } elsif ($colsleft == 1) {
+ $datatable .= '<td class="LC_left_item"> </td>';
+ }
+ $datatable .='</table></td></tr>';
+ $itemcount ++;
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.
+ '<td class="LC_left_item"><span class="LC_nobreak">'.
+ '<input type="text" name="passwords_expire" value="'.$expire.'" size="4" />'.
+ '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
+ '</span></td></tr>';
+ } else {
+ my $checkedon;
+ my $checkedoff = ' checked="checked"';
+ if (ref($settings) eq 'HASH') {
+ if ($settings->{crsownerchg}) {
+ $checkedon = $checkedoff;
+ $checkedoff = '';
+ }
+ }
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr '.$css_class.'>'.
+ '<td>'.
+ &mt('Requirements').'<ul>'.
+ '<li>'.&mt("Course 'type' is not a Community").'</li>'.
+ '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.
+ '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.
+ '</ul>'.
+ '</td>'.
+ '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
+ '<label><input type="radio" name="passwords_crsowner" value="1"'.$checkedon.' />'.&mt('Yes').'</label></span> '.
+ '<span class="LC_nobreak"><label><input type="radio" name="passwords_crsowner" value="0"'.$checkedoff.' />'.
+ &mt('No').'</label></span>'.
+ '</td></tr>';
+
+ }
+ return $datatable;
+}
+
sub print_usersessions {
my ($position,$dom,$settings,$rowtotal) = @_;
my ($css_class,$datatable,$itemcount,%checked,%choices);
@@ -7528,10 +7947,14 @@
$vertext,$currver);
my %lt = &captcha_phrases();
$keyentry = 'hidden';
+ my $colspan=2;
if ($context eq 'cancreate') {
$rowname = &mt('CAPTCHA validation');
} elsif ($context eq 'login') {
$rowname = &mt('"Contact helpdesk" CAPTCHA validation');
+ } elsif ($context eq 'passwords') {
+ $rowname = &mt('"Forgot Password" CAPTCHA validation');
+ $colspan=1;
}
if (ref($settings) eq 'HASH') {
if ($settings->{'captcha'}) {
@@ -7571,7 +7994,7 @@
$css_class .= ' style="'.$rowstyle.'"';
}
my $output = '<tr'.$css_class.'>'.
- '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="2">'."\n".
+ '<td class="LC_left_item">'.$rowname.'</td><td class="LC_left_item" colspan="'.$colspan.'">'."\n".
'<table><tr><td>'."\n";
foreach my $option ('original','recaptcha','notused') {
$output .= '<span class="LC_nobreak"><label><input type="radio" name="'.$context.'_captcha" value="'.
@@ -7810,133 +8233,54 @@
$datatable .= '</td></tr>';
$rownum ++;
}
- } elsif ($position eq 'middle') {
- my @items = ('intauth_cost','intauth_check','intauth_switch');
+ } else {
my %defaults;
if (ref($settings) eq 'HASH') {
- %defaults = %{$settings};
- if ($defaults{'intauth_cost'} !~ /^\d+$/) {
- $defaults{'intauth_cost'} = 10;
- }
- if ($defaults{'intauth_check'} !~ /^(0|1|2)$/) {
- $defaults{'intauth_check'} = 0;
- }
- if ($defaults{'intauth_switch'} !~ /^(0|1|2)$/) {
- $defaults{'intauth_switch'} = 0;
- }
- } else {
- %defaults = (
- 'intauth_cost' => 10,
- 'intauth_check' => 0,
- 'intauth_switch' => 0,
- );
- }
- foreach my $item (@items) {
- if ($rownum%2) {
- $css_class = '';
- } else {
- $css_class = ' class="LC_odd_row" ';
- }
- $datatable .= '<tr'.$css_class.'>'.
- '<td><span class="LC_nobreak">'.$titles->{$item}.
- '</span></td><td class="LC_left_item" colspan="3">';
- if ($item eq 'intauth_switch') {
- my @options = (0,1,2);
- my %optiondesc = &Apache::lonlocal::texthash (
- 0 => 'No',
- 1 => 'Yes',
- 2 => 'Yes, and copy existing passwd file to passwd.bak file',
- );
- $datatable .= '<table width="100%">';
- foreach my $option (@options) {
- my $checked = ' ';
- if ($defaults{$item} eq $option) {
- $checked = ' checked="checked"';
- }
- $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
- '<label><input type="radio" name="'.$item.
- '" value="'.$option.'"'.$checked.' />'.
- $optiondesc{$option}.'</label></span></td></tr>';
- }
- $datatable .= '</table>';
- } elsif ($item eq 'intauth_check') {
- my @options = (0,1,2);
- my %optiondesc = &Apache::lonlocal::texthash (
- 0 => 'No',
- 1 => 'Yes, allow login then update passwd file using default cost (if higher)',
- 2 => 'Yes, disallow login if stored cost is less than domain default',
- );
- $datatable .= '<table width="100%">';
- foreach my $option (@options) {
- my $checked = ' ';
- my $onclick;
- if ($defaults{$item} eq $option) {
- $checked = ' checked="checked"';
- }
- if ($option == 2) {
- $onclick = ' onclick="javascript:warnIntAuth(this);"';
- }
- $datatable .= '<tr><td class="LC_left_item"><span class="LC_nobreak">'.
- '<label><input type="radio" name="'.$item.
- '" value="'.$option.'"'.$checked.$onclick.' />'.
- $optiondesc{$option}.'</label></span></td></tr>';
- }
- $datatable .= '</table>';
- } else {
- $datatable .= '<input type="text" name="'.$item.'" value="'.
- $defaults{$item}.'" size="3" onblur="javascript:warnIntAuth(this);" />';
- }
- $datatable .= '</td></tr>';
- $rownum ++;
- }
- } else {
- my %defaults;
- if (ref($settings) eq 'HASH') {
- if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
- my $maxnum = @{$settings->{'inststatusorder'}};
- for (my $i=0; $i<$maxnum; $i++) {
- $css_class = $rownum%2?' class="LC_odd_row"':'';
- my $item = $settings->{'inststatusorder'}->[$i];
- my $title = $settings->{'inststatustypes'}->{$item};
- my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';
- $datatable .= '<tr'.$css_class.'>'.
- '<td><span class="LC_nobreak">'.
- '<select name="inststatus_pos_'.$item.'"'.$chgstr.'>';
- for (my $k=0; $k<=$maxnum; $k++) {
- my $vpos = $k+1;
- my $selstr;
- if ($k == $i) {
- $selstr = ' selected="selected" ';
- }
- $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
- }
- $datatable .= '</select> '.&mt('Internal ID:').' <b>'.$item.'</b> '.
- '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
- &mt('delete').'</span></td>'.
- '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed:').
- '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
- '</span></td></tr>';
- }
- $css_class = $rownum%2?' class="LC_odd_row"':'';
- my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';
- $datatable .= '<tr '.$css_class.'>'.
- '<td><span class="LC_nobreak"><select name="addinststatus_pos"'.$chgstr.'>';
- for (my $k=0; $k<=$maxnum; $k++) {
- my $vpos = $k+1;
- my $selstr;
- if ($k == $maxnum) {
- $selstr = ' selected="selected" ';
- }
- $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
- }
- $datatable .= '</select> '.&mt('Internal ID:').
- '<input type="text" size="10" name="addinststatus" value="" />'.
- ' '.&mt('(new)').
- '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
- &mt('Name displayed:').
- '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
- '</tr>'."\n";
- $rownum ++;
+ if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
+ my $maxnum = @{$settings->{'inststatusorder'}};
+ for (my $i=0; $i<$maxnum; $i++) {
+ $css_class = $rownum%2?' class="LC_odd_row"':'';
+ my $item = $settings->{'inststatusorder'}->[$i];
+ my $title = $settings->{'inststatustypes'}->{$item};
+ my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'$item'".');"';
+ $datatable .= '<tr'.$css_class.'>'.
+ '<td><span class="LC_nobreak">'.
+ '<select name="inststatus_pos_'.$item.'"'.$chgstr.'>';
+ for (my $k=0; $k<=$maxnum; $k++) {
+ my $vpos = $k+1;
+ my $selstr;
+ if ($k == $i) {
+ $selstr = ' selected="selected" ';
+ }
+ $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
+ }
+ $datatable .= '</select> '.&mt('Internal ID:').' <b>'.$item.'</b> '.
+ '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
+ &mt('delete').'</span></td>'.
+ '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed:').
+ '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
+ '</span></td></tr>';
+ }
+ $css_class = $rownum%2?' class="LC_odd_row"':'';
+ my $chgstr = ' onchange="javascript:reorderTypes(this.form,'."'addinststatus_pos'".');"';
+ $datatable .= '<tr '.$css_class.'>'.
+ '<td><span class="LC_nobreak"><select name="addinststatus_pos"'.$chgstr.'>';
+ for (my $k=0; $k<=$maxnum; $k++) {
+ my $vpos = $k+1;
+ my $selstr;
+ if ($k == $maxnum) {
+ $selstr = ' selected="selected" ';
+ }
+ $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
+ }
+ $datatable .= '</select> '.&mt('Internal ID:').
+ '<input type="text" size="10" name="addinststatus" value="" />'.
+ ' '.&mt('(new)').
+ '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
+ &mt('Name displayed:').
+ '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
+ '</tr>'."\n";
+ $rownum ++;
}
}
}
@@ -8677,35 +9021,7 @@
sub defaults_javascript {
my ($settings) = @_;
- my $intauthcheck = &mt('Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.');
- my $intauthcost = &mt('Warning: bcrypt encryption cost for internal authentication must be an integer.');
- &js_escape(\$intauthcheck);
- &js_escape(\$intauthcost);
- my $intauthjs = <<"ENDSCRIPT";
-
-function warnIntAuth(field) {
- if (field.name == 'intauth_check') {
- if (field.value == '2') {
- alert('$intauthcheck');
- }
- }
- if (field.name == 'intauth_cost') {
- field.value.replace(/\s/g,'');
- if (field.value != '') {
- var regexdigit=/^\\d+\$/;
- if (!regexdigit.test(field.value)) {
- alert('$intauthcost');
- }
- }
- }
- return;
-}
-
-ENDSCRIPT
-
- if (ref($settings) ne 'HASH') {
- return &Apache::lonhtmlcommon::scripttag($intauthjs);
- }
+ return unless (ref($settings) eq 'HASH');
if ((ref($settings->{'inststatusorder'}) eq 'ARRAY') && (ref($settings->{'inststatustypes'}) eq 'HASH')) {
my $maxnum = scalar(@{$settings->{'inststatusorder'}});
if ($maxnum eq '') {
@@ -8759,15 +9075,41 @@
return;
}
-$intauthjs
-
// ]]>
</script>
ENDSCRIPT
- } else {
- return &Apache::lonhtmlcommon::scripttag($intauthjs);
}
+ return;
+}
+
+sub passwords_javascript {
+ my $intauthcheck = &mt('Warning: disallowing login for an authenticated user if the stored cost is less than the default will require a password reset by/for the user.');
+ my $intauthcost = &mt('Warning: bcrypt encryption cost for internal authentication must be an integer.');
+ &js_escape(\$intauthcheck);
+ &js_escape(\$intauthcost);
+ my $intauthjs = <<"ENDSCRIPT";
+
+function warnIntAuth(field) {
+ if (field.name == 'intauth_check') {
+ if (field.value == '2') {
+ alert('$intauthcheck');
+ }
+ }
+ if (field.name == 'intauth_cost') {
+ field.value.replace(/\s/g,'');
+ if (field.value != '') {
+ var regexdigit=/^\\d+\$/;
+ if (!regexdigit.test(field.value)) {
+ alert('$intauthcost');
+ }
+ }
+ }
+ return;
+}
+
+ENDSCRIPT
+ return &Apache::lonhtmlcommon::scripttag($intauthjs);
}
sub coursecategories_javascript {
@@ -9122,7 +9464,7 @@
my $check = ' ';
unless ($role eq 'emailusername') {
if (exists($checks{$fields[$i]})) {
- $check = $checks{$fields[$i]}
+ $check = $checks{$fields[$i]};
} elsif ($context ne 'lti') {
if ($role eq 'st') {
if (ref($settings) ne 'HASH') {
@@ -13616,6 +13958,460 @@
return $resulttext;
}
+sub modify_passwords {
+ my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
+ my ($resulttext,%current,%changes,%newvalues, at oktypes,$errors,$updatedefaults);
+ my $customfn = 'resetpw.html';
+ if (ref($domconfig{'passwords'}) eq 'HASH') {
+ %current = %{$domconfig{'passwords'}};
+ }
+ my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
+ my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
+ if (ref($types) eq 'ARRAY') {
+ @oktypes = @{$types};
+ }
+ push(@oktypes,'default');
+
+ my %titles = &Apache::lonlocal::texthash (
+ intauth_cost => 'Encryption cost for bcrypt (positive integer)',
+ intauth_check => 'Check bcrypt cost if authenticated',
+ intauth_switch => 'Existing crypt-based switched to bcrypt on authentication',
+ permanent => 'Permanent e-mail address',
+ critical => 'Critical notification address',
+ notify => 'Notification address',
+ min => 'Minimum password length',
+ max => 'Maximum password length',
+ chars => 'Required characters',
+ expire => 'Password expiration (days)',
+ reset => 'Resetting Forgotten Password',
+ intauth => 'Encryption of Stored Passwords (Internal Auth)',
+ rules => 'Rules for LON-CAPA Passwords',
+ crsownerchg => 'Course Owner Changing Student Passwords',
+ username => 'Username',
+ email => 'E-mail address',
+ );
+
+#
+# Retrieve current domain configuration for internal authentication from $domconfig{'defaults'}.
+#
+ my (%curr_defaults,%save_defaults);
+ if (ref($domconfig{'defaults'}) eq 'HASH') {
+ foreach my $key (keys(%{$domconfig{'defaults'}})) {
+ if ($key =~ /^intauth_(cost|check|switch)$/) {
+ $curr_defaults{$key} = $domconfig{'defaults'}{$key};
+ } else {
+ $save_defaults{$key} = $domconfig{'defaults'}{$key};
+ }
+ }
+ }
+ my %staticdefaults = (
+ 'resetlink' => 2,
+ 'resetcase' => \@oktypes,
+ 'resetprelink' => 'both',
+ 'resetemail' => ['critical','notify','permanent'],
+ 'intauth_cost' => 10,
+ 'intauth_check' => 0,
+ 'intauth_switch' => 0,
+ 'min' => 7,
+ );
+ foreach my $type (@oktypes) {
+ $staticdefaults{'resetpostlink'}{$type} = ['email','username'];
+ }
+ my $linklife = $env{'form.passwords_link'};
+ $linklife =~ s/^\s+|\s+$//g;
+ if (($linklife =~ /^\d+(|\.\d*)$/) && ($linklife > 0)) {
+ $newvalues{'resetlink'} = $linklife;
+ if ($current{'resetlink'}) {
+ if ($current{'resetlink'} ne $linklife) {
+ $changes{'reset'} = 1;
+ }
+ } elsif (!exists($domconfig{passwords})) {
+ if ($staticdefaults{'resetlink'} ne $linklife) {
+ $changes{'reset'} = 1;
+ }
+ }
+ } elsif ($current{'resetlink'}) {
+ $changes{'reset'} = 1;
+ }
+ my @casesens;
+ my @posscase = &Apache::loncommon::get_env_multiple('form.passwords_case_sensitive');
+ foreach my $case (sort(@posscase)) {
+ if (grep(/^\Q$case\E$/, at oktypes)) {
+ push(@casesens,$case);
+ }
+ }
+ $newvalues{'resetcase'} = \@casesens;
+ if (ref($current{'resetcase'}) eq 'ARRAY') {
+ my @diffs = &Apache::loncommon::compare_arrays($current{'resetcase'},\@casesens);
+ if (@diffs > 0) {
+ $changes{'reset'} = 1;
+ }
+ } elsif (!exists($domconfig{passwords})) {
+ my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetcase'},\@casesens);
+ if (@diffs > 0) {
+ $changes{'reset'} = 1;
+ }
+ }
+ if ($env{'form.passwords_prelink'} =~ /^(both|either)$/) {
+ $newvalues{'resetprelink'} = $env{'form.passwords_prelink'};
+ if (exists($current{'resetprelink'})) {
+ if ($current{'resetprelink'} ne $newvalues{'resetprelink'}) {
+ $changes{'reset'} = 1;
+ }
+ } elsif (!exists($domconfig{passwords})) {
+ if ($staticdefaults{'resetprelink'} ne $newvalues{'resetprelink'}) {
+ $changes{'reset'} = 1;
+ }
+ }
+ } elsif ($current{'resetprelink'}) {
+ $changes{'reset'} = 1;
+ }
+ foreach my $type (@oktypes) {
+ my @possplink = &Apache::loncommon::get_env_multiple('form.passwords_postlink_'.$type);
+ my @postlink;
+ foreach my $item (sort(@possplink)) {
+ if ($item =~ /^(email|username)$/) {
+ push(@postlink,$item);
+ }
+ }
+ $newvalues{'resetpostlink'}{$type} = \@postlink;
+ unless ($changes{'reset'}) {
+ if (ref($current{'resetpostlink'}) eq 'HASH') {
+ if (ref($current{'resetpostlink'}{$type}) eq 'ARRAY') {
+ my @diffs = &Apache::loncommon::compare_arrays($current{'resetpostlink'}{$type},\@postlink);
+ if (@diffs > 0) {
+ $changes{'reset'} = 1;
+ }
+ } else {
+ $changes{'reset'} = 1;
+ }
+ } elsif (!exists($domconfig{passwords})) {
+ my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetpostlink'}{$type},\@postlink);
+ if (@diffs > 0) {
+ $changes{'reset'} = 1;
+ }
+ }
+ }
+ }
+ my @possemailsrc = &Apache::loncommon::get_env_multiple('form.passwords_emailsrc');
+ my @resetemail;
+ foreach my $item (sort(@possemailsrc)) {
+ if ($item =~ /^(permanent|critical|notify)$/) {
+ push(@resetemail,$item);
+ }
+ }
+ $newvalues{'resetemail'} = \@resetemail;
+ unless ($changes{'reset'}) {
+ if (ref($current{'resetemail'}) eq 'ARRAY') {
+ my @diffs = &Apache::loncommon::compare_arrays($current{'resetemail'},\@resetemail);
+ if (@diffs > 0) {
+ $changes{'reset'} = 1;
+ }
+ } elsif (!exists($domconfig{passwords})) {
+ my @diffs = &Apache::loncommon::compare_arrays($staticdefaults{'resetemail'},\@resetemail);
+ if (@diffs > 0) {
+ $changes{'reset'} = 1;
+ }
+ }
+ }
+ if ($env{'form.passwords_stdtext'} == 0) {
+ $newvalues{'resetremove'} = 1;
+ unless ($current{'resetremove'}) {
+ $changes{'reset'} = 1;
+ }
+ } elsif ($current{'resetremove'}) {
+ $changes{'reset'} = 1;
+ }
+ if ($env{'form.passwords_customfile.filename'} ne '') {
+ my $servadm = $r->dir_config('lonAdmEMail');
+ my ($configuserok,$author_ok,$switchserver) =
+ &config_check($dom,$confname,$servadm);
+ my $error;
+ if ($configuserok eq 'ok') {
+ if ($switchserver) {
+ $error = &mt("Upload of file containing domain-specific text is not permitted to this server: [_1]",$switchserver);
+ } else {
+ if ($author_ok eq 'ok') {
+ my ($result,$customurl) =
+ &publishlogo($r,'upload','passwords_customfile',$dom,
+ $confname,'customtext/resetpw','','',$customfn);
+ if ($result eq 'ok') {
+ $newvalues{'resetcustom'} = $customurl;
+ $changes{'reset'} = 1;
+ } else {
+ $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$customfn,$result);
+ }
+ } else {
+ $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$customfn,$confname,$dom,$author_ok);
+ }
+ }
+ } else {
+ $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$customfn,$confname,$dom,$configuserok);
+ }
+ if ($error) {
+ &Apache::lonnet::logthis($error);
+ $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
+ }
+ } elsif ($current{'resetcustom'}) {
+ if ($env{'form.passwords_custom_del'}) {
+ $changes{'reset'} = 1;
+ } else {
+ $newvalues{'resetcustom'} = $current{'resetcustom'};
+ }
+ }
+ $env{'form.intauth_cost'} =~ s/^\s+|\s+$//g;
+ if (($env{'form.intauth_cost'} ne '') && ($env{'form.intauth_cost'} =~ /^\d+$/)) {
+ $save_defaults{'intauth_cost'} = $env{'form.intauth_cost'};
+ if ($save_defaults{'intauth_cost'} ne $curr_defaults{'intauth_cost'}) {
+ $changes{'intauth'} = 1;
+ }
+ } else {
+ $save_defaults{'intauth_cost'} = $curr_defaults{'intauth_cost'};
+ }
+ if ($env{'form.intauth_check'} =~ /^(0|1|2)$/) {
+ $save_defaults{'intauth_check'} = $env{'form.intauth_check'};
+ if ($save_defaults{'intauth_check'} ne $curr_defaults{'intauth_check'}) {
+ $changes{'intauth'} = 1;
+ }
+ } else {
+ $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};
+ }
+ if ($env{'form.intauth_switch'} =~ /^(0|1|2)$/) {
+ $save_defaults{'intauth_switch'} = $env{'form.intauth_switch'};
+ if ($save_defaults{'intauth_switch'} ne $curr_defaults{'intauth_switch'}) {
+ $changes{'intauth'} = 1;
+ }
+ } else {
+ $save_defaults{'intauth_check'} = $curr_defaults{'intauth_check'};
+ }
+ foreach my $item ('cost','check','switch') {
+ if ($save_defaults{'intauth_'.$item} ne $domdefaults{'intauth_'.$item}) {
+ $domdefaults{'intauth_'.$item} = $save_defaults{'intauth_'.$item};
+ $updatedefaults = 1;
+ }
+ }
+ foreach my $rule ('min','max','expire') {
+ $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g;
+ if ($env{'form.passwords_'.$rule} =~ /^(|\d+(|\.\d*))$/) {
+ $newvalues{$rule} = $env{'form.passwords_'.$rule};
+ if (exists($current{$rule})) {
+ if ($newvalues{$rule} ne $current{$rule}) {
+ $changes{'rules'} = 1;
+ }
+ } elsif ($rule eq 'min') {
+ if ($staticdefaults{$rule} ne $newvalues{$rule}) {
+ $changes{'rules'} = 1;
+ }
+ }
+ } elsif (exists($current{$rule})) {
+ $changes{'rules'} = 1;
+ }
+ }
+ my @posschars = &Apache::loncommon::get_env_multiple('form.passwords_chars');
+ my @chars;
+ foreach my $item (sort(@posschars)) {
+ if ($item =~ /^(uc|lc|num|spec)$/) {
+ push(@chars,$item);
+ }
+ }
+ $newvalues{'chars'} = \@chars;
+ unless ($changes{'rules'}) {
+ if (ref($current{'chars'}) eq 'ARRAY') {
+ my @diffs = &Apache::loncommon::compare_arrays($current{'chars'},\@chars);
+ if (@diffs > 0) {
+ $changes{'rules'} = 1;
+ }
+ } else {
+ if (@chars > 0) {
+ $changes{'rules'} = 1;
+ }
+ }
+ }
+ if ($env{'form.passwords_crsowner'}) {
+ $newvalues{'crsownerchg'} = 1;
+ unless ($current{'crsownerchg'}) {
+ $changes{'crsownerchg'} = 1;
+ }
+ } elsif ($current{'crsownerchg'}) {
+ $changes{'crsownerchg'} = 1;
+ }
+
+ my %confighash = (
+ defaults => \%save_defaults,
+ passwords => \%newvalues,
+ );
+ &process_captcha('passwords',\%changes,$confighash{'passwords'},$domconfig{'passwords'});
+
+ my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);
+ if ($putresult eq 'ok') {
+ if (keys(%changes) > 0) {
+ $resulttext = &mt('Changes made: ').'<ul>';
+ foreach my $key ('reset','intauth','rules','crsownerchg') {
+ if ($changes{$key}) {
+ $resulttext .= '<li>'.$titles{$key}.':<ul>';
+ if ($key eq 'reset') {
+ if ($confighash{'passwords'}{'captcha'} eq 'original') {
+ $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: original CAPTCHA').'</li>';
+ } elsif ($confighash{'passwords'}{'captcha'} eq 'recaptcha') {
+ $resulttext .= '<li>'.&mt('CAPTCHA validation set to use: reCAPTCHA').' '.
+ &mt('version: [_1]',$confighash{'passwords'}{'recaptchaversion'}).'<br />'.
+ &mt('Public key: [_1]',$confighash{'passwords'}{'recaptchapub'}).'</br>'.
+ &mt('Private key: [_1]',$confighash{'passwords'}{'recaptchapriv'}).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('No CAPTCHA validation').'</li>';
+ }
+ if ($confighash{'passwords'}{'resetlink'}) {
+ $resulttext .= '<li>'.&mt('Reset link expiration set to [quant,_1,hour]',$confighash{'passwords'}{'resetlink'}).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('No reset link expiration set.').' '.
+ &mt('Will default to 2 hours').'</li>';
+ }
+ if (ref($confighash{'passwords'}{'resetcase'}) eq 'ARRAY') {
+ if (@{$confighash{'passwords'}{'resetcase'}} == 0) {
+ $resulttext .= '<li>'.&mt('User input for username and/or e-mail address not case sensitive for "Forgot Password" web form').'</li>';
+ } else {
+ my $casesens;
+ foreach my $type (@{$confighash{'passwords'}{'resetcase'}}) {
+ if ($type eq 'default') {
+ $casesens .= $othertitle.', ';
+ } elsif ($usertypes->{$type} ne '') {
+ $casesens .= $usertypes->{$type}.', ';
+ }
+ }
+ $casesens =~ s/\Q, \E$//;
+ $resulttext .= '<li>'.&mt('"Forgot Password" web form input for username and/or e-mail address is case-sensitive for: [_1]',$casesens).'</li>';
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('Case-sensitivity not set for "Forgot Password" web form').' '.&mt('Will default to case-sensitive for username and/or e-mail address for all').'</li>';
+ }
+ if ($confighash{'passwords'}{'resetprelink'} eq 'either') {
+ $resulttext .= '<li>'.&mt('Users can enter either a username or an e-mail address in "Forgot Password" web form').'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('Users can enter both a username and an e-mail address in "Forgot Password" web form').'</li>';
+ }
+ if (ref($confighash{'passwords'}{'resetpostlink'}) eq 'HASH') {
+ my $output;
+ if (ref($types) eq 'ARRAY') {
+ foreach my $type (@{$types}) {
+ if (ref($confighash{'passwords'}{'resetpostlink'}{$type}) eq 'ARRAY') {
+ if (@{$confighash{'passwords'}{'resetpostlink'}{$type}} == 0) {
+ $output .= $usertypes->{$type}.' -- '.&mt('none');
+ } else {
+ $output .= $usertypes->{$type}.' -- '.
+ join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{$type}})).'; ';
+ }
+ }
+ }
+ }
+ if (ref($confighash{'passwords'}{'resetpostlink'}{'default'}) eq 'ARRAY') {
+ if (@{$confighash{'passwords'}{'resetpostlink'}{'default'}} == 0) {
+ $output .= $othertitle.' -- '.&mt('none');
+ } else {
+ $output .= $othertitle.' -- '.
+ join(', ',map { $titles{$_}; } (@{$confighash{'passwords'}{'resetpostlink'}{'default'}}));
+ }
+ }
+ if ($output) {
+ $resulttext .= '<li>'.&mt('Information required for new password form (by user type) set to: [_1]',$output).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('Information required for new password form not set.').' '.&mt('Will default to requiring both the username and an e-mail address').'</li>';
+ }
+ if (ref($confighash{'passwords'}{'resetemail'}) eq 'ARRAY') {
+ if (@{$confighash{'passwords'}{'resetemail'}} > 0) {
+ $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$confighash{'passwords'}{'resetemail'}})).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA used for verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
+ }
+ } else {
+ $resulttext .= '<li>'.&mt('E-mail address(es) in LON-CAPA usedfor verification will include: [_1]',join(', ',map { $titles{$_}; } @{$staticdefaults{'resetemail'}})).'</li>';
+ }
+ if ($confighash{'passwords'}{'resetremove'}) {
+ $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form not shown').'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" web form is shown').'</li>';
+ }
+ if ($confighash{'passwords'}{'resetcustom'}) {
+ my $customlink = &Apache::loncommon::modal_link($confighash{'passwords'}{'resetcustom'},
+ $titles{custom},600,500);
+ $resulttext .= '<li>'.&mt('Preamble to "Forgot Password" form includes [_1]',$customlink).'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('No custom text included in preamble to "Forgot Password" form').'</li>';
+ }
+ } elsif ($key eq 'intauth') {
+ foreach my $item ('cost','switch','check') {
+ my $value = $save_defaults{$key.'_'.$item};
+ if ($item eq 'switch') {
+ my %optiondesc = &Apache::lonlocal::texthash (
+ 0 => 'No',
+ 1 => 'Yes',
+ 2 => 'Yes, and copy existing passwd file to passwd.bak file',
+ );
+ if ($value =~ /^(0|1|2)$/) {
+ $value = $optiondesc{$value};
+ } else {
+ $value = &mt('none -- defaults to No');
+ }
+ } elsif ($item eq 'check') {
+ my %optiondesc = &Apache::lonlocal::texthash (
+ 0 => 'No',
+ 1 => 'Yes, allow login then update passwd file using default cost (if higher)',
+ 2 => 'Yes, disallow login if stored cost is less than domain default',
+ );
+ if ($value =~ /^(0|1|2)$/) {
+ $value = $optiondesc{$value};
+ } else {
+ $value = &mt('none -- defaults to No');
+ }
+ }
+ $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';
+ }
+ } elsif ($key eq 'rules') {
+ foreach my $rule ('min','max','expire') {
+ if ($confighash{'passwords'}{$rule} eq '') {
+ $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
+ if ($rule eq 'min') {
+ $resulttext .= ' '.&mt('Default of 7 will be used');
+ }
+ $resulttext .= '</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>';
+ }
+ }
+ } elsif ($key eq 'crsownerchg') {
+ if ($confighash{'passwords'}{'crsownerchg'}) {
+ $resulttext .= '<li>'.&mt('Course owner may change student passwords.').'</li>';
+ } else {
+ $resulttext .= '<li>'.&mt('Course owner may not change student passwords.');
+ }
+ }
+ $resulttext .= '</ul></li>';
+ }
+ }
+ $resulttext .= '</ul>';
+ } else {
+ $resulttext = &mt('No changes made to password settings');
+ }
+ if ($updatedefaults) {
+ my $cachetime = 24*60*60;
+ &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
+ if (ref($lastactref) eq 'HASH') {
+ $lastactref->{'domdefaults'} = 1;
+ }
+ }
+ } else {
+ $resulttext = '<span class="LC_error">'.
+ &mt('An error occurred: [_1]',$putresult).'</span>';
+ }
+ if ($errors) {
+ $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
+ $errors.'</ul></p>';
+ }
+ return $resulttext;
+}
+
sub modify_usercreation {
my ($dom,%domconfig) = @_;
my ($resulttext,%curr_usercreation,%changes,%authallowed,%cancreate,%save_usercreate);
@@ -14881,7 +15677,7 @@
my ($resulttext,$mailmsgtxt,%newvalues,%changes, at errors);
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',
- 'portal_def','intauth_cost','intauth_check','intauth_switch');
+ 'portal_def');
my @authtypes = ('internal','krb4','krb5','localauth','lti');
foreach my $item (@items) {
$newvalues{$item} = $env{'form.'.$item};
@@ -14923,24 +15719,6 @@
push(@errors,$item);
}
}
- } elsif ($item eq 'intauth_cost') {
- if ($newvalues{$item} ne '') {
- if ($newvalues{$item} =~ /\D/) {
- push(@errors,$item);
- }
- }
- } elsif ($item eq 'intauth_check') {
- if ($newvalues{$item} ne '') {
- unless ($newvalues{$item} =~ /^(0|1|2)$/) {
- push(@errors,$item);
- }
- }
- } elsif ($item eq 'intauth_switch') {
- if ($newvalues{$item} ne '') {
- unless ($newvalues{$item} =~ /^(0|1|2)$/) {
- push(@errors,$item);
- }
- }
}
if (grep(/^\Q$item\E$/, at errors)) {
$newvalues{$item} = $domdefaults{$item};
@@ -14949,6 +15727,18 @@
}
$domdefaults{$item} = $newvalues{$item};
}
+ my %staticdefaults = (
+ 'intauth_cost' => 10,
+ 'intauth_check' => 0,
+ 'intauth_switch' => 0,
+ );
+ foreach my $item ('intauth_cost','intauth_check','intauth_switch') {
+ if (exists($domdefaults{$item})) {
+ $newvalues{$item} = $domdefaults{$item};
+ } else {
+ $newvalues{$item} = $staticdefaults{$item};
+ }
+ }
my %defaults_hash = (
defaults => \%newvalues,
);
@@ -15077,28 +15867,6 @@
lti => 'lti',
);
$value = $authnames{$shortauth{$value}};
- } elsif ($item eq 'intauth_switch') {
- my %optiondesc = &Apache::lonlocal::texthash (
- 0 => 'No',
- 1 => 'Yes',
- 2 => 'Yes, and copy existing passwd file to passwd.bak file',
- );
- if ($value =~ /^(0|1|2)$/) {
- $value = $optiondesc{$value};
- } else {
- $value = &mt('none -- defaults to No');
- }
- } elsif ($item eq 'intauth_check') {
- my %optiondesc = &Apache::lonlocal::texthash (
- 0 => 'No',
- 1 => 'Yes, allow login then update passwd file using default cost (if higher)',
- 2 => 'Yes, disallow login if stored cost is less than domain default',
- );
- if ($value =~ /^(0|1|2)$/) {
- $value = $optiondesc{$value};
- } else {
- $value = &mt('none -- defaults to No');
- }
}
$resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'</li>';
$mailmsgtext .= "$title->{$item} set to $value\n";
More information about the LON-CAPA-cvs
mailing list