[prev in list] [next in list] [prev in thread] [next in thread]
List: lon-capa-cvs
Subject: [LON-CAPA-cvs] cvs: loncom /interface domainprefs.pm
From: raeburn <raeburn () source ! lon-capa ! org>
Date: 2019-04-22 1:55:17
Message-ID: cvsraeburn1555898117 () cvsserver
[Download RAW message or body]
This is a MIME encoded message
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).
["raeburn-20190422015517.txt" (text/plain)]
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,@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$/,@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,@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$/,@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";
_______________________________________________
LON-CAPA-cvs mailing list
LON-CAPA-cvs@mail.lon-capa.org
http://mail.lon-capa.org/mailman/listinfo/lon-capa-cvs
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic