[LON-CAPA-cvs] cvs: loncom /auth lonlogin.pm lonshibauth.pm /interface domainprefs.pm loncommon.pm lonconfigsettings.pm lonmenu.pm /lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Tue Sep 21 18:54:27 EDT 2021
raeburn Tue Sep 21 22:54:27 2021 EDT
Modified files:
/loncom/interface loncommon.pm lonconfigsettings.pm lonmenu.pm
domainprefs.pm
/loncom/auth lonlogin.pm lonshibauth.pm
/loncom/lonnet/perl lonnet.pm
Log:
- For SAML authentication (Shibboleth) config for each of domain's nodes
to set /adm/log-in as landing page for user toggle between SSO or non-SSO.
-------------- next part --------------
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1365 loncom/interface/loncommon.pm:1.1366
--- loncom/interface/loncommon.pm:1.1365 Sun Sep 5 05:55:50 2021
+++ loncom/interface/loncommon.pm Tue Sep 21 22:54:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1365 2021/09/05 05:55:50 raeburn Exp $
+# $Id: loncommon.pm,v 1.1366 2021/09/21 22:54:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -5745,6 +5745,17 @@
}
}
}
+ } elsif ($key eq 'saml') {
+ if (ref($domconfig{'login'}{$key}) eq 'HASH') {
+ foreach my $host (keys(%{$domconfig{'login'}{$key}})) {
+ if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') {
+ $designhash{$udom.'.login.'.$key.'_'.$host} = 1;
+ foreach my $item ('text','img','alt','url','title','notsso') {
+ $designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item};
+ }
+ }
+ }
+ }
} else {
foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
$designhash{$udom.'.login.'.$key.'_'.$img} =
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.52 loncom/interface/lonconfigsettings.pm:1.53
--- loncom/interface/lonconfigsettings.pm:1.52 Wed Sep 1 00:21:52 2021
+++ loncom/interface/lonconfigsettings.pm Tue Sep 21 22:54:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: lonconfigsettings.pm,v 1.52 2021/09/01 00:21:52 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.53 2021/09/21 22:54:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -266,6 +266,12 @@
if (grep(/^autoupdate$/, at actions)) {
$onload .= "toggleLastActiveDays('document.display');";
}
+ if (grep(/^login$/, at actions)) {
+ my %domservers = &Apache::lonnet::get_servers($dom);
+ foreach my $server (sort(keys(%domservers))) {
+ $onload .= "toggleSamlOptions(document.display,'$server');";
+ }
+ }
if ($onload) {
my %loaditems = (
'onload' => $onload,
Index: loncom/interface/lonmenu.pm
diff -u loncom/interface/lonmenu.pm:1.509 loncom/interface/lonmenu.pm:1.510
--- loncom/interface/lonmenu.pm:1.509 Fri Jul 16 01:14:14 2021
+++ loncom/interface/lonmenu.pm Tue Sep 21 22:54:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines to control the menu
#
-# $Id: lonmenu.pm,v 1.509 2021/07/16 01:14:14 raeburn Exp $
+# $Id: lonmenu.pm,v 1.510 2021/09/21 22:54:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -387,6 +387,13 @@
} else {
$menu{$position} .= '<li>'.&Apache::loncommon::top_nav_help('Help').'</li>';
}
+ } elsif ($$menuitem[3] eq 'Log In') {
+ if ($public) {
+ if (&Apache::lonnet::get_saml_landing()) {
+ $$menuitem[0] = '/adm/login';
+ }
+ }
+ $menu{$position} .= prep_menuitem($menuitem,$ltitarget);
} else {
$menu{$position} .= prep_menuitem($menuitem,$ltitarget);
}
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.385 loncom/interface/domainprefs.pm:1.386
--- loncom/interface/domainprefs.pm:1.385 Wed Sep 1 00:21:52 2021
+++ loncom/interface/domainprefs.pm Tue Sep 21 22:54:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set domain-wide configuration settings
#
-# $Id: domainprefs.pm,v 1.385 2021/09/01 00:21:52 raeburn Exp $
+# $Id: domainprefs.pm,v 1.386 2021/09/21 22:54:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -297,7 +297,10 @@
{col1 => 'Log-in Help',
col2 => 'Value'},
{col1 => 'Custom HTML in document head',
- col2 => 'Value'}],
+ col2 => 'Value'},
+ {col1 => 'SSO',
+ col2 => 'Dual login: SSO and non-SSO options'},
+ ],
print => \&print_login,
modify => \&modify_login,
},
@@ -632,7 +635,10 @@
{col1 => 'Log-in Help',
col2 => 'Value'},
{col1 => 'Custom HTML in document head',
- col2 => 'Value'}],
+ col2 => 'Value'},
+ {col1 => 'SSO',
+ col2 => 'Dual login: SSO and non-SSO options'},
+ ],
print => \&print_login,
modify => \&modify_login,
};
@@ -859,6 +865,8 @@
$output .= &wafproxy_javascript($dom);
} elsif ($action eq 'autoupdate') {
$output .= &autoupdate_javascript();
+ } elsif ($action eq 'login') {
+ $output .= &saml_javascript();
}
$output .=
'<table class="LC_nested_outer">
@@ -878,7 +886,7 @@
my $leftnobr = '';
if (($action eq 'rolecolors') || ($action eq 'defaults') ||
($action eq 'directorysrch') ||
- (($action eq 'login') && ($numheaders < 4))) {
+ (($action eq 'login') && ($numheaders < 5))) {
$colspan = ' colspan="2"';
}
if ($action eq 'usersessions') {
@@ -909,7 +917,7 @@
} elsif ($action eq 'scantron') {
$output .= $item->{'print'}->($r,'top',$dom,$confname,$settings,\$rowtotal);
} elsif ($action eq 'login') {
- if ($numheaders == 4) {
+ if ($numheaders == 5) {
$colspan = ' colspan="2"';
$output .= &print_login('service',$dom,$confname,$phase,$settings,\$rowtotal);
} else {
@@ -1050,7 +1058,7 @@
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
$item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
} elsif ($action eq 'login') {
- if ($numheaders == 4) {
+ if ($numheaders == 5) {
$output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
</table>
</td>
@@ -1074,7 +1082,7 @@
<td>
<table class="LC_nested">
<tr class="LC_info_row">';
- if ($numheaders == 4) {
+ if ($numheaders == 5) {
$output .= '
<td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
<td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td>
@@ -1086,7 +1094,27 @@
</tr>';
}
$rowtotal ++;
- $output .= &print_login('headtag',$dom,$confname,$phase,$settings,\$rowtotal);
+ $output .= &print_login('headtag',$dom,$confname,$phase,$settings,\$rowtotal).'
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table class="LC_nested">
+ <tr class="LC_info_row">';
+ if ($numheaders == 5) {
+ $output .= '
+ <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
+ <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
+ </tr>';
+ } else {
+ $output .= '
+ <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>';
+ }
+ $rowtotal ++;
+ $output .= &print_login('saml',$dom,$confname,$phase,$settings,\$rowtotal);
} elsif ($action eq 'requestcourses') {
$output .= &print_requestmail($dom,$action,$settings,\$rowtotal);
$rowtotal ++;
@@ -1221,9 +1249,12 @@
sub print_login {
my ($caller,$dom,$confname,$phase,$settings,$rowtotal) = @_;
- my ($css_class,$datatable);
+ my ($css_class,$datatable,$switchserver,%lt);
my %choices = &login_choices();
-
+ if (($caller eq 'help') || ($caller eq 'headtag') || ($caller eq 'saml')) {
+ %lt = &login_file_options();
+ $switchserver = &check_switchserver($dom,$confname);
+ }
if ($caller eq 'service') {
my %servers = &Apache::lonnet::internet_dom_servers($dom);
my $choice = $choices{'disallowlogin'};
@@ -1417,18 +1448,10 @@
$datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext);
$datatable .= '</tr></table></td></tr>';
} elsif ($caller eq 'help') {
- my ($defaulturl,$defaulttype,%url,%type,%lt,%langchoices);
- my $switchserver = &check_switchserver($dom,$confname);
+ my ($defaulturl,$defaulttype,%url,%type,%langchoices);
my $itemcount = 1;
$defaulturl = '/adm/loginproblems.html';
$defaulttype = 'default';
- %lt = &Apache::lonlocal::texthash (
- del => 'Delete?',
- rep => 'Replace:',
- upl => 'Upload:',
- default => 'Default',
- custom => 'Custom',
- );
%langchoices = &Apache::lonlocal::texthash(&get_languages_hash());
my @currlangs;
if (ref($settings) eq 'HASH') {
@@ -1525,14 +1548,6 @@
}
}
}
- my %lt = &Apache::lonlocal::texthash(
- del => 'Delete?',
- rep => 'Replace:',
- upl => 'Upload:',
- curr => 'View contents',
- none => 'None',
- );
- my $switchserver = &check_switchserver($dom,$confname);
foreach my $lonhost (sort(keys(%domservers))) {
my $exempt = &check_exempt_addresses($currexempt{$lonhost});
$datatable .= '<tr><td>'.$domservers{$lonhost}.'</td>';
@@ -1556,6 +1571,88 @@
$datatable .= '</td><td><input type="text" name="loginheadtagexempt_'.$lonhost.'" value="'.$exempt.'" /></td></tr>';
}
$datatable .= '</table></td></tr>';
+ } elsif ($caller eq 'saml') {
+ my %domservers = &Apache::lonnet::get_servers($dom);
+ $datatable .= '<tr><td colspan="3" style="text-align: left">'.
+ '<table><tr><th>'.$choices{'hostid'}.'</th>'.
+ '<th>'.$choices{'samllanding'}.'</th>'.
+ '<th>'.$choices{'samloptions'}.'</th></tr>'."\n";
+ my (%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlnotsso,%styleon,%styleoff);
+ foreach my $lonhost (keys(%domservers)) {
+ $samlurl{$lonhost} = '/adm/sso';
+ $styleon{$lonhost} = 'display:none';
+ $styleoff{$lonhost} = '';
+ }
+ if (ref($settings->{'saml'}) eq 'HASH') {
+ foreach my $lonhost (keys(%{$settings->{'saml'}})) {
+ if (ref($settings->{'saml'}{$lonhost}) eq 'HASH') {
+ $saml{$lonhost} = 1;
+ $samltext{$lonhost} = $settings->{'saml'}{$lonhost}{'text'};
+ $samlimg{$lonhost} = $settings->{'saml'}{$lonhost}{'img'};
+ $samlalt{$lonhost} = $settings->{'saml'}{$lonhost}{'alt'};
+ $samlurl{$lonhost} = $settings->{'saml'}{$lonhost}{'url'};
+ $samltitle{$lonhost} = $settings->{'saml'}{$lonhost}{'title'};
+ $samlnotsso{$lonhost} = $settings->{'saml'}{$lonhost}{'notsso'};
+ $styleon{$lonhost} = '';
+ $styleoff{$lonhost} = 'display:none';
+ } else {
+ $styleon{$lonhost} = 'display:none';
+ $styleoff{$lonhost} = '';
+ }
+ }
+ }
+ my $itemcount = 1;
+ foreach my $lonhost (sort(keys(%domservers))) {
+ my $samlon = ' ';
+ my $samloff = ' checked="checked" ';
+ if ($saml{$lonhost}) {
+ $samlon = $samloff;
+ $samloff = ' ';
+ }
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.$domservers{$lonhost}.'</span></td>'.
+ '<td><span class="LC_nobreak"><label><input type="radio" name="saml_'.$lonhost.'"'.$samloff.
+ 'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="0" />'.
+ &mt('No').'</label>'.(' 'x2).
+ '<label><input type="radio" name="saml_'.$lonhost.'"'.$samlon.
+ 'onclick="toggleSamlOptions(this.form,'."'$lonhost'".');" value="1" />'.
+ &mt('Yes').'</label></span></td>'.
+ '<td id="samloptionson_'.$lonhost.'" style="'.$styleon{$lonhost}.'" width="100%">'.
+ '<table><tr><th colspan="5" align="center">'.&mt('SSO').'</th><th align="center">'.
+ '<span class="LC_nobreak">'.&mt('Non-SSO').'</span></th></tr>'.
+ '<tr><th>'.&mt('Text').'</th><th>'.&mt('Image').'</th>'.
+ '<th>'.&mt('Alt Text').'</th><th>'.&mt('URL').'</th>'.
+ '<th>'.&mt('Tool Tip').'</th><th>'.&mt('Text').'</th></tr>'.
+ '<tr'.$css_class.'><td><input type="text" name="saml_text_'.$lonhost.'" size="8" value="'.
+ $samltext{$lonhost}.'" /></td><td>';
+ if ($samlimg{$lonhost}) {
+ $datatable .= '<img src="'.$samlimg{$lonhost}.'" /><br />'.
+ '<span class="LC_nobreak"><label>'.
+ '<input type="checkbox" name="saml_img_del" value="'.$lonhost.'" />'.
+ $lt{'del'}.'</label> '.$lt{'rep'}.'</span>';
+ } else {
+ $datatable .= $lt{'upl'};
+ }
+ $datatable .='<br />';
+ if ($switchserver) {
+ $datatable .= &mt('Upload to library server: [_1]',$switchserver);
+ } else {
+ $datatable .= '<input type="file" name="saml_img_'.$lonhost.'" />';
+ }
+ $datatable .= '</td>'.
+ '<td><input type="text" name="saml_alt_'.$lonhost.'" size="20" '.
+ 'value="'.$samlalt{$lonhost}.'" /></td>'.
+ '<td><input type="text" name="saml_url_'.$lonhost.'" size="8" '.
+ 'value="'.$samlurl{$lonhost}.'" /></td>'.
+ '<td><textarea name="saml_title_'.$lonhost.'" rows="3" cols="15">'.
+ $samltitle{$lonhost}.'</textarea></td>'.
+ '<td><input type="text" name="saml_notsso_'.$lonhost.'" size="8" '.
+ 'value="'.$samlnotsso{$lonhost}.'" /></td></tr>'.
+ '</table></td>'.
+ '<td id="samloptionsoff_'.$lonhost.'" style="'.$styleoff{$lonhost}.'" width="100%"> </td></tr>';
+ $itemcount ++;
+ }
+ $datatable .= '</table></td></tr>';
}
return $datatable;
}
@@ -1592,10 +1689,24 @@
headtag => "Custom markup",
action => "Action",
current => "Current",
+ samllanding => "Dual login?",
+ samloptions => "Options",
);
return %choices;
}
+sub login_file_options {
+ return &Apache::lonlocal::texthash(
+ del => 'Delete?',
+ rep => 'Replace:',
+ upl => 'Upload:',
+ curr => 'View contents',
+ default => 'Default',
+ custom => 'Custom',
+ none => 'None',
+ );
+}
+
sub print_rolecolors {
my ($phase,$role,$dom,$confname,$settings,$rowtotal) = @_;
my %choices = &color_font_choices();
@@ -3348,6 +3459,48 @@
ENDSCRIPT
}
+sub saml_javascript {
+ return <<"ENDSCRIPT";
+<script type="text/javascript">
+// <![CDATA[
+function toggleSamlOptions(form,hostid) {
+ var radioname = 'saml_'+hostid;
+ var tablecellon = 'samloptionson_'+hostid;
+ var tablecelloff = 'samloptionsoff_'+hostid;
+ var num = form.elements[radioname].length;
+ if (num) {
+ var setvis = '';
+ for (var i=0; i<num; i++) {
+ if (form.elements[radioname][i].checked) {
+ if (form.elements[radioname][i].value == '1') {
+ if (document.getElementById(tablecellon)) {
+ document.getElementById(tablecellon).style.display='';
+ }
+ if (document.getElementById(tablecelloff)) {
+ document.getElementById(tablecelloff).style.display='none';
+ }
+ setvis = 1;
+ }
+ break;
+ }
+ }
+ if (!setvis) {
+ if (document.getElementById(tablecellon)) {
+ document.getElementById(tablecellon).style.display='none';
+ }
+ if (document.getElementById(tablecelloff)) {
+ document.getElementById(tablecelloff).style.display='';
+ }
+ }
+ }
+ return;
+}
+// ]]>
+</script>
+
+ENDSCRIPT
+}
+
sub print_autoenroll {
my ($dom,$settings,$rowtotal) = @_;
my $autorun = &Apache::lonnet::auto_run(undef,$dom),
@@ -11251,12 +11404,14 @@
sub modify_login {
my ($r,$dom,$confname,$lastactref,%domconfig) = @_;
my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl,
- %curr_loginvia,%loginhash, at currlangs, at newlangs,$addedfile,%title, at offon);
+ %curr_loginvia,%loginhash, at currlangs, at newlangs,$addedfile,%title, at offon,
+ %currsaml,%saml,%samltext,%samlimg,%samlalt,%samlurl,%samltitle,%samlnotsso);
%title = ( coursecatalog => 'Display course catalog',
adminmail => 'Display administrator E-mail address',
helpdesk => 'Display "Contact Helpdesk" link',
newuser => 'Link for visitors to create a user account',
- loginheader => 'Log-in box header');
+ loginheader => 'Log-in box header',
+ saml => 'Dual SSO and non-SSO login');
@offon = ('off','on');
if (ref($domconfig{login}) eq 'HASH') {
if (ref($domconfig{login}{loginvia}) eq 'HASH') {
@@ -11264,6 +11419,20 @@
$curr_loginvia{$lonhost} = $domconfig{login}{loginvia}{$lonhost};
}
}
+ if (ref($domconfig{login}{'saml'}) eq 'HASH') {
+ foreach my $lonhost (keys(%{$domconfig{login}{'saml'}})) {
+ if (ref($domconfig{login}{'saml'}{$lonhost}) eq 'HASH') {
+ $currsaml{$lonhost} = $domconfig{login}{'saml'}{$lonhost};
+ $saml{$lonhost} = 1;
+ $samltext{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'text'};
+ $samlurl{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'url'};
+ $samlalt{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'alt'};
+ $samlimg{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'img'};
+ $samltitle{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'title'};
+ $samlnotsso{$lonhost} = $domconfig{login}{'saml'}{$lonhost}{'notsso'};
+ }
+ }
+ }
}
($errors,%colchanges) = &modify_colors($r,$dom,$confname,['login'],
\%domconfig,\%loginhash);
@@ -11510,6 +11679,86 @@
$errors .= '<li><span class="LC_error">'.$error.'</span></li>';
}
}
+ my @delsamlimg = &Apache::loncommon::get_env_multiple('form.saml_img_del');
+ my @newsamlimgs;
+ foreach my $lonhost (keys(%domservers)) {
+ if ($env{'form.saml_'.$lonhost}) {
+ if ($env{'form.saml_img_'.$lonhost.'.filename'}) {
+ push(@newsamlimgs,$lonhost);
+ }
+ foreach my $item ('text','alt','url','title','notsso') {
+ $env{'form.saml_'.$item.'_'.$lonhost} =~ s/^\s+|\s+$//g;
+ }
+ if ($saml{$lonhost}) {
+ if (grep(/^\Q$lonhost\E$/, at delsamlimg)) {
+#FIXME Need to obsolete published image
+ delete($currsaml{$lonhost}{'img'});
+ $changes{'saml'}{$lonhost} = 1;
+ }
+ if ($env{'form.saml_alt_'.$lonhost} ne $samlalt{$lonhost}) {
+ $changes{'saml'}{$lonhost} = 1;
+ }
+ if ($env{'form.saml_text_'.$lonhost} ne $samltext{$lonhost}) {
+ $changes{'saml'}{$lonhost} = 1;
+ }
+ if ($env{'form.saml_url_'.$lonhost} ne $samlurl{$lonhost}) {
+ $changes{'saml'}{$lonhost} = 1;
+ }
+ if ($env{'form.saml_title_'.$lonhost} ne $samltitle{$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') {
+ $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost};
+ }
+ } else {
+ delete($currsaml{$lonhost});
+ }
+ }
+ foreach my $posshost (keys(%currsaml)) {
+ unless (exists($domservers{$posshost})) {
+ delete($currsaml{$posshost});
+ }
+ }
+ %{$loginhash{'login'}{'saml'}} = %currsaml;
+ if (@newsamlimgs) {
+ my $error;
+ my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
+ if ($configuserok eq 'ok') {
+ if ($switchserver) {
+ $error = &mt("Upload of SSO Button Image is not permitted to this server: [_1].",$switchserver);
+ } elsif ($author_ok eq 'ok') {
+ 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'});
+ if ($result eq 'ok') {
+ $currsaml{$lonhost}{'img'} = $imgurl;
+ $loginhash{'login'}{'saml'}{$lonhost}{'img'} = $imgurl;
+ $changes{'saml'}{$lonhost} = 1;
+ } else {
+ my $puberror = &mt("Upload of SSO button image failed for [_1] because an error occurred publishing the file in RES space. Error was: [_2].",
+ $lonhost,$result);
+ $errors .= '<li><span class="LC_error">'.$puberror.'</span></li>';
+ }
+ }
+ } 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);
+ }
+ } else {
+ $error = &mt("Upload of SSO button image file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2]. Error was: [_3].",$confname,$dom,$configuserok);
+ }
+ if ($error) {
+ &Apache::lonnet::logthis($error);
+ $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
+ }
+ }
&process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'});
my $defaulthelpfile = '/adm/loginproblems.html';
@@ -11550,6 +11799,31 @@
}
if (keys(%changes) > 0 || $colchgtext) {
&Apache::loncommon::devalidate_domconfig_cache($dom);
+ if (exists($changes{'saml'})) {
+ my $hostid_in_use;
+ my @hosts = &Apache::lonnet::current_machine_ids();
+ if (@hosts > 1) {
+ foreach my $hostid (@hosts) {
+ if (&Apache::lonnet::host_domain($hostid) eq $dom) {
+ $hostid_in_use = $hostid;
+ last;
+ }
+ }
+ } else {
+ $hostid_in_use = $r->dir_config('lonHostID');
+ }
+ if (($hostid_in_use) &&
+ (&Apache::lonnet::host_domain($hostid_in_use) eq $dom)) {
+ &devalidate_cache_new('samllanding',$hostid_in_use);
+ }
+ if (ref($lastactref) eq 'HASH') {
+ if (ref($changes{'saml'}) eq 'HASH') {
+ my %updates;
+ map { $updates{$_} = 1; } keys(%{$changes{'saml'}});
+ $lastactref->{'samllanding'} = \%updates;
+ }
+ }
+ }
if (ref($lastactref) eq 'HASH') {
$lastactref->{'domainconfig'} = 1;
}
@@ -11629,6 +11903,38 @@
}
}
}
+ } elsif ($item eq 'saml') {
+ if (ref($changes{$item}) eq 'HASH') {
+ my %notlt = (
+ text => 'Text for log-in by SSO',
+ img => 'SSO button image',
+ alt => 'Alt text for button image',
+ url => 'SSO URL',
+ title => 'Tooltip for SSO link',
+ notsso => 'Text for non-SSO log-in',
+ );
+ foreach my $lonhost (sort(keys(%{$changes{$item}}))) {
+ if (ref($currsaml{$lonhost}) eq 'HASH') {
+ $resulttext .= '<li>'.&mt("$title{$item} in use for [_1]","<b>$lonhost</b>").
+ '<ul>';
+ foreach my $key ('text','img','alt','url','title','notsso') {
+ if ($currsaml{$lonhost}{$key} eq '') {
+ $resulttext .= '<li>'.&mt("$notlt{$key} not in use").'</li>';
+ } else {
+ my $value = "'$currsaml{$lonhost}{$key}'";
+ if ($key eq 'img') {
+ $value = '<img src="'.$currsaml{$lonhost}{$key}.'" />';
+ }
+ $resulttext .= '<li>'.&mt("$notlt{$key} set to: [_1]",
+ $value).'</li>';
+ }
+ }
+ $resulttext .= '</ul></li>';
+ } else {
+ $resulttext .= '<li>'.&mt("$title{$item} not in use for [_1]",$lonhost).'</li>';
+ }
+ }
+ }
} elsif ($item eq 'captcha') {
if (ref($loginhash{'login'}) eq 'HASH') {
my $chgtxt;
@@ -21913,6 +22219,25 @@
map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',
'directorysrch','passwdconf','cats','proxyalias');
+ my %cache_by_lonhost;
+ if (exists($cachekeys->{'samllanding'})) {
+ if (ref($cachekeys->{'samllanding'}) eq 'HASH') {
+ my %landing = %{$cachekeys->{'samllanding'}};
+ my %domservers = &Apache::lonnet::get_servers($dom);
+ if (keys(%domservers)) {
+ foreach my $server (keys(%domservers)) {
+ my @cached;
+ next if ($thismachine{$server});
+ if ($landing{$server}) {
+ push(@cached,&escape('samllanding').':'.&escape($server));
+ }
+ if (@cached) {
+ $cache_by_lonhost{$server} = \@cached;
+ }
+ }
+ }
+ }
+ }
if (keys(%servers)) {
foreach my $server (keys(%servers)) {
next if ($thismachine{$server});
@@ -21920,7 +22245,7 @@
foreach my $name (@posscached) {
if ($cachekeys->{$name}) {
if ($name eq 'proxyalias') {
- if (ref($cachekeys->{$name}) eq 'HASH') {
+ if (ref($cachekeys->{$name}) eq 'HASH') {
foreach my $key (keys(%{$cachekeys->{$name}})) {
push(@cached,&escape($name).':'.&escape($key));
}
@@ -21930,6 +22255,10 @@
}
}
}
+ if ((exists($cache_by_lonhost{$server})) &&
+ (ref($cache_by_lonhost{$server}) eq 'ARRAY')) {
+ push(@cached,@{$cache_by_lonhost{$server}});
+ }
if (@cached) {
&Apache::lonnet::remote_devalidate_cache($server,\@cached);
}
Index: loncom/auth/lonlogin.pm
diff -u loncom/auth/lonlogin.pm:1.183 loncom/auth/lonlogin.pm:1.184
--- loncom/auth/lonlogin.pm:1.183 Mon May 3 15:27:44 2021
+++ loncom/auth/lonlogin.pm Tue Sep 21 22:54:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Login Screen
#
-# $Id: lonlogin.pm,v 1.183 2021/05/03 15:27:44 raeburn Exp $
+# $Id: lonlogin.pm,v 1.184 2021/09/21 22:54:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -47,7 +47,7 @@
(join('&',$ENV{'QUERY_STRING'},$env{'request.querystring'},
$ENV{'REDIRECT_QUERY_STRING'}),
['interface','username','domain','firsturl','localpath','localres',
- 'token','role','symb','iptoken','btoken','ltoken','linkkey']);
+ 'token','role','symb','iptoken','btoken','ltoken','linkkey','saml']);
if (!defined($env{'form.firsturl'})) {
&Apache::lonacc::get_posted_cgi($r,['firsturl']);
}
@@ -581,17 +581,9 @@
ENDSCRIPT
-# --------------------------------------------------- Print login screen header
-
- my %add_entries = (
- bgcolor => "$mainbg",
- text => "$font",
- link => "$link",
- vlink => "$vlink",
- alink => "$alink",
- onload => 'javascript:enableInput();',);
-
- my ($lonhost_in_use,$headextra,$headextra_exempt, at hosts,%defaultdomconf);
+ my ($lonhost_in_use, at hosts,%defaultdomconf,$saml_prefix,$saml_landing,
+ $samlssotext,$samlnonsso,$samlssoimg,$samlssoalt,$samlssourl,$samltooltip);
+ %defaultdomconf = &Apache::loncommon::get_domainconf($defdom);
@hosts = &Apache::lonnet::current_machine_ids();
$lonhost_in_use = $lonhost;
if (@hosts > 1) {
@@ -602,7 +594,67 @@
}
}
}
- %defaultdomconf = &Apache::loncommon::get_domainconf($defdom);
+ $saml_prefix = $defdom.'.login.saml_';
+ if ($defaultdomconf{$saml_prefix.$lonhost_in_use}) {
+ $saml_landing = 1;
+ $samlssotext = $defaultdomconf{$saml_prefix.'text_'.$lonhost_in_use};
+ $samlnonsso = $defaultdomconf{$saml_prefix.'notsso_'.$lonhost_in_use};
+ $samlssoimg = $defaultdomconf{$saml_prefix.'img_'.$lonhost_in_use};
+ $samlssoalt = $defaultdomconf{$saml_prefix.'alt_'.$lonhost_in_use};
+ $samlssourl = $defaultdomconf{$saml_prefix.'url_'.$lonhost_in_use};
+ $samltooltip = $defaultdomconf{$saml_prefix.'title_'.$lonhost_in_use};
+ }
+ if ($saml_landing) {
+ if ($samlssotext eq '') {
+ $samlssotext = 'SSO Login';
+ }
+ if ($samlnonsso eq '') {
+ $samlnonsso = 'Non-SSO Login';
+ }
+ $js .= <<"ENDSAMLJS";
+
+<script type="text/javascript">
+// <![CDATA[
+function toggleLClogin() {
+ if (document.getElementById('LC_standard_login')) {
+ if (document.getElementById('LC_standard_login').style.display == 'none') {
+ document.getElementById('LC_standard_login').style.display = 'inline-block';
+ if (document.getElementById('LC_login_text')) {
+ document.getElementById('LC_login_text').innerHTML = '$samlnonsso';
+ }
+ if (document.getElementById('LC_SSO_login')) {
+ document.getElementById('LC_SSO_login').style.display = 'none';
+ }
+ } else {
+ document.getElementById('LC_standard_login').style.display = 'none';
+ if (document.getElementById('LC_login_text')) {
+ document.getElementById('LC_login_text').innerHTML = '$samlssotext';
+ }
+ if (document.getElementById('LC_SSO_login')) {
+ document.getElementById('LC_SSO_login').style.display = 'inline-block';
+ }
+ }
+ }
+ return;
+}
+
+// ]]>
+</script>
+
+ENDSAMLJS
+ }
+
+# --------------------------------------------------- Print login screen header
+
+ my %add_entries = (
+ bgcolor => "$mainbg",
+ text => "$font",
+ link => "$link",
+ vlink => "$vlink",
+ alink => "$alink",
+ onload => 'javascript:enableInput();',);
+
+ my ($headextra,$headextra_exempt, at hosts,%defaultdomconf);
$headextra = $defaultdomconf{$defdom.'.login.headtag_'.$lonhost_in_use};
$headextra_exempt = $defaultdomconf{$domain.'.login.headtag_exempt_'.$lonhost_in_use};
if ($headextra) {
@@ -647,6 +699,7 @@
'helpdesk' => 'Contact Helpdesk',
'forgotpw' => 'Forgot password?',
'newuser' => 'New User?',
+ 'change' => 'Change?',
);
# -------------------------------------------------- Change password field name
@@ -708,7 +761,7 @@
$mobileargs = 'autocapitalize="off" autocorrect="off"';
}
my $loginform=(<<LFORM);
-<form name="client" action="" onsubmit="return(send())">
+<form name="client" action="" onsubmit="return(send())" id="lclogin">
<input type="hidden" name="lextkey" value="$lextkey" />
<input type="hidden" name="uextkey" value="$uextkey" />
<b><label for="uname">$lt{'un'}</label>:</b><br />
@@ -729,8 +782,56 @@
</div>
HEADER
}
- $r->print(<<ENDTOP);
-<div style="float:left;margin-top:0;">
+
+ my $stdauthformstyle = 'inline-block';
+ my $ssoauthstyle = 'none';
+ my $logintype;
+ $r->print('<div style="float:left;margin-top:0;">');
+ if ($saml_landing) {
+ $ssoauthstyle = 'inline-block';
+ $stdauthformstyle = 'none';
+ $logintype = $samlssotext;
+ my $ssologin = '/adm/sso';
+ if ($samlssourl ne '') {
+ $ssologin = $samlssourl;
+ }
+ my $ssohref;
+ if ($samlssoimg ne '') {
+ $ssohref = '<a href="'.$ssologin.'" title="'.$samltooltip.'"><img src="'.$samlssoimg.'" alt="'.$samlssoalt.'" /></a>';
+ } else {
+ $ssohref = '<a href="'.$ssologin.'">'.$samlssotext.'</a>';
+ }
+ if ($env{'form.firsturl'}) {
+ $ssologin .= '?origurl='.&HTML::Entities::encode($env{'form.firsturl'},'<>&"');
+ }
+ if (($env{'form.saml'} eq 'no') ||
+ (($env{'form.username'} ne '') && ($env{'form.domain'} ne ''))) {
+ $ssoauthstyle = 'none';
+ $stdauthformstyle = 'inline-block';
+ $logintype = $samlnonsso;
+ }
+ $r->print(<<ENDSAML);
+<p>
+Log-in type:
+<span style="font-weight:bold" id="LC_login_text">$logintype</span><br />
+<span><a href="javascript:toggleLClogin();" style="color:#000000">$lt{'change'}</a></span>
+</p>
+<div style="display:$ssoauthstyle" id="LC_SSO_login">
+<div class="LC_Box" style="padding-top: 10px;">
+$ssohref
+$noscript_warning
+</div>
+<div class="LC_Box" style="padding-top: 10px;">
+$loginhelp
+$contactblock
+$coursecatalog
+</div>
+</div>
+ENDSAML
+ }
+
+ $r->print(<<ENDLOGIN);
+<div style="display:$stdauthformstyle;" id="LC_standard_login">
<div class="LC_Box" style="background:$loginbox_bg;">
$logintitle
$loginform
@@ -746,8 +847,8 @@
</div>
</div>
-<div>
-ENDTOP
+ENDLOGIN
+ $r->print('</div><div>'."\n");
if ($showmainlogo) {
$r->print(' <img src="'.$logo.'" alt="" class="LC_maxwidth" />'."\n");
}
Index: loncom/auth/lonshibauth.pm
diff -u loncom/auth/lonshibauth.pm:1.5 loncom/auth/lonshibauth.pm:1.6
--- loncom/auth/lonshibauth.pm:1.5 Tue Jun 22 16:56:35 2021
+++ loncom/auth/lonshibauth.pm Tue Sep 21 22:54:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Redirect Shibboleth authentication to designated URL (/adm/sso).
#
-# $Id: lonshibauth.pm,v 1.5 2021/06/22 16:56:35 raeburn Exp $
+# $Id: lonshibauth.pm,v 1.6 2021/09/21 22:54:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -74,8 +74,11 @@
sub handler {
my $r = shift;
my $target = '/adm/sso';
+ if (&Apache::lonnet::get_saml_landing()) {
+ $target = '/adm/login';
+ }
my $uri = $r->uri;
- if (($r->user eq '') && ($uri ne $target)) {
+ if (($r->user eq '') && ($uri ne $target) && ($uri ne '/adm/sso')) {
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
my $hostname = &Apache::lonnet::hostname($lonhost);
if (!$hostname) { $hostname = $r->hostname(); }
@@ -88,10 +91,8 @@
if ($ENV{'QUERY_STRING'} ne '') {
$dest .= '?'.$ENV{'QUERY_STRING'};
}
- if ($uri ne '/adm/roles/') {
- unless ($ENV{'QUERY_STRING'} =~ /origurl=/) {
- $dest.=(($dest=~/\?/)?'&':'?').'origurl='.$uri;
- }
+ unless (($uri eq '/adm/roles') || ($ENV{'QUERY_STRING'} =~ /origurl=/)) {
+ $dest.=(($dest=~/\?/)?'&':'?').'origurl='.$uri;
}
$r->header_out(Location => $dest);
return REDIRECT;
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1464 loncom/lonnet/perl/lonnet.pm:1.1465
--- loncom/lonnet/perl/lonnet.pm:1.1464 Fri Aug 13 20:32:23 2021
+++ loncom/lonnet/perl/lonnet.pm Tue Sep 21 22:54:27 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1464 2021/08/13 20:32:23 raeburn Exp $
+# $Id: lonnet.pm,v 1.1465 2021/09/21 22:54:27 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -14619,6 +14619,52 @@
return;
}
+sub get_saml_landing {
+ my ($lonid) = @_;
+ if ($lonid eq '') {
+ my $defdom = &default_login_domain();
+ my @hosts = ¤t_machine_ids();
+ if (@hosts > 1) {
+ foreach my $hostid (@hosts) {
+ if (&host_domain($hostid) eq $defdom) {
+ $lonid = $hostid;
+ last;
+ }
+ }
+ } else {
+ $lonid = $perlvar{'lonHostID'};
+ }
+ if ($lonid) {
+ unless (&Apache::lonnet::host_domain($lonid) eq $defdom) {
+ return;
+ }
+ } else {
+ return;
+ }
+ } elsif (!defined(&hostname($lonid))) {
+ return;
+ }
+ my ($landing,$cached) = &is_cached_new('samllanding',$lonid);
+ if ($cached) {
+ return $landing;
+ }
+ my $dom = &Apache::lonnet::host_domain($lonid);
+ if ($dom ne '') {
+ my $cachetime = 60*60*24;
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['login'],$dom);
+ if (ref($domconfig{'login'}) eq 'HASH') {
+ if (ref($domconfig{'login'}{'saml'}) eq 'HASH') {
+ if (ref($domconfig{'login'}{'saml'}{$lonid}) eq 'HASH') {
+ $landing = 1;
+ }
+ }
+ }
+ return &do_cache_new('samllanding',$lonid,$landing,$cachetime);
+ }
+ return;
+}
+
# ------------------------------------------------------------- Declutters URLs
sub declutter {
More information about the LON-CAPA-cvs
mailing list