--- loncom/cgi/lonauthcgi.pm 2008/12/25 01:51:03 1.1 +++ loncom/cgi/lonauthcgi.pm 2014/01/01 17:41:51 1.12 @@ -1,7 +1,7 @@ # # LON-CAPA authorization for cgi-bin scripts # -# $Id: lonauthcgi.pm,v 1.1 2008/12/25 01:51:03 raeburn Exp $ +# $Id: lonauthcgi.pm,v 1.12 2014/01/01 17:41:51 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -32,7 +32,7 @@ =head1 NAME -loncgi +lonauthcgi =head1 SYNOPSIS @@ -55,6 +55,7 @@ package LONCAPA::lonauthcgi; use strict; use lib '/home/httpd/lib/perl'; +use Socket; use Apache::lonnet; use Apache::lonlocal; use LONCAPA; @@ -72,11 +73,16 @@ Inputs: $page, the identifier of the pag $ip, the IP address of the client requesting the page. Returns: 1 if access is permitted for the requestor's IP. - Access is allowed if on of the following is true: - (a) the requestor IP is the loopback address - (b) Domain configurations for domains hosted on this server include + Access is allowed if one of the following is true: + (a) the requestor IP is the loopback address. + (b) the requestor IP is the IP of the current server. + (c) the requestor IP is the IP of a manager, + if the page to view is not "takeoffline" or "toggledebug" + (d) the requestor IP is the IP of a server belonging + to a domain included in domains hosted on this server. + (e) Domain configurations for domains hosted on this server include the requestor's IP as one of the specified IPs with access - to this page. (does not apply to 'ping' page type) + to this page. (not applicable to 'ping' page). =cut @@ -88,12 +94,27 @@ sub check_ipbased_access { if (!defined($ip)) { $ip = $ENV{'REMOTE_ADDR'}; } - if (($page ne 'lonstatus') && ($page ne 'serverstatus')) { - if ($ip eq '127.0.0.1') { + if ($ip eq '127.0.0.1') { + $allowed = 1; + return $allowed; + } else { + my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; + my $host_ip = &Apache::lonnet::get_host_ip($lonhost); + if (($host_ip ne '') && ($host_ip eq $ip)) { $allowed = 1; return $allowed; } } + if (&is_manager_ip($ip)) { + unless (($page eq 'toggledebug') || ($page eq 'takeoffline')) { + $allowed = 1; + return $allowed; + } + } + if (&check_domain_ip($ip)) { + $allowed = 1; + return $allowed; + } if ($page ne 'ping') { my @poss_domains = &Apache::lonnet::current_machine_domains(); foreach my $dom (@poss_domains) { @@ -110,6 +131,86 @@ sub check_ipbased_access { } } } + } + return $allowed; +} + +############################################# +############################################# + +=pod + +=item is_manager_ip() + +Inputs: $remote_ip, the IP address of the client requesting the page. + +Returns: 1 if the client IP address corresponds to that of a + machine listed in /home/httpd/lonTabs/managers.tab + +=cut + +############################################# +############################################# +sub is_manager_ip { + my ($remote_ip) = @_; + return if ($remote_ip eq ''); + my ($directory,$is_manager); + foreach my $key (keys(%Apache::lonnet::managerstab)) { + my $manager_ip; + if ($key =~ /:/) { + my ($cluname,$dnsname) = split(/:/,$key); + my $ip = gethostbyname($dnsname); + if (defined($ip)) { + $manager_ip = inet_ntoa($ip); + } + } else { + $manager_ip = &Apache::lonnet::get_host_ip($key); + } + if (defined($manager_ip)) { + if ($remote_ip eq $manager_ip) { + $is_manager = 1; + last; + } + } + } + return $is_manager; +} + +############################################# +############################################# + +=pod + +=item check_domain_ip() + +Inputs: $remote_ip, the IP address of the client requesting the page. + +Returns: 1 if the client IP address is for a machine in the cluster + and domain in common for client machine and this machine. + +=cut + +############################################# +############################################# +sub check_domain_ip { + my ($remote_ip) = @_; + my %remote_doms; + my $allowed; + if ($remote_ip ne '') { + if (&Apache::lonnet::hostname($remote_ip) ne '') { + my @poss_domains = &Apache::lonnet::current_machine_domains(); + if (@poss_domains > 0) { + my @remote_hosts = &Apache::lonnet::get_hosts_from_ip($remote_ip); + foreach my $hostid (@remote_hosts) { + my $hostdom = &Apache::lonnet::host_domain($hostid); + if ($hostdom ne '') { + if (grep(/^\Q$hostdom\E$/,@poss_domains)) { + $allowed = 1; + last; + } + } + } + } } } return $allowed; @@ -124,55 +225,92 @@ sub check_ipbased_access { Inputs: $page, the identifier of the page to be viewed, can be one of the keys in the hash from &serverstatus_titles() + $domain (optional), a specific domain for which the page is needed. -Returns: 1 if access to the page is permitted. +Returns: 1 if access to the page is permitted, or &-separated list of domains + for which access is allowed, if $page is domconf, and not superuser. Access allowed if one of the following is true: (a) Requestor has LON-CAPA superuser role - (b) Requestor's role is Domain Coordinator in one of the domains + (b) Requestor's role is Domain Coordinator in requested domain + (if specified) or (if unspecified) in one of the domains hosted on this server - (c) Domain configurations for domains hosted on this server include - the requestor as one of the named users (username:domain) with access - to the page. - - In the case of requests for the 'ping' page, and access is also allowed if - at least one domain hosted on requestor's server is also hosted on this server. + (c) The domain configuration for the particular domain (if specified), + or domain configurations for domains hosted on this server (if + specific domain not specified), include the requestor as one of + the named users (username:domain) with access to the page. + + In the case of requests for the 'showenv' page (/adm/test), the domains tested + are not the domains hosted on the server, but instead are a single domain - + the domain of the requestor. In addition, if the requestor has an active + Domain Coordinator role for that domain, access is permitted, regardless of + the requestor's current role. =cut ############################################# ############################################# sub can_view { - my ($page) = @_; + my ($page,$domain) = @_; my $allowed; if ($Apache::lonnet::env{'request.role'} =~ m{^su\./}) { $allowed = 1; - } elsif ($page eq 'ping') { - my @poss_domains = &Apache::lonnet::current_machine_domains(); - my @hostids= &Apache::lonnet::get_hosts_from_ip($ENV{'REMOTE_ADDR'}); - foreach my $hostid (@hostids) { - my $hostdom = &Apache::lonnet::host_domain($hostid); - if (grep(/^\Q$hostdom\E$/,@poss_domains)) { - $allowed = 1; - last; + } else { + my @poss_domains; + if ($page eq 'showenv') { + @poss_domains = ($env{'user.domain'}); + my $envkey = 'user.role.dc./'.$poss_domains[0].'/'; + if (exists($Apache::lonnet::env{$envkey})) { + my $livedc = 1; + my $then = $Apache::lonnet::env{'user.login.time'}; + my ($tstart,$tend)=split(/\./,$Apache::lonnet::env{$envkey}); + if ($tstart && $tstart>$then) { $livedc = 0; } + if ($tend && $tend <$then) { $livedc = 0; } + if ($livedc) { + $allowed = 1; + } + } + } else { + @poss_domains = &Apache::lonnet::current_machine_domains(); + if ($domain ne '') { + if (grep(/^\Q$domain\E$/,@poss_domains)) { + @poss_domains = ($domain); + } else { + undef(@poss_domains); + } } } - } else { - my @poss_domains = &Apache::lonnet::current_machine_domains(); - foreach my $dom (@poss_domains) { - my %domconfig = &Apache::lonnet::get_dom('configuration',['serverstatuses'],$dom); - if ($Apache::lonnet::env{'request.role'} eq "dc./$dom/") { - $allowed = 1; - } elsif (ref($domconfig{'serverstatuses'}) eq 'HASH') { - if (ref($domconfig{'serverstatuses'}{$page}) eq 'HASH') { - if ($domconfig{'serverstatuses'}{$page}{'namedusers'} ne '') { - my @okusers = split(/,/,$domconfig{'serverstatuses'}{$page}{'namedusers'}); - if (grep(/^\Q$Apache::lonnet::env{'user.name'}:$Apache::lonnet::env{'user.domain'}\E$/,@okusers)) { - $allowed = 1; + unless ($allowed) { + my %alloweddoms; + foreach my $dom (@poss_domains) { + my %domconfig = &Apache::lonnet::get_dom('configuration',['serverstatuses'], + $dom); + if ($Apache::lonnet::env{'request.role'} eq "dc./$dom/") { + if ($page eq 'domconf') { + $alloweddoms{$dom} = 1; + } else { + $allowed = 1; + } + } elsif (ref($domconfig{'serverstatuses'}) eq 'HASH') { + if (ref($domconfig{'serverstatuses'}{$page}) eq 'HASH') { + if ($domconfig{'serverstatuses'}{$page}{'namedusers'} ne '') { + my @okusers = split(/,/,$domconfig{'serverstatuses'}{$page}{'namedusers'}); + if (grep(/^\Q$Apache::lonnet::env{'user.name'}:$Apache::lonnet::env{'user.domain'}\E$/,@okusers)) { + if ($page eq 'domconf') { + $alloweddoms{$dom} = 1; + } else { + $allowed = 1; + } + } + unless ($page eq 'domconf') { + last if ($allowed); + } } } } } - last if $allowed; + if (($page eq 'domconf') && (!$allowed)) { + $allowed = join('&',sort(keys(%alloweddoms))); + } } } return $allowed; @@ -183,7 +321,7 @@ sub can_view { =pod -=unauthorized_msg() +=item unauthorized_msg() Inputs: $page, the identifier of the page to be viewed, can be one of the keys in the hash from &serverstatus_titles() @@ -242,16 +380,25 @@ sub serverstatus_titles { 'loncron' => 'Generate Detailed Report', 'server-status' => 'Apache Status Page', 'codeversions' => 'LON-CAPA Module Versions', + 'checksums' => 'LON-CAPA Module Checking', 'clusterstatus' => 'Domain status', 'metadata_keywords' => 'Display Metadata Keywords', 'metadata_harvest' => 'Harvest Metadata Searches', 'takeoffline' => 'Offline - replace Log-in page', 'takeonline' => 'Online - restore Log-in page', - 'showenv' => "Show user environment", + 'showenv' => 'Show user environment', + 'toggledebug' => 'Toggle debug messages', + 'ping' => 'Cause server to ping another server', + 'domconf' => 'Text Display of Domain Configuration', + 'uniquecodes' => 'Six-character Course Codes', ); return \%titles; } +=pod -1; +=back + +=cut +1;