Annotation of loncom/auth/lonauth.pm, revision 1.101

1.1       albertel    1: # The LearningOnline Network
                      2: # User Authentication Module
1.27      www         3: #
1.101   ! raeburn     4: # $Id: lonauth.pm,v 1.100 2009/07/22 20:24:07 raeburn Exp $
1.27      www         5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
                     27: #
1.1       albertel   28: 
                     29: package Apache::lonauth;
                     30: 
1.18      albertel   31: use strict;
1.78      albertel   32: use LONCAPA;
1.1       albertel   33: use Apache::Constants qw(:common);
                     34: use CGI qw(:standard);
1.26      harris41   35: use DynaLoader; # for Crypt::DES version
1.8       www        36: use Crypt::DES;
1.45      matthew    37: use Apache::loncommon();
1.66      albertel   38: use Apache::lonnet;
1.12      www        39: use Apache::lonmenu();
1.90      raeburn    40: use Apache::createaccount;
1.18      albertel   41: use Fcntl qw(:flock);
1.56      www        42: use Apache::lonlocal;
1.101   ! raeburn    43: use HTML::Entities;
1.85      albertel   44:  
1.1       albertel   45: # ------------------------------------------------------------ Successful login
1.85      albertel   46: sub success {
                     47:     my ($r, $username, $domain, $authhost, $lowerurl, $extra_env,
                     48: 	$form) = @_;
1.1       albertel   49: 
1.85      albertel   50: # ------------------------------------------------------------ Get cookie ready
                     51:     my $cookie =
                     52: 	&Apache::loncommon::init_user_environment($r, $username, $domain,
                     53: 						  $authhost, $form,
1.86      albertel   54: 						  {'extra_env' => $extra_env,});
1.4       www        55: 
1.69      albertel   56:     my $public=($username eq 'public' && $domain eq 'public');
                     57: 
1.85      albertel   58:     if ($public or $lowerurl eq 'noredirect') { return $cookie; }
1.78      albertel   59: 
1.7       www        60: # -------------------------------------------------------------------- Log this
                     61: 
                     62:     &Apache::lonnet::log($domain,$username,$authhost,
                     63:                          "Login $ENV{'REMOTE_ADDR'}");
1.4       www        64: 
1.14      www        65: # ------------------------------------------------- Check for critical messages
                     66: 
1.21      www        67:     my @what=&Apache::lonnet::dump('critical',$domain,$username);
1.14      www        68:     if ($what[0]) {
1.22      www        69: 	if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
1.21      www        70: 	    $lowerurl='/adm/email?critical=display';
1.14      www        71:         }
                     72:     }
                     73: 
1.5       www        74: # ------------------------------------------------------------ Get cookie ready
1.1       albertel   75:     $cookie="lonID=$cookie; path=/";
1.12      www        76: # -------------------------------------------------------- Menu script and info
1.100     raeburn    77:     my $destination = $lowerurl;
                     78: 
                     79:     if (defined($form->{role})) {
                     80:         my $envkey = 'user.role.'.$form->{role};
                     81:         my $now=time;
                     82:         my $then=$env{'user.login.time'};
                     83:         my $refresh=$env{'user.refresh.time'};
                     84:         if (exists($env{$envkey})) {
                     85:             my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus);
                     86:             &Apache::lonnet::role_status($envkey,$then,$refresh,$now,\$role,\$where,
                     87:                                          \$trolecode,\$tstatus,\$tstart,\$tend);
                     88:             if ($tstatus eq 'is') {
1.101   ! raeburn    89:                 $destination  .= ($destination =~ /\?/) ? '&' : '?';
        !            90:                 my $newrole = &HTML::Entities::encode($form->{role},'"<>&');
        !            91:                 $destination .= 'selectrole=1&'.$newrole.'=1';
1.100     raeburn    92:             }
                     93:         }
                     94:     }
1.101   ! raeburn    95:     if (defined($form->{symb})) {
        !            96:         my $destsymb = $form->{symb};
        !            97:         $destination  .= ($destination =~ /\?/) ? '&' : '?';
        !            98:         if ($destsymb =~ /___/) {
        !            99:             # FIXME Need to deal with encrypted symbs and urls as needed.
        !           100:             my ($map,$resid,$desturl)=split(/___/,$destsymb);
        !           101:             unless ($desturl=~/^(adm|uploaded|editupload|public)/) {
        !           102:                 $desturl = &Apache::lonnet::clutter($desturl);
        !           103:             }
        !           104:             $desturl = &HTML::Entities::encode($desturl,'"<>&');
        !           105:             $destsymb = &HTML::Entities::encode($destsymb,'"<>&');
        !           106:             $destination .= '&destinationurl='.$desturl.
        !           107:                             '&destsymb='.$destsymb;
        !           108:         } else {
        !           109:             $destsymb = &HTML::Entities::encode($destsymb,'"<>&');
        !           110:             $destination .= '&destinationurl='.$destsymb;
        !           111:         }
        !           112:     }
1.100     raeburn   113: 
1.85      albertel  114:     my $windowinfo=&Apache::lonmenu::open($env{'browser.os'});
1.100     raeburn   115:     my $startupremote=&Apache::lonmenu::startupremote($destination);
1.63      albertel  116:     my $remoteinfo=&Apache::lonmenu::load_remote_msg($lowerurl);
1.35      www       117:     my $setflags=&Apache::lonmenu::setflags();
                    118:     my $maincall=&Apache::lonmenu::maincall();
1.99      bisitz    119:     my $brcrum = [{'href' => '',
                    120:                    'text' => 'Successful Login'},];
1.74      albertel  121:     my $start_page=&Apache::loncommon::start_page('Successful Login',
1.99      bisitz    122:                                                   $startupremote,
                    123:                                                   {'no_inline_link' => 1,
                    124:                                                    'bread_crumbs' => $brcrum,});
1.74      albertel  125:     my $end_page  =&Apache::loncommon::end_page();
                    126: 
1.64      albertel  127:     my $continuelink;
1.98      www       128:     if ($env{'environment.remote'} eq 'off') {
1.100     raeburn   129: 	$continuelink='<a href="'.$destination.'">'.&mt('Continue').'</a>';
1.64      albertel  130:     }
1.5       www       131: # ------------------------------------------------- Output for successful login
                    132: 
1.74      albertel  133:     &Apache::loncommon::content_type($r,'text/html');
                    134:     $r->header_out('Set-cookie' => $cookie);
                    135:     $r->send_http_header;
1.1       albertel  136: 
1.58      www       137:     my %lt=&Apache::lonlocal::texthash(
                    138: 				       'wel' => 'Welcome',
1.92      bisitz    139: 				       'mes' => 'Welcome to the Learning<i>Online</i> Network with CAPA. Please wait while your session is being set up.',
                    140: 				       'pro' => 'Login problems?',
1.58      www       141: 				       'log' => 'loginproblems.html',
                    142: 				       );
1.1       albertel  143:     $r->print(<<ENDSUCCESS);
1.74      albertel  144: $start_page
1.35      www       145: $setflags
1.19      www       146: $windowinfo
1.58      www       147: <h1>$lt{'wel'}</h1>
1.92      bisitz    148: $lt{'mes'}<p>
                    149: <a href="/adm/$lt{'log'}">$lt{'pro'}</a></p>
1.63      albertel  150: $remoteinfo
1.35      www       151: $maincall
1.64      albertel  152: $continuelink
1.74      albertel  153: $end_page
1.1       albertel  154: ENDSUCCESS
                    155: }
                    156: 
                    157: # --------------------------------------------------------------- Failed login!
                    158: 
                    159: sub failed {
1.85      albertel  160:     my ($r,$message,$form) = @_;
1.76      albertel  161:     my $start_page = &Apache::loncommon::start_page('Unsuccessful Login',undef,
                    162: 						    {'no_inline_link' => 1,});
1.100     raeburn   163:     my $retry = '/adm/login?username='.$form->{'uname'}.
                    164:                 '&domain='.$form->{'udom'};
                    165:     if (exists($form->{role})) {
                    166:         $retry .= '&role='.$form->{role};
                    167:     }
                    168:     if (exists($form->{symb})) {
                    169:         $retry .= '&symb='.$form->{symb};
                    170:     }
1.74      albertel  171:     my $end_page   = &Apache::loncommon::end_page();
                    172:     &Apache::loncommon::content_type($r,'text/html');
                    173:     $r->send_http_header;
1.92      bisitz    174:     $r->print(
                    175:        $start_page
                    176:       .'<h1>'.&mt('Sorry ...').'</h1>'
1.95      bisitz    177:       .'<p class="LC_warning">'.&mt($message).'</p>'
1.100     raeburn   178:       .'<p>'.&mt('Please [_1]log in again[_2].','<a href="'.$retry.'">','</a>')
1.92      bisitz    179:       .'</p>'
                    180:       .'<p><a href="/adm/loginproblems.html">'.&mt('Login problems?').'</a></p>'
                    181:       .$end_page
                    182:     );
                    183:  }
1.60      www       184: 
1.55      www       185: # ------------------------------------------------------------------ Rerouting!
                    186: 
                    187: sub reroute {
1.74      albertel  188:     my ($r) = @_;
                    189:     &Apache::loncommon::content_type($r,'text/html');
                    190:     $r->send_http_header;
1.92      bisitz    191:     my $msg='<h1>'.&mt('Sorry ...').'</h1>'
                    192:            .&mt('Please [_1]log in again[_2].');
1.74      albertel  193:     &Apache::loncommon::simple_error_page($r,'Rerouting',$msg);
1.55      www       194: }
                    195: 
1.1       albertel  196: # ---------------------------------------------------------------- Main handler
                    197: 
                    198: sub handler {
                    199:     my $r = shift;
1.85      albertel  200:     my $form;
1.55      www       201: # Are we re-routing?
                    202:     if (-e '/home/httpd/html/lon-status/reroute.txt') {
                    203: 	&reroute($r);
                    204: 	return OK;
                    205:     }
1.56      www       206: 
1.57      www       207:     &Apache::lonlocal::get_language_handle($r);
1.1       albertel  208: 
1.59      www       209: # -------------------------------- Prevent users from attempting to login twice
1.89      albertel  210:     my $handle = &Apache::lonnet::check_for_valid_session($r);
                    211:     if ($handle ne '') {
1.59      www       212: # Indeed, a valid token is found
1.89      albertel  213: 	&Apache::loncommon::content_type($r,'text/html');
                    214: 	$r->send_http_header;
                    215: 	my $start_page = 
                    216: 	    &Apache::loncommon::start_page('Already logged in');
                    217: 	my $end_page = 
                    218: 	    &Apache::loncommon::end_page();
1.92      bisitz    219:         $r->print(
                    220:            $start_page
                    221:           .'<h1>'.&mt('You are already logged in!').'</h1>'
1.97      hauer     222:           .'<p>'.&mt('Please either [_1]continue the current session[_2] or [_3]log out[_4].'
1.92      bisitz    223:                     ,'<a href="/adm/roles">','</a>','<a href="/adm/logout">','</a>')
                    224:           .'</p>'
                    225:           .'<p><a href="/adm/loginproblems.html">'.&mt('Login problems?').'</a></p>'
                    226:           .$end_page
                    227:         );
                    228:         return OK;
1.59      www       229:     }
                    230: 
                    231: # ---------------------------------------------------- No valid token, continue
                    232: 
                    233: 
1.1       albertel  234:     my $buffer;
1.84      albertel  235:     if ($r->header_in('Content-length') > 0) {
                    236: 	$r->read($buffer,$r->header_in('Content-length'),0);
                    237:     }
1.85      albertel  238:     my %form;
                    239:     foreach my $pair (split(/&/,$buffer)) {
                    240:        my ($name,$value) = split(/=/,$pair);
1.7       www       241:        $value =~ tr/+/ /;
                    242:        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.85      albertel  243:        $form{$name}=$value;
1.1       albertel  244:     } 
                    245: 
1.85      albertel  246:     if ((!$form{'uname'}) || (!$form{'upass0'}) || (!$form{'udom'})) {
                    247: 	&failed($r,'Username, password and domain need to be specified.',
                    248: 		\%form);
1.1       albertel  249:         return OK;
                    250:     }
1.61      www       251: 
                    252: # split user logging in and "su"-user
                    253: 
1.85      albertel  254:     ($form{'uname'},$form{'suname'})=split(/\:/,$form{'uname'});
1.87      albertel  255:     $form{'uname'} = &LONCAPA::clean_username($form{'uname'});
                    256:     $form{'suname'}= &LONCAPA::clean_username($form{'suname'});
                    257:     $form{'udom'}  = &LONCAPA::clean_domain(  $form{'udom'});
1.1       albertel  258: 
                    259:     my $role   = $r->dir_config('lonRole');
                    260:     my $domain = $r->dir_config('lonDefDomain');
                    261:     my $prodir = $r->dir_config('lonUsersDir');
1.93      raeburn   262:     my $contact_name = &mt('LON-CAPA helpdesk');
1.1       albertel  263: 
1.8       www       264: # ---------------------------------------- Get the information from login token
                    265: 
1.85      albertel  266:     my $tmpinfo=Apache::lonnet::reply('tmpget:'.$form{'logtoken'},
                    267:                                       $form{'serverid'});
1.8       www       268: 
                    269:     if (($tmpinfo=~/^error/) || ($tmpinfo eq 'con_lost')) {
1.85      albertel  270: 	&failed($r,'Information needed to verify your login information is missing, inaccessible or expired.',\%form);
1.8       www       271:         return OK;
1.44      www       272:     } else {
1.85      albertel  273: 	my $reply = &Apache::lonnet::reply('tmpdel:'.$form{'logtoken'},
                    274: 					   $form{'serverid'});
1.77      albertel  275:         if ( $reply ne 'ok' ) {
1.85      albertel  276:             &failed($r,'Session could not be opened.',\%form);
                    277: 	    &Apache::lonnet::logthis("ERROR got a reply of $reply when trying to contact ". $form{'serverid'}." to get login token");
1.77      albertel  278: 	    return OK;
1.44      www       279: 	}
1.8       www       280:     }
1.100     raeburn   281: 
1.93      raeburn   282:     if (!&Apache::lonnet::domain($form{'udom'})) {
                    283:         &failed($r,'The domain you provided is not a valid LON-CAPA domain.',\%form);
                    284:         return OK;
                    285:     }
1.100     raeburn   286: 
                    287:     my ($key,$firsturl,$rolestr,$symbstr)=split(/&/,$tmpinfo);
                    288:     if ($rolestr) {
                    289:         $rolestr = &unescape($rolestr);
                    290:     }
                    291:     if ($symbstr) {
                    292:         $symbstr= &unescape($symbstr);
                    293:     }
                    294:     if ($rolestr =~ /^role=/) {
                    295:         (undef,$form{'role'}) = split('=',$rolestr);
                    296:     }
                    297:     if ($symbstr =~ /^symb=/) { 
                    298:         (undef,$form{'symb'}) = split('=',$symbstr);
                    299:     }
1.8       www       300: 
                    301:     my $keybin=pack("H16",$key);
                    302: 
1.26      harris41  303:     my $cipher;
                    304:     if ($Crypt::DES::VERSION>=2.03) {
                    305: 	$cipher=new Crypt::DES $keybin;
                    306:     }
                    307:     else {
                    308: 	$cipher=new DES $keybin;
                    309:     }
1.67      www       310:     my $upass='';
                    311:     for (my $i=0;$i<=2;$i++) {
                    312: 	my $chunk=
1.85      albertel  313: 	    $cipher->decrypt(unpack("a8",pack("H16",substr($form{'upass'.$i},0,16))));
1.8       www       314: 
1.67      www       315: 	$chunk.=
1.85      albertel  316: 	    $cipher->decrypt(unpack("a8",pack("H16",substr($form{'upass'.$i},16,16))));
1.8       www       317: 
1.67      www       318: 	$chunk=substr($chunk,1,ord(substr($chunk,0,1)));
                    319: 	$upass.=$chunk;
                    320:     }
1.8       www       321: 
1.1       albertel  322: # ---------------------------------------------------------------- Authenticate
1.91      raeburn   323:     my @cancreate;
1.90      raeburn   324:     my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$form{'udom'});
                    325:     if (ref($domconfig{'usercreation'}) eq 'HASH') {
                    326:         if (ref($domconfig{'usercreation'}{'cancreate'}) eq 'HASH') {
1.91      raeburn   327:             if (ref($domconfig{'usercreation'}{'cancreate'}{'selfcreate'}) eq 'ARRAY') {
                    328:                 @cancreate = @{$domconfig{'usercreation'}{'cancreate'}{'selfcreate'}};
                    329:             } elsif (($domconfig{'usercreation'}{'cancreate'}{'selfcreate'} ne 'none') && 
                    330:                      ($domconfig{'usercreation'}{'cancreate'}{'selfcreate'} ne '')) {
                    331:                 @cancreate = ($domconfig{'usercreation'}{'cancreate'}{'selfcreate'});
1.90      raeburn   332:             }
                    333:         }
                    334:     }
                    335:     my $defaultauth;
1.91      raeburn   336:     if (grep(/^login$/,@cancreate)) {
1.90      raeburn   337:         $defaultauth = 1;
                    338:     }
                    339:     my $authhost=Apache::lonnet::authenticate($form{'uname'},$upass,
                    340:                                               $form{'udom'},$defaultauth);
1.1       albertel  341:     
                    342: # --------------------------------------------------------------------- Failed?
                    343: 
                    344:     if ($authhost eq 'no_host') {
1.85      albertel  345: 	&failed($r,'Username and/or password could not be authenticated.',
                    346: 		\%form);
1.1       albertel  347:         return OK;
1.90      raeburn   348:     } elsif ($authhost eq 'no_account_on_host') {
                    349:         my %domconfig = 
                    350:             &Apache::lonnet::get_dom('configuration',['usercreation'],$form{'udom'});
1.91      raeburn   351:         if (grep(/^login$/,@cancreate)) {
1.90      raeburn   352:             my $start_page = 
                    353:                 &Apache::loncommon::start_page('Create a user account in LON-CAPA',
                    354:                                                '',{'no_inline_link'   => 1,});
                    355:             my $domdesc = &Apache::lonnet::domain($form{'udom'},'description');
1.93      raeburn   356:             my $lonhost = $r->dir_config('lonHostID');
                    357:             my $origmail = $Apache::lonnet::perlvar{'lonSupportEMail'};
                    358:             my $contacts = 
                    359:                 &Apache::loncommon::build_recipient_list(undef,'helpdeskmail',
                    360:                                                         $form{'udom'},$origmail);
                    361:             my ($contact_email) = split(',',$contacts); 
1.94      raeburn   362:             my $output = &Apache::createaccount::username_check($form{'uname'}, 
                    363:                                                                 $form{'udom'},$domdesc,'',
                    364:                                                                 $lonhost,$contact_email,$contact_name);
1.90      raeburn   365:             &Apache::loncommon::content_type($r,'text/html');
                    366:             $r->send_http_header;
                    367:             &Apache::createaccount::print_header($r,$start_page);
1.94      raeburn   368:             $r->print('<h3>'.&mt('Account creation').'</h3>'.
                    369:                       &mt('Although your username and password were authenticated, you do not currently have a LON-CAPA account at this institution.').'<br />'.
                    370:                       $output.&Apache::loncommon::end_page());
1.90      raeburn   371:             return OK;
                    372:         } else {
                    373:             &failed($r,'Although your username and password were authenticated, you do not currently have a LON-CAPA account in this domain, and you are not permitted to create one.',\%form);
                    374:             return OK;
                    375:         }
1.1       albertel  376:     }
                    377: 
1.59      www       378:     if (($firsturl eq '') || 
                    379: 	($firsturl=~/^\/adm\/(logout|remote)/)) {
1.24      www       380: 	$firsturl='/adm/roles';
1.7       www       381:     }
1.61      www       382: # --------------------------------- Are we attempting to login as somebody else?
1.85      albertel  383:     if ($form{'suname'}) {
1.61      www       384: # ------------ see if the original user has enough privileges to pull this stunt
1.85      albertel  385: 	if (&Apache::lonnet::privileged($form{'uname'},$form{'udom'})) {
1.61      www       386: # ---------------------------------------------------- see if the su-user exists
1.85      albertel  387: 	    unless (&Apache::lonnet::homeserver($form{'suname'},$form{'udom'})
1.61      www       388: 		eq 'no_host') {
1.85      albertel  389: 		&Apache::lonnet::logthis(&Apache::lonnet::homeserver($form{'suname'},$form{'udom'}));
1.61      www       390: # ------------------------------ see if the su-user is not too highly privileged
1.85      albertel  391: 		unless (&Apache::lonnet::privileged($form{'suname'},$form{'udom'})) {
1.61      www       392: # -------------------------------------------------------- actually switch users
1.85      albertel  393: 		    &Apache::lonnet::logperm('User '.$form{'uname'}.' at '.$form{'udom'}.
                    394: 			' logging in as '.$form{'suname'});
                    395: 		    $form{'uname'}=$form{'suname'};
1.61      www       396: 		} else {
                    397: 		    &Apache::lonnet::logthis('Attempted switch user to privileged user');
                    398: 		}
                    399: 	    }
                    400: 	} else {
                    401: 	    &Apache::lonnet::logthis('Non-privileged user attempting switch user');
                    402: 	}
                    403:     }
1.85      albertel  404: 
1.81      albertel  405:     if ($r->dir_config("lonBalancer") eq 'yes') {
1.85      albertel  406: 	&success($r,$form{'uname'},$form{'udom'},$authhost,'noredirect',undef,
                    407: 		 \%form);
1.81      albertel  408: 	$r->internal_redirect('/adm/switchserver');
                    409:     } else {
1.85      albertel  410: 	&success($r,$form{'uname'},$form{'udom'},$authhost,$firsturl,undef,
                    411: 		 \%form);
1.81      albertel  412:     }
1.1       albertel  413:     return OK;
                    414: }
                    415: 
                    416: 1;
                    417: __END__
1.7       www       418: 
                    419: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.