version 1.9, 2021/10/07 19:24:25
|
version 1.18, 2023/06/02 01:20:26
|
Line 1
|
Line 1
|
# The LearningOnline Network |
# The LearningOnline Network |
# Redirect Shibboleth authentication to designated URL (/adm/sso). |
# Redirect Single Sign On authentication to designated URL: |
|
# /adm/sso, by default. |
# |
# |
# $Id$ |
# $Id$ |
# |
# |
Line 28
|
Line 29
|
|
|
=head1 NAME |
=head1 NAME |
|
|
Apache::lonshibauth - Redirect Shibboleth authentication |
Apache::lonshibauth - Redirect Single Sign On authentication |
|
|
=head1 SYNOPSIS |
=head1 SYNOPSIS |
|
|
Invoked when lonOtherAuthen is set to yes, and type is Shibboleth |
Invoked when an Apache config file includes: |
|
PerlAuthenHandler Apache::lonshibauth |
|
|
If server is configured as a Shibboleth SP, the main Apache |
If server is configured as a Shibboleth SP, the main Apache |
configuration file, e.g., /etc/httpd/conf/httpd.conf |
configuration file, e.g., /etc/httpd/conf/httpd.conf |
(for RHEL/CentOS/Scentific Linux/Fedora) should contain: |
(for RHEL/CentOS/Scentific Linux/Fedora) should contain: |
|
|
LoadModule mod_shib /usr/lib/shibboleth/mod_shib_22.so |
LoadModule mod_shib /usr/lib/shibboleth/mod_shib_22.so |
Line 43 LoadModule mod_shib /usr/lib/shibboleth/
|
Line 45 LoadModule mod_shib /usr/lib/shibboleth/
|
or equivalent (depending on Apache version) |
or equivalent (depending on Apache version) |
before the line to include conf/loncapa_apache.conf |
before the line to include conf/loncapa_apache.conf |
|
|
|
If some other Apache module is in use for Single Sign On |
|
authentication e.g., mod_auth_cas or mod_sentinel, |
|
then a separate config file should be created which |
|
includes settings for the authentication module. |
|
|
=head1 INTRODUCTION |
=head1 INTRODUCTION |
|
|
Redirects a user requiring Single Sign On via Shibboleth to a |
Redirects a user requiring Single Sign On to a URL on the server |
URL -- /adm/sso -- on the server which is configured to use that service. |
which is configured to use that service. The default URL is: |
|
/adm/sso. |
|
|
|
If this is to be used with a Single Sign On service other Shibboleth |
|
then an Apache config file needs to be loaded which: |
|
|
|
(a) loads the corresponding Apache module, and |
|
(b) sets appropriate values for perl vars in |
|
an <IfModule mod_***></IfModule> block, and |
|
(c) sets an appropriate value for AuthType in a |
|
<Location /adm/sso><IfModule mod_***> |
|
</IfModule></Location> block, which also contains |
|
|
|
require valid-user |
|
|
|
PerlAuthzHandler Apache::lonshibacc |
|
|
|
PerlAuthzHandler Apache::lonacc |
|
|
|
In the case of Shibboleth no additional file is needed |
|
because loncapa_apache.conf already contains: |
|
|
|
<IfModule mod_shib> |
|
PerlAuthenHandler Apache::lonshibauth |
|
PerlSetVar lonOtherAuthen yes |
|
PerlSetVar lonOtherAuthenType Shibboleth |
|
|
|
</IfModule> |
|
|
|
and |
|
|
|
<Location /adm/sso> |
|
Header set Cache-Control "private,no-store,no-cache,max-age=0" |
|
<IfModule mod_shib> |
|
AuthType shibboleth |
|
ShibUseEnvironment On |
|
ShibRequestSetting requireSession 1 |
|
ShibRequestSetting redirectToSSL 443 |
|
require valid-user |
|
PerlAuthzHandler Apache::lonshibacc |
|
PerlAuthzHandler Apache::lonacc |
|
ErrorDocument 403 /adm/login |
|
ErrorDocument 500 /adm/errorhandler |
|
</IfModule> |
|
<IfModule !mod_shib> |
|
PerlTypeHandler Apache::lonnoshib |
|
</IfModule> |
|
|
|
</Location> |
|
|
|
If the service is not Shibboleth, then (optionally) a URL that is |
|
not /adm/sso can be used as the URL for the service, e.g., /adm/cas |
|
or /adm/sentinel, by setting a lonOtherAuthenUrl perl var |
|
in an Apache config file containing (for example): |
|
|
|
PerlSetVar lonOtherAuthenUrl /adm/sentinel |
|
|
|
<IfModule mod_sentinel> |
|
PerlAuthenHandler Apache::lonshibauth |
|
PerlSetVar lonOtherAuthen yes |
|
PerlSetVar lonOtherAuthenType Sentinel |
|
|
|
</IfModule> |
|
|
|
<Location /adm/sentinel> |
|
Header set Cache-Control "private,no-store,no-cache,max-age=0" |
|
<IfModule mod_sentinel> |
|
AuthType Sentinel |
|
require valid-user |
|
PerlAuthzHandler Apache::lonshibacc |
|
PerlAuthzHandler Apache::lonacc |
|
ErrorDocument 403 /adm/login |
|
ErrorDocument 500 /adm/errorhandler |
|
</IfModule> |
|
<IfModule !mod_sentinel> |
|
PerlTypeHandler Apache::lonnoshib |
|
</IfModule> |
|
|
|
</Location> |
|
|
|
In the example above for Sentinel SSO, it would also be possible to |
|
use /adm/sso instead of /adm/sentinel, in which case (i) there would be |
|
no need to define lonOtherAuthenUrl, (ii) there would be <Location /adm/sso> |
|
and (iii) the <IfModule !></IfModule> block would not be needed as |
|
it is already present in /etc/httpd/conf/loncapa_apache.conf. |
|
|
=head1 HANDLER SUBROUTINE |
=head1 HANDLER SUBROUTINE |
|
|
Line 54 This routine is called by Apache and mod
|
Line 145 This routine is called by Apache and mod
|
|
|
=over 4 |
=over 4 |
|
|
If $r->user defined and requested uri not /adm/sso |
If $r->user is defined and requested URL is not /adm/sso or |
redirect to /adm/sso |
other specific URL as set by a lonOtherAuthenUrl perlvar, |
|
then redirect to /adm/sso (or to the specific URL). |
|
|
|
Otherwise return DECLINED. |
|
|
|
In the case of redirection a query string is appended, |
|
which will contain either (a) the originally requested URL, |
|
if not /adm/sso (or lonOtherAuthenUrl URL), and |
|
any existing query string in the original request, or |
|
(b) if original request was for /tiny/domain/uniqueID, |
|
or if redirect is to /adm/login to support dual SSO and |
|
non-SSO, a query string which contains sso=tokenID, where the |
|
token contains information for deep-linking to course/resource. |
|
|
|
Support is included for use of LON-CAPA's standard log-in |
|
page -- /adm/login -- to support dual SSO and non-SSO |
|
authentication from that "landing" page. |
|
|
|
To enable dual SSO and non-SSO access from /adm/login |
|
a Domain Coordinator will use the web GUI: |
|
Main Menu > Set domain configuration > Display |
|
("Log-in page options" checked) |
|
and for any of the LON-CAPA domain's servers which |
|
will offer dual login will check "Yes" and then set: |
|
(a) SSO Text, Image, Alt Text, URL, Tool Tip |
|
(b) non-SSO: Text |
|
|
|
The value in the URL field should be /adm/sso, |
|
or the same URL as set for the lonOtherAuthenUrl |
|
perl var, e.g., /adm/sentinel. |
|
|
Otherwise return DECLINED |
=back |
|
|
|
=head1 NOTABLE SUBROUTINES |
|
|
|
=over 4 |
|
|
|
=item set_token() |
|
|
|
Inputs: 2 |
|
$r - request object |
|
$lonhost - hostID of current server |
|
|
|
Output: 1 |
|
$querystring - query string to append to URL |
|
when redirecting. |
|
|
|
If any of the following items are present in the original query string: |
|
role, symb, and linkkey, then they will be stored in the token file |
|
on the server, for access later to support deep-linking. If the ltoken |
|
item is available, from successful launch from an LTI Consumer where |
|
LON-CAPA is the LTI Provider, but not configured to accept user |
|
information, and the destination is a deep-link URL /tiny/domain/uniqueiD, |
|
then the LTI number, type (c or d), and tiny URL will be saved as the |
|
linkprot item in a token file. |
|
|
|
=item set_mailtoken() |
|
|
|
Inputs: 2 |
|
$r - request object |
|
$lonhost - hostID of current server |
|
|
|
Output: 1 |
|
$querystring - query string to append to URL |
|
when redirecting. |
|
|
|
Called if requested URL is /adm/email, dual SSO and non-SSO login |
|
are supported by /adm/login and original query string contains values |
|
for elements: display, username and domain, which will then be |
|
stored in the token file on the server to support direct access |
|
to a specific message sent to the user. |
|
|
=back |
=back |
|
|
Line 68 package Apache::lonshibauth;
|
Line 227 package Apache::lonshibauth;
|
use strict; |
use strict; |
use lib '/home/httpd/lib/perl/'; |
use lib '/home/httpd/lib/perl/'; |
use Apache::lonnet; |
use Apache::lonnet; |
|
use Apache::loncommon; |
|
use Apache::lonacc; |
use Apache::Constants qw(:common REDIRECT); |
use Apache::Constants qw(:common REDIRECT); |
use LONCAPA qw(:DEFAULT); |
use LONCAPA qw(:DEFAULT :match); |
|
|
sub handler { |
sub handler { |
my $r = shift; |
my $r = shift; |
my $target = '/adm/sso'; |
my $ssourl = '/adm/sso'; |
|
if ($r->dir_config('lonOtherAuthenUrl') ne '') { |
|
$ssourl = $r->dir_config('lonOtherAuthenUrl'); |
|
} |
|
my $target = $ssourl; |
if (&Apache::lonnet::get_saml_landing()) { |
if (&Apache::lonnet::get_saml_landing()) { |
$target = '/adm/login'; |
$target = '/adm/login'; |
} |
} |
my $uri = $r->uri; |
if (($r->user eq '') && ($r->uri ne $target) && ($r->uri ne $ssourl)) { |
if (($r->user eq '') && ($uri ne $target) && ($uri ne '/adm/sso')) { |
|
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; |
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; |
my $hostname = &Apache::lonnet::hostname($lonhost); |
my $hostname = &Apache::lonnet::hostname($lonhost); |
if (!$hostname) { $hostname = $r->hostname(); } |
if (!$hostname) { $hostname = $r->hostname(); } |
Line 86 sub handler {
|
Line 250 sub handler {
|
unless ($protocol eq 'https') { $protocol = 'http'; } |
unless ($protocol eq 'https') { $protocol = 'http'; } |
my $alias = &Apache::lonnet::use_proxy_alias($r,$lonhost); |
my $alias = &Apache::lonnet::use_proxy_alias($r,$lonhost); |
if (($alias ne '') && |
if (($alias ne '') && |
(&Apache::lonnet::alias_shibboleth($lonhost))) { |
(&Apache::lonnet::alias_sso($lonhost))) { |
$hostname = $alias; |
$hostname = $alias; |
} |
} |
my $dest = $protocol.'://'.$hostname.$target; |
my $dest = $protocol.'://'.$hostname.$target; |
$r->subprocess_env; |
if ($target eq '/adm/login') { |
if ($ENV{'QUERY_STRING'} ne '') { |
my $uri = $r->uri; |
$dest .= '?'.$ENV{'QUERY_STRING'}; |
my $querystring; |
} |
if (($uri eq '/adm/email') && ($r->args ne '')) { |
unless (($uri eq '/adm/roles') || ($uri eq '/adm/logout')) { |
$querystring = &set_mailtoken($r,$lonhost); |
if ($target eq '/adm/login') { |
} else { |
unless ($ENV{'QUERY_STRING'} =~ /firsturl=/) { |
$querystring = &set_token($r,$lonhost); |
$dest.=(($dest=~/\?/)?'&':'?').'firsturl='.$uri; |
} |
|
if ($querystring ne '') { |
|
$dest .= '?'.$querystring; |
|
} |
|
} else { |
|
my $uri = $r->uri; |
|
if ($uri =~ m{^/tiny/$match_domain/\w+$}) { |
|
my $querystring = &set_token($r,$lonhost); |
|
if ($querystring ne '') { |
|
$dest .= '?'.$querystring; |
|
} |
|
} elsif ((&Apache::lonnet::get_saml_landing()) && |
|
($uri eq '/adm/email') && ($r->args ne '')) { |
|
my $querystring = &set_mailtoken($r,$lonhost); |
|
if ($querystring ne '') { |
|
$dest .= '?'.$querystring; |
} |
} |
} else { |
} else { |
unless ($ENV{'QUERY_STRING'} =~ /origurl=/) { |
if ($r->args ne '') { |
$dest.=(($dest=~/\?/)?'&':'?').'origurl='.$uri; |
$dest .= (($dest=~/\?/)?'&':'?').$r->args; |
|
} |
|
unless (($uri eq '/adm/roles') || ($uri eq '/adm/logout')) { |
|
unless ($r->args =~ /origurl=/) { |
|
$dest.=(($dest=~/\?/)?'&':'?').'origurl='.$uri; |
|
} |
} |
} |
} |
} |
} |
} |
Line 112 sub handler {
|
Line 296 sub handler {
|
} |
} |
} |
} |
|
|
|
sub set_token { |
|
my ($r,$lonhost) = @_; |
|
my ($firsturl,$querystring,$ssotoken,@names,%token); |
|
@names = ('role','symb','ltoken','linkkey'); |
|
map { $token{$_} = 1; } @names; |
|
unless (($r->uri eq '/adm/roles') || ($r->uri eq '/adm/logout')) { |
|
$firsturl = $r->uri; |
|
} |
|
if ($r->args ne '') { |
|
&Apache::loncommon::get_unprocessed_cgi($r->args); |
|
} |
|
if ($r->uri =~ m{^/tiny/$match_domain/\w+$}) { |
|
if ($env{'form.ttoken'}) { |
|
my %info = &Apache::lonnet::tmpget($env{'form.ttoken'}); |
|
&Apache::lonnet::tmpdel($env{'form.ttoken'}); |
|
if ($info{'ltoken'}) { |
|
$env{'form.ltoken'} = $info{'ltoken'}; |
|
} elsif ($info{'linkkey'} ne '') { |
|
$env{'form.linkkey'} = $info{'linkkey'}; |
|
} |
|
} else { |
|
unless (($env{'form.ltoken'}) || ($env{'form.linkkey'})) { |
|
&Apache::lonacc::get_posted_cgi($r,['linkkey']); |
|
} |
|
} |
|
unless (($r->is_initial_req()) || ($env{'form.ltoken'}) || |
|
($env{'form.linkkey'})) { |
|
return; |
|
} |
|
} |
|
my $extras; |
|
foreach my $name (@names) { |
|
if ($env{'form.'.$name} ne '') { |
|
if ($name eq 'ltoken') { |
|
my %info = &Apache::lonnet::tmpget($env{'form.ltoken'}); |
|
&Apache::lonnet::tmpdel($env{'form.ltoken'}); |
|
if ($info{'linkprot'}) { |
|
$extras .= '&linkprot='.&escape($info{'linkprot'}); |
|
foreach my $item ('linkprotuser','linkprotexit','linkprotpbid','linkprotpburl') { |
|
if ($info{$item} ne '') { |
|
$extras .= '&'.$item.'='.&escape($info{$item}); |
|
} |
|
} |
|
last; |
|
} |
|
} else { |
|
$extras .= '&'.$name.'='.&escape($env{'form.'.$name}); |
|
} |
|
} |
|
} |
|
if (($firsturl ne '') || ($extras ne '')) { |
|
$extras .= ':sso'; |
|
$ssotoken = &Apache::lonnet::reply('tmpput:'.&escape($firsturl). |
|
$extras,$lonhost); |
|
$querystring = 'sso='.$ssotoken; |
|
} |
|
if ($r->args ne '') { |
|
foreach my $key (sort(keys(%env))) { |
|
if ($key =~ /^form\.(.+)$/) { |
|
my $name = $1; |
|
next if (($token{$name}) || ($name eq 'ttoken')); |
|
$querystring .= '&'.$name.'='.$env{$key}; |
|
} |
|
} |
|
} |
|
return $querystring; |
|
} |
|
|
|
sub set_mailtoken { |
|
my ($r,$lonhost) = @_; |
|
my $firsturl = $r->uri; |
|
my ($querystring,$ssotoken,$extras); |
|
&Apache::loncommon::get_unprocessed_cgi($r->args); |
|
my $extras; |
|
if (($env{'form.display'} ne '') && |
|
($env{'form.username'} =~ /^$match_username$/) && |
|
($env{'form.domain'} =~ /^$match_domain$/)) { |
|
$extras .= '&display='.&escape($env{'form.display'}). |
|
'&mailrecip='.&escape($env{'form.username'}.':'.$env{'form.domain'}); |
|
} |
|
if (($firsturl ne '') || ($extras ne '')) { |
|
$extras .= ':sso'; |
|
$ssotoken = &Apache::lonnet::reply('tmpput:'.&escape($firsturl). |
|
$extras,$lonhost); |
|
$querystring = 'sso='.$ssotoken; |
|
} |
|
if ($r->args ne '') { |
|
foreach my $key (sort(keys(%env))) { |
|
if ($key =~ /^form\.(.+)$/) { |
|
my $name = $1; |
|
next if (($name eq 'display') || ($name eq 'username') || ($name eq 'domain')); |
|
$querystring .= '&'.$name.'='.$env{$key}; |
|
} |
|
} |
|
} |
|
return $querystring; |
|
} |
|
|
1; |
1; |
__END__ |
__END__ |