Annotation of loncom/LWPReq.pm, revision 1.4

1.1       raeburn     1: # The LearningOnline Network with CAPA
1.2       raeburn     2: # LON-CAPA wrapper for LWP UserAgent to accommodate certification
1.1       raeburn     3: # verification for SSL.
                      4: #
1.4     ! raeburn     5: # $Id: LWPReq.pm,v 1.3 2018/09/20 14:17:01 raeburn Exp $
1.1       raeburn     6: #
                      7: # The LearningOnline Network with CAPA
                      8: #
                      9: # Copyright Michigan State University Board of Trustees
                     10: #
                     11: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     12: #
                     13: # LON-CAPA is free software; you can redistribute it and/or modify
                     14: # it under the terms of the GNU General Public License as published by
                     15: # the Free Software Foundation; either version 2 of the License, or
                     16: # (at your option) any later version.
                     17: #
                     18: # LON-CAPA is distributed in the hope that it will be useful,
                     19: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     20: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     21: # GNU General Public License for more details.
                     22: #
                     23: # You should have received a copy of the GNU General Public License
                     24: # along with LON-CAPA; if not, write to the Free Software
                     25: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     26: #
                     27: # /home/httpd/html/adm/gpl.txt
                     28: #
                     29: # http://www.lon-capa.org/
                     30: #
                     31: 
                     32: package LONCAPA::LWPReq;
                     33: 
                     34: use strict;
                     35: use lib '/home/httpd/perl/lib';
                     36: use LONCAPA::Configuration;
                     37: use IO::Socket::SSL();
                     38: use LWP::UserAgent();
1.2       raeburn    39: use LWP::UserAgent::DNS::Hosts();
                     40: use Apache::lonnet;
1.1       raeburn    41: 
                     42: sub makerequest {
1.3       raeburn    43:     my ($remotehostid,$request,$content,$perlvar,$timeout,$verifycert,$use_lc_ca,$islocal,$debug) = @_;
1.1       raeburn    44:     unless (ref($perlvar) eq' HASH') {
                     45:         $perlvar = LONCAPA::Configuration::read_conf('loncapa.conf');
                     46:     }
1.2       raeburn    47:     my ($certf,$keyf,$caf,@opts,$dns_set,$lonhost);
1.1       raeburn    48:     if (ref($perlvar) eq 'HASH') {
1.2       raeburn    49:         $lonhost = $perlvar->{'lonHostID'};
                     50:         if ($perlvar->{'lonCertificateDirectory'}) {
                     51:             if ($perlvar->{'lonnetHostnameCertificate'}) {
                     52:                 if (-e $perlvar->{'lonCertificateDirectory'}.'/'.$perlvar->{'lonnetHostnameCertificate'}) {
                     53:                     $certf = $perlvar->{'lonCertificateDirectory'}.'/'.$perlvar->{'lonnetHostnameCertificate'};
                     54:                 }
                     55:             }
                     56:             if ($perlvar->{'lonnetPrivateKey'}) {
                     57:                 if (-e $perlvar->{'lonCertificateDirectory'}.'/'.$perlvar->{'lonnetPrivateKey'}) {
                     58:                     $keyf = $perlvar->{'lonCertificateDirectory'}.'/'.$perlvar->{'lonnetPrivateKey'};
                     59:                 }
                     60:             }
                     61:             if ($perlvar->{'lonnetCertificateAuthority'}) {
                     62:                 if (-e $perlvar->{'lonCertificateDirectory'}.'/'.$perlvar->{'lonnetCertificateAuthority'}) {
                     63:                     $caf = $perlvar->{'lonCertificateDirectory'}.'/'.$perlvar->{'lonnetCertificateAuthority'};
                     64:                 }
                     65:             }
                     66:         }
1.1       raeburn    67:     }
                     68:     if ($debug) {
                     69:         $IO::Socket::SSL::DEBUG=$debug;
                     70:     }
1.2       raeburn    71:     my ($response,$stdhostname,$remotehostname,$fn);
                     72:     if ($request->uri =~ m{^https?://((?:internal\-|)([^/]+))(/raw/.+)$}) {
                     73:         $remotehostname = $1;
                     74:         $stdhostname = $2;
                     75:         $fn = $3;
                     76:         $dns_set = &setdns($remotehostid,$remotehostname);
                     77:         unless ($remotehostname =~ /^internal\-/) {
                     78:             if (($use_lc_ca && $certf && $keyf) &&
                     79:                 (&raw_redirected($remotehostid,$lonhost))) {
                     80:                 $remotehostname = 'internal-'.$stdhostname;
                     81:                 $request->uri('https://'.$remotehostname.$fn);
                     82:             }
                     83:         }
                     84:     }
1.1       raeburn    85:     if (LWP::UserAgent->VERSION >= 6.00) {
                     86:         my $ssl_opts;
                     87:         if ($use_lc_ca && $certf && $keyf) {
                     88:             $ssl_opts->{'SSL_use_cert'} = 1;
                     89:             $ssl_opts->{'SSL_cert_file'} = $certf;
                     90:             $ssl_opts->{'SSL_key_file'} = $keyf;
1.2       raeburn    91:             if ($dns_set && $remotehostname) {
                     92:                 if ($remotehostname =~ /^internal\-/) {
                     93:                     $ssl_opts->{'SSL_hostname'} = $remotehostname;
                     94:                 }
                     95:             }
1.1       raeburn    96:         } else {
                     97:             $ssl_opts->{'SSL_use_cert'} = 0;
                     98:         }
                     99:         if ($verifycert) {
                    100:             $ssl_opts->{'verify_hostname'} = 1;
                    101:             $ssl_opts->{'SSL_verify_mode'} = IO::Socket::SSL::SSL_VERIFY_PEER;
                    102:             $ssl_opts->{'SSL_version'} = 'SSLv23:!SSLv3:!SSLv2';
1.2       raeburn   103:             if ($use_lc_ca) {
1.1       raeburn   104:                 $ssl_opts->{'SSL_ca_file'} = $caf;
                    105:             }
                    106:         } else {
                    107:             $ssl_opts->{'verify_hostname'} = 0;
                    108:             $ssl_opts->{'SSL_verify_mode'} = IO::Socket::SSL::SSL_VERIFY_NONE;
                    109:         }
                    110:         push(@opts,(ssl_opts => $ssl_opts));
                    111:         my $ua = LWP::UserAgent->new(@opts);
                    112:         if ($timeout) {
                    113:             $ua->timeout($timeout);
                    114:         }
1.2       raeburn   115:         if ($use_lc_ca && $remotehostname && $fn) {
                    116:             $ua->requests_redirectable(undef);
                    117:         }
1.3       raeburn   118:         if ($islocal) {
                    119:             $ua->local_address('127.0.0.1');
                    120:         }
1.1       raeburn   121:         if ($content ne '') {
                    122:             $response = $ua->request($request,$content);
                    123:         } else {
                    124:             $response = $ua->request($request);
                    125:         }
1.2       raeburn   126:         if (($response->code eq '302') && ($fn) && ($remotehostname) &&
                    127:             ($response->header('Location') eq 'https://internal-'.$stdhostname.$fn)) {
                    128:             my $newurl = $response->header('Location');
                    129:             unless ($dns_set) {
                    130:                 $dns_set = &setdns($remotehostid,$remotehostname);
                    131:             }
                    132:             if ($use_lc_ca && $certf && $keyf) {
                    133:                 $ssl_opts->{'SSL_hostname'} = 'internal-'.$stdhostname;
                    134:             }
                    135:             $request->uri($newurl);
                    136:             if ($content ne '') {
                    137:                 $response = $ua->request($request,$content);
                    138:             } else {
                    139:                 $response = $ua->request($request);
                    140:             }
                    141:         }
1.1       raeburn   142:     } else {
                    143:         {
                    144:             require Net::SSLGlue::LWP;
                    145:             local %Net::SSLGlue::LWP::SSLopts = %Net::SSLGlue::LWP::SSLopts;
                    146:             if ($use_lc_ca && $certf && $keyf) {
                    147:                 $Net::SSLGlue::LWP::SSLopts{'SSL_use_cert'} = 1;
                    148:                 $Net::SSLGlue::LWP::SSLopts{'SSL_cert_file'} = $certf;
                    149:                 $Net::SSLGlue::LWP::SSLopts{'SSL_key_file'} = $keyf;
1.2       raeburn   150:                 if ($dns_set && $remotehostname) {
                    151:                     if ($remotehostname =~ /^internal\-/) {
                    152:                         $Net::SSLGlue::LWP::SSLopts{'SSL_hostname'} = $remotehostname;
                    153:                     }
                    154:                 }
1.1       raeburn   155:             } else {
                    156:                 $Net::SSLGlue::LWP::SSLopts{'SSL_use_cert'} = 0;
                    157:             }
                    158:             if ($verifycert) {
                    159:                 $Net::SSLGlue::LWP::SSLopts{'SSL_verify_mode'} = IO::Socket::SSL::SSL_VERIFY_PEER;
                    160:                 $Net::SSLGlue::LWP::SSLopts{'SSL_version'} = 'SSLv23:!SSLv3:!SSLv2';
                    161:                 if ($use_lc_ca) {
                    162:                     $Net::SSLGlue::LWP::SSLopts{'SSL_ca_file'} = $caf;
                    163:                 }
                    164:             } else {
                    165:                 $Net::SSLGlue::LWP::SSLopts{'SSL_verify_mode'} = IO::Socket::SSL::SSL_VERIFY_NONE;
                    166:             }
                    167:             my $ua = LWP::UserAgent->new();
                    168:             if ($timeout) {
                    169:                 $ua->timeout($timeout);
                    170:             }
1.2       raeburn   171:             if ($use_lc_ca && $remotehostname && $fn) {
                    172:                 $ua->requests_redirectable(undef);
                    173:             }
1.3       raeburn   174:             if ($islocal) {
                    175:                 if (LWP::UserAgent->VERSION >= 5.834) {
                    176:                     $ua->local_address('127.0.0.1');
                    177:                 } else {
1.4     ! raeburn   178:                     require LWP::Protocol::http;
1.3       raeburn   179:                     local @LWP::Protocol::http::EXTRA_SOCK_OPTS =
                    180:                           (LocalAddr => '127.0.0.1');
                    181:                 }
                    182:             }
1.1       raeburn   183:             if ($content ne '') {
                    184:                 $response = $ua->request($request,$content);
                    185:             } else {
                    186:                 $response = $ua->request($request);
                    187:             }
1.2       raeburn   188:             if (($response->code eq '302') && ($fn) && ($remotehostname) &&
                    189:                 ($response->header('Location') eq 'https://internal-'.$stdhostname.$fn)) {
                    190:                 my $newurl = $response->header('Location');
                    191:                 unless ($dns_set) {
                    192:                     $dns_set = &setdns($remotehostid,$remotehostname);
                    193:                 }
                    194:                 $Net::SSLGlue::LWP::SSLopts{'SSL_hostname'} = 'internal-'.$stdhostname;
                    195:                 $request->uri($newurl);
                    196:                 if ($content ne '') {
                    197:                     $response = $ua->request($request,$content);
                    198:                 } else {
                    199:                     $response = $ua->request($request);
                    200:                 }
                    201:             }
1.3       raeburn   202:             if (($islocal) && (LWP::UserAgent->VERSION < 5.834)) {
                    203:                 local @LWP::Protocol::http::EXTRA_SOCK_OPTS = ();
                    204:             }
1.1       raeburn   205:         }
                    206:    }
1.2       raeburn   207:    if ($dns_set) {
                    208:        $dns_set = &unsetdns();
                    209:    }
1.1       raeburn   210:    return $response;
                    211: }
                    212: 
1.2       raeburn   213: sub setdns {
                    214:     my ($remotehostid,$remotehostname) = @_;
                    215:     my $ip = &Apache::lonnet::get_host_ip($remotehostid);
                    216:     if ($remotehostname =~ /^internal\-/) {
                    217:         LWP::UserAgent::DNS::Hosts->register_host(
                    218:             $remotehostname => $ip,
                    219:         );
                    220:     } else {
                    221:         LWP::UserAgent::DNS::Hosts->register_host(
                    222:             'internal-'.$remotehostname => $ip,
                    223:         );
                    224:     }
                    225:     LWP::UserAgent::DNS::Hosts->enable_override;
                    226:     return 1;
                    227: }
                    228: 
                    229: sub unsetdns {
                    230:     LWP::UserAgent::DNS::Hosts->clear_hosts();
                    231:     return 0;
                    232: }
                    233: 
                    234: sub raw_redirected {
                    235:     my ($remotehostid,$lonhost) = @_;
                    236:     my $remhostname = &Apache::lonnet::hostname($remotehostid);
                    237:     my $redirect;
                    238:     if ($remhostname) {
                    239:         my $remoterev = &Apache::lonnet::get_server_loncaparev(undef,$remotehostid);
                    240:         my ($remmajor,$remminor) = ($remoterev =~ /^(\d+)\.(\d+)/);
                    241:         if (($remmajor > 2) || (($remmajor == 2) && $remminor >= 12)) {
                    242:             my $internet_names = &Apache::lonnet::get_internet_names($remotehostid);
                    243:             if (ref($internet_names) eq 'ARRAY') {
                    244:                 my $intdom = &Apache::lonnet::internet_dom($lonhost);
                    245:                 unless (grep(/^\Q$intdom\E$/,@{$internet_names})) {
                    246:                     my $remhomeID = &Apache::lonnet::get_server_homeID($remhostname);
                    247:                     my $remhomedom = &Apache::lonnet::host_domain($remhomeID);
                    248:                     my %domdefaults = &Apache::lonnet::get_domain_defaults($remhomedom);
                    249:                     my $replication = $domdefaults{'replication'};
                    250:                     if (ref($replication) eq 'HASH') {
                    251:                         if (ref($replication->{'reqcerts'}) eq 'ARRAY') {
                    252:                             if (grep(/^\Q$intdom\E$/,@{$replication->{'reqcerts'}})) {
                    253:                                 $redirect = 1;
                    254:                             } else {
                    255:                                 $redirect = 0;
                    256:                             }
                    257:                         }
                    258:                         if (ref($replication->{'noreqcerts'}) eq 'ARRAY') {
                    259:                             if (grep(/^\Q$intdom\E$/,@{$replication->{'noreqcerts'}})) {
                    260:                                 $redirect = 0;
                    261:                             } else {
                    262:                                 $redirect = 1;
                    263:                             }
                    264:                         }
                    265:                     }
                    266:                 }
                    267:             }
                    268:         }
                    269:     }
                    270:     return $redirect;
                    271: }
                    272: 
1.1       raeburn   273: 1;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>