';
}
}
@@ -8990,7 +10701,7 @@ sub modify_login {
my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,
%curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon,
- %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlnotsso);
+ %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlwindow,%samlnotsso);
%title = ( coursecatalog => 'Display course catalog',
adminmail => 'Display administrator E-mail address',
helpdesk => 'Display "Contact Helpdesk" link',
@@ -9014,6 +10725,7 @@ sub modify_login {
$samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'};
$samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'};
$samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'};
+ $samlwindow{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'window'};
$samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'};
}
}
@@ -9156,13 +10868,16 @@ sub modify_login {
if ($addedfile ne '') {
push(@allnew,$addedfile);
}
+ my $modified = [];
foreach my $lang (@allnew) {
my $formelem = 'loginhelpurl_'.$lang;
if ($lang eq $env{'form.loginhelpurl_add_lang'}) {
$formelem = 'loginhelpurl_add_file';
}
- (my $result,$newurl{$lang}) = &publishlogo($r,'upload',$formelem,$dom,$confname,
- "help/$lang",'','',$newfile{$lang});
+ (my $result,$newurl{$lang}) =
+ &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
+ "help/$lang",'','',$newfile{$lang},
+ $modified);
if ($result eq 'ok') {
$loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang};
$changes{'helpurl'}{$lang} = 1;
@@ -9175,6 +10890,7 @@ sub modify_login {
}
}
}
+ &update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok);
}
@@ -9232,11 +10948,14 @@ sub modify_login {
if ($switchserver) {
$error = &mt("Upload of custom markup is not permitted to this server: [_1]",$switchserver);
} elsif ($author_ok eq 'ok') {
+ my $modified = [];
foreach my $lonhost (@newhosts) {
my $formelem = 'loginheadtag_'.$lonhost;
- (my $result,$newheadtagurls{$lonhost}) = &publishlogo($r,'upload',$formelem,$dom,$confname,
- "login/headtag/$lonhost",'','',
- $env{'form.loginheadtag_'.$lonhost.'.filename'});
+ (my $result,$newheadtagurls{$lonhost}) =
+ &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
+ "login/headtag/$lonhost",'','',
+ $env{'form.loginheadtag_'.$lonhost.'.filename'},
+ $modified);
if ($result eq 'ok') {
$loginhash{'login'}{'headtag'}{$lonhost}{'url'} = $newheadtagurls{$lonhost};
$changes{'headtag'}{$lonhost} = 1;
@@ -9253,6 +10972,7 @@ sub modify_login {
}
}
}
+ &update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of custom markup file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok);
}
@@ -9271,10 +10991,13 @@ sub modify_login {
if ($env{'form.saml_img_'.$lonhost.'.filename'}) {
push(@newsamlimgs,$lonhost);
}
- foreach my $item ('text','alt','url','title','notsso') {
+ foreach my $item ('text','alt','url','title','window','notsso') {
$env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;
}
if ($saml{$lonhost}) {
+ if ($env{'form.saml_window_'.$lonhost} ne '1') {
+ $env{'form.saml_window_'.$lonhost} = '';
+ }
if (grep(/^\Q$lonhost\E$/,@delsamlimg)) {
#FIXME Need to obsolete published image
delete($currsaml{$lonhost}{'img'});
@@ -9292,13 +11015,16 @@ sub modify_login {
if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
+ if ($env{'form.saml_window_'.$lonhost} ne $samlwindow{$lonhost}) {
+ $changes{'saml'}{$lonhost} = 1;
+ }
if ($env{'form.saml_notsso_'.$lonhost} ne $samlnotsso{$lonhost}) {
$changes{'saml'}{$lonhost} = 1;
}
} else {
$changes{'saml'}{$lonhost} = 1;
}
- foreach my $item ('text','alt','url','title','notsso') {
+ foreach my $item ('text','alt','url','title','window','notsso') {
$currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};
}
} else {
@@ -9321,11 +11047,14 @@ sub modify_login {
if ($switchserver) {
$error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);
} elsif ($author_ok eq 'ok') {
+ my $modified = [];
foreach my $lonhost (@newsamlimgs) {
my $formelem = 'saml_img_'.$lonhost;
- my ($result,$imgurl) = &publishlogo($r,'upload',$formelem,$dom,$confname,
- "login/saml/$lonhost",'','',
- $env{'form.saml_img_'.$lonhost.'.filename'});
+ my ($result,$imgurl) =
+ &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname,
+ "login/saml/$lonhost",'','',
+ $env{'form.saml_img_'.$lonhost.'.filename'},
+ $modified);
if ($result eq 'ok') {
$currsaml{$lonhost}{'img'} = $imgurl;
$loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;
@@ -9336,6 +11065,7 @@ sub modify_login {
$errors .= '
'.$puberror.'
';
}
}
+ &update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of SSO button image file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok);
}
@@ -9499,19 +11229,22 @@ sub modify_login {
alt => 'Alt text for button image',
url => 'SSO URL',
title => 'Tooltip for SSO link',
+ window => 'Pop-up window if iframe',
notsso => 'Text for non-SSO log-in',
);
foreach my $lonhost (sort(keys(%{$changes{$item}}))) {
if (ref($currsaml{$lonhost}) eq 'HASH') {
$resulttext .= '
'.&mt("$title{$item} in use for [_1]","$lonhost").
'
';
- foreach my $key ('text','img','alt','url','title','notsso') {
+ foreach my $key ('text','img','alt','url','title','window','notsso') {
if ($currsaml{$lonhost}{$key} eq '') {
$resulttext .= '
';
+ }
+ return $resulttext;
+}
+
+sub fetch_secrets {
+ my ($dom,$context,$domconfig,$currsec,$secchanges,$newsec,$newkeyset) = @_;
+ my %keyset;
+ %{$currsec} = ();
+ $newsec->{'private'}{'keys'} = [];
+ $newsec->{'encrypt'} = {};
+ $newsec->{'rules'} = {};
+ if ($context eq 'ltisec') {
+ $newsec->{'linkprot'} = {};
+ }
+ if (ref($domconfig->{$context}) eq 'HASH') {
+ %{$currsec} = %{$domconfig->{$context}};
+ if ($context eq 'ltisec') {
+ if (ref($currsec->{'linkprot'}) eq 'HASH') {
+ foreach my $id (keys(%{$currsec->{'linkprot'}})) {
+ unless ($id =~ /^\d+$/) {
+ delete($currsec->{'linkprot'}{$id});
+ }
+ }
+ }
+ }
+ if (ref($currsec->{'private'}) eq 'HASH') {
+ if (ref($currsec->{'private'}{'keys'}) eq 'ARRAY') {
+ $newsec->{'private'}{'keys'} = $currsec->{'private'}{'keys'};
+ map { $keyset{$_} = 1; } @{$currsec->{'private'}{'keys'}};
+ }
+ }
+ }
+ my @items= ('crs','dom');
+ if ($context eq 'ltisec') {
+ push(@items,'consumers');
+ }
+ foreach my $item (@items) {
+ my $formelement;
+ if (($context eq 'toolsec') || ($item eq 'consumers')) {
+ $formelement = 'form.'.$context.'_'.$item;
+ } else {
+ $formelement = 'form.'.$context.'_'.$item.'linkprot';
+ }
+ if ($env{$formelement}) {
+ $newsec->{'encrypt'}{$item} = 1;
+ if (ref($currsec->{'encrypt'}) eq 'HASH') {
+ unless ($currsec->{'encrypt'}{$item}) {
+ $secchanges->{'encrypt'} = 1;
+ }
+ } else {
+ $secchanges->{'encrypt'} = 1;
+ }
+ } elsif (ref($currsec->{'encrypt'}) eq 'HASH') {
+ if ($currsec->{'encrypt'}{$item}) {
+ $secchanges->{'encrypt'} = 1;
+ }
+ }
+ }
+ my $secrets;
+ if ($context eq 'ltisec') {
+ $secrets = 'ltisecrets';
+ } else {
+ $secrets = 'toolsecrets';
+ }
+ unless (exists($currsec->{'rules'})) {
+ $currsec->{'rules'} = {};
+ }
+ &password_rule_changes($secrets,$newsec->{'rules'},$currsec->{'rules'},$secchanges);
+
+ my @ids=&Apache::lonnet::current_machine_ids();
+ my %servers = &Apache::lonnet::get_servers($dom,'library');
+
+ foreach my $hostid (keys(%servers)) {
+ if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) {
+ my $keyitem = 'form.'.$context.'_privkey_'.$hostid;
+ if (exists($env{$keyitem})) {
+ $env{$keyitem} =~ s/(`)/'/g;
+ if ($keyset{$hostid}) {
+ if ($env{'form.'.$context.'_changeprivkey_'.$hostid}) {
+ if ($env{$keyitem} ne '') {
+ $secchanges->{'private'} = 1;
+ $newkeyset->{$hostid} = $env{$keyitem};
+ }
+ }
+ } elsif ($env{$keyitem} ne '') {
+ unless (grep(/^\Q$hostid\E$/,@{$newsec->{'private'}{'keys'}})) {
+ push(@{$newsec->{'private'}{'keys'}},$hostid);
+ }
+ $secchanges->{'private'} = 1;
+ $newkeyset->{$hostid} = $env{$keyitem};
+ }
+ }
+ }
+ }
+}
+
+sub store_security {
+ my ($dom,$context,$secchanges,$newkeyset,$keystore) = @_;
+ return unless ((ref($secchanges) eq 'HASH') && (ref($newkeyset) eq 'HASH') &&
+ (ref($keystore) eq 'HASH'));
+ if (keys(%{$secchanges})) {
+ if ($secchanges->{'private'}) {
+ my $who = &escape($env{'user.name'}.':'.$env{'user.domain'});
+ foreach my $hostid (keys(%{$newkeyset})) {
+ my $storehash = {
+ key => $newkeyset->{$hostid},
+ who => $env{'user.name'}.':'.$env{'user.domain'},
+ };
+ $keystore->{$hostid} = &Apache::lonnet::store_dom($storehash,$context,'private',
+ $dom,$hostid);
+ }
+ }
+ }
+}
+
+sub lti_security_results {
+ my ($dom,$context,$secchanges,$newsec,$newkeyset,$keystore) = @_;
+ my $output;
+ my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
+ my $needs_update;
+ foreach my $item (keys(%{$secchanges})) {
+ if ($item eq 'encrypt') {
+ $needs_update = 1;
+ my %encrypted;
+ if ($context eq 'lti') {
+ %encrypted = (
+ crs => {
+ on => &mt('Encryption of stored link protection secrets defined in courses enabled'),
+ off => &mt('Encryption of stored link protection secrets defined in courses disabled'),
+ },
+ dom => {
+ on => &mt('Encryption of stored link protection secrets defined in domain enabled'),
+ off => &mt('Encryption of stored link protection secrets defined in domain disabled'),
+ },
+ consumers => {
+ on => &mt('Encryption of stored consumer secrets defined in domain enabled'),
+ off => &mt('Encryption of stored consumer secrets defined in domain disabled'),
+ },
+ );
+ } else {
+ %encrypted = (
+ crs => {
+ on => &mt('Encryption of stored external tool secrets defined in courses enabled'),
+ off => &mt('Encryption of stored external tool secrets defined in courses disabled'),
+ },
+ dom => {
+ on => &mt('Encryption of stored external tool secrets defined in domain enabled'),
+ off => &mt('Encryption of stored external tool secrets defined in domain disabled'),
+ },
+ );
+
+ }
+ my @types= ('crs','dom');
+ if ($context eq 'lti') {
+ foreach my $type (@types) {
+ undef($domdefaults{'linkprotenc_'.$type});
+ }
+ push(@types,'consumers');
+ undef($domdefaults{'ltienc_consumers'});
+ } elsif ($context eq 'ltitools') {
+ foreach my $type (@types) {
+ undef($domdefaults{'toolenc_'.$type});
+ }
+ }
+ foreach my $type (@types) {
+ my $shown = $encrypted{$type}{'off'};
+ if (ref($newsec->{$item}) eq 'HASH') {
+ if ($newsec->{$item}{$type}) {
+ if ($context eq 'lti') {
+ if ($type eq 'consumers') {
+ $domdefaults{'ltienc_consumers'} = 1;
+ } else {
+ $domdefaults{'linkprotenc_'.$type} = 1;
+ }
+ } elsif ($context eq 'ltitools') {
+ $domdefaults{'toolenc_'.$type} = 1;
+ }
+ $shown = $encrypted{$type}{'on'};
+ }
+ }
+ $output .= '
'.$shown.'
';
+ }
+ } elsif ($item eq 'rules') {
+ my %titles = &Apache::lonlocal::texthash(
+ min => 'Minimum password length',
+ max => 'Maximum password length',
+ chars => 'Required characters',
+ );
+ foreach my $rule ('min','max') {
+ if ($newsec->{rules}{$rule} eq '') {
+ if ($rule eq 'min') {
+ $output .= '
'.&mt('[_1] not set.',$titles{$rule});
+ ' '.&mt('Default of [_1] will be used',
+ $Apache::lonnet::passwdmin).'
';
+ } else {
+ $output .= '
'.&mt('[_1] set to none',$titles{$rule}).'
';
+ }
+ } else {
+ $output .= '
'.&mt('[_1] set to [_2]',$titles{$rule},$newsec->{rules}{$rule}).'
';
+ }
+ }
+ if (ref($newsec->{'rules'}{'chars'}) eq 'ARRAY') {
+ if (@{$newsec->{'rules'}{'chars'}} > 0) {
+ 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',
+ );
+ my $needed = '
';
+ }
+ if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
+ if (@{$confhash{$itemid}{'makeuser'}} > 0) {
+ $resulttext .= '
'.&mt('Following roles may create user accounts: [_1]',
+ join(', ',@{$confhash{$itemid}{'makeuser'}})).' ';
+ if ($confhash{$itemid}{'lcauth'} eq 'lti') {
+ $resulttext .= &mt('New users will only be able to authenticate via LTI').'
'.&mt('Institutional data will be used when creating a new user for: [_1]',
+ join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'
';
+ } else {
+ $resulttext .= '
'.&mt('No institutional data used when creating a new user.').'
'.&mt('[_1] set to "[_2]"',$title->{$item},$value).'
';
- $mailmsgtext .= "$title->{$item} set to $value\n";
+ $mailmsgtext .= "$title->{$item} set to $value\n";
+ if ($item eq 'portal_def') {
+ if ($env{'form.'.$item} ne '') {
+ foreach my $field ('email','web') {
+ $value = $env{'form.'.$item.'_'.$field};
+ if ($value) {
+ $value = &mt('Yes');
+ } else {
+ $value = &mt('No');
+ }
+ $resulttext .= '
'.&mt('[_1] set to "[_2]"',$title->{$field},$value).'
';
+ }
+ }
+ }
}
}
$resulttext .= '
';
@@ -14611,12 +17456,15 @@ sub modify_scantron {
$error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver);
} else {
if ($author_ok eq 'ok') {
+ my $modified = [];
my ($result,$scantronurl) =
- &publishlogo($r,'upload','scantronformat',$dom,
- $confname,'scantron','','',$custom);
+ &Apache::lonconfigsettings::publishlogo($r,'upload','scantronformat',$dom,
+ $confname,'scantron','','',$custom,
+ $modified);
if ($result eq 'ok') {
$confhash{'scantron'}{'scantronformat'} = $scantronurl;
$changes{'scantronformat'} = 1;
+ &update_modify_urls($r,$modified);
} else {
$error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result);
}
@@ -14768,8 +17616,8 @@ sub modify_scantron {
$resulttext = &mt('No changes made to bubblesheet format settings');
}
if ($errors) {
- $resulttext .= &mt('The following errors occurred: ').'