Annotation of loncom/lti/ltiauth.pm, revision 1.9

1.1       raeburn     1: # The LearningOnline Network
                      2: # Basic LTI Authentication Module
                      3: #
1.9     ! raeburn     4: # $Id: ltiauth.pm,v 1.8 2018/04/14 02:30:07 raeburn Exp $
1.1       raeburn     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: #
                     28: 
                     29: package Apache::ltiauth;
                     30: 
                     31: use strict;
                     32: use LONCAPA qw(:DEFAULT :match);
                     33: use Apache::Constants qw(:common :http);
                     34: use Net::OAuth;
                     35: use Apache::lonlocal;
                     36: use Apache::lonnet;
                     37: use Apache::loncommon;
                     38: use Apache::lonacc;
1.6       raeburn    39: use Apache::lonrequestcourse;
1.2       raeburn    40: use LONCAPA::ltiutils;
1.1       raeburn    41: 
                     42: sub handler {
                     43:     my $r = shift;
                     44:     my $requri = $r->uri;
                     45: #
1.9     ! raeburn    46: # Check for existing session, and temporarily delete any form items
        !            47: # in %env, if session exists
        !            48: #
        !            49:     my %savedform;
        !            50:     my $handle = &Apache::lonnet::check_for_valid_session($r);
        !            51:     if ($handle ne '') {
        !            52:         foreach my $key (sort(keys(%env))) {
        !            53:             if ($key =~ /^form\.(.+)$/) {
        !            54:                 $savedform{$1} = $env{$key};
        !            55:                 delete($env{$key});
        !            56:             }
        !            57:         }
        !            58:     }
        !            59: #
1.1       raeburn    60: # Retrieve data POSTed by LTI Consumer on launch  
                     61: #
                     62:     &Apache::lonacc::get_posted_cgi($r);
                     63:     my $params = {};
                     64:     foreach my $key (sort(keys(%env))) {
                     65:         if ($key =~ /^form\.(.+)$/) {
                     66:             $params->{$1} = $env{$key};
                     67:         }
                     68:     }
1.9     ! raeburn    69: #
        !            70: # Check for existing session, and restored temporarily
        !            71: # deleted form items to %env, if session exists.
        !            72: #
        !            73:     if ($handle ne '') {
        !            74:         if (keys(%savedform)) {
        !            75:             foreach my $key (sort(keys(%savedform))) {
        !            76:                 $env{'form.'.$key} = $savedform{$key};
        !            77:             }
        !            78:         }
        !            79:     }
1.1       raeburn    80: 
                     81:     unless (keys(%{$params})) {
                     82:         &invalid_request($r,1);
                     83:         return OK;
                     84:     }
                     85: 
                     86:     unless ($params->{'oauth_consumer_key'} &&
                     87:             $params->{'oauth_nonce'} &&
                     88:             $params->{'oauth_timestamp'} &&
                     89:             $params->{'oauth_version'} &&
                     90:             $params->{'oauth_signature'} &&
                     91:             $params->{'oauth_signature_method'}) {
                     92:         &invalid_request($r,2);
                     93:         return OK;
                     94:     }
                     95: 
                     96: #
                     97: # Retrieve "internet domains" for all this institution's LON-CAPA
                     98: # nodes.
                     99: #
                    100:     my ($udom,$uname,$uhome,$cdom,$cnum,$symb,$mapurl,@intdoms);
                    101:     my $lonhost = $r->dir_config('lonHostID');
                    102:     my $internet_names = &Apache::lonnet::get_internet_names($lonhost);
                    103:     if (ref($internet_names) eq 'ARRAY') {
                    104:         @intdoms = @{$internet_names};
                    105:     }
                    106: 
                    107: #
                    108: # For user who launched LTI in Consumer, determine user's domain in 
                    109: # LON-CAPA.
                    110: #
                    111: # Order is:
                    112: #
                    113: # (a) from custom_userdomain item in POSTed data
                    114: # (b) from lis_person_sourcedid in POSTed data
                    115: # (c) from default "log-in" domain for node
                    116: #     (can support multidomain servers, where specific domain is 
                    117: #      first part of hostname).
                    118: #
                    119: # Note: "internet domain" for user's domain must be one of the
                    120: # "internet domain(s)" for the institution's LON-CAPA servers.
                    121: #
                    122:     if (exists($params->{'custom_userdomain'})) {
                    123:         if ($params->{'custom_userdomain'} =~ /^$match_domain$/) {
                    124:             my $uprimary_id = &Apache::lonnet::domain($params->{'custom_userdomain'},'primary');
                    125:             if ($uprimary_id ne '') {
                    126:                 my $uintdom = &Apache::lonnet::internet_dom($uprimary_id);
                    127:                 if (($uintdom ne '') && (grep(/^\Q$uintdom\E$/,@intdoms))) {
                    128:                     $udom = $params->{'custom_userdomain'};
                    129:                 }
                    130:             }
                    131:         }
                    132:     }
                    133:     my $defdom = &Apache::lonnet::default_login_domain();
                    134:     my ($domain,$possuname,$possudom,$possmapuser);
                    135:     if ($env{'form.lis_person_sourcedid'} =~ /^($match_username)\:($match_domain)$/) {
                    136:         ($possuname,$possudom) = ($1,$2);
                    137:         if ($udom eq '') {
                    138:             my $uintdom = &Apache::lonnet::domain($possudom,'primary');
                    139:             if (($uintdom ne '') && (grep(/^\Q$uintdom\E$/,@intdoms))) {
                    140:                 $udom = $possudom;
                    141:                 $possmapuser = 'lis_person_sourcedid';
                    142:             } else {
                    143:                 $udom = $defdom;
                    144:             }
                    145:         } elsif ($udom eq $possudom) {
                    146:             $possmapuser = 'lis_person_sourcedid';
                    147:         }
                    148:     }
                    149:     unless ($possuname) {
                    150:         if ($env{'form.lis_person_sourcedid'} =~ /^$match_username$/) {
                    151:             $possuname = $env{'form.lis_person_sourcedid'};
                    152:             $possmapuser = 'lis_person_sourcedid';
                    153:         } elsif ($env{'form.lis_person_contact_email_primary'} =~ /^$match_username$/) {
                    154:             $possuname = $env{'form.lis_person_contact_email_primary'};
                    155:             $possmapuser = 'lis_person_contact_email_primary';
                    156:         }
                    157:         unless ($udom) {
                    158:             $udom = $defdom;
                    159:         }
                    160:     }
                    161: 
                    162: #
                    163: # Determine course's domain in LON-CAPA
                    164: #
                    165: # Order is:
                    166: #
                    167: # (a) from custom_coursedomain item in POSTed data
1.9     ! raeburn   168: # (b) from tail of requested URL (after /adm/lti/) if it has format of a symb  
1.1       raeburn   169: # (c) from tail of requested URL (after /adm/lti) if it has format of a map 
                    170: # (d) from tail of requested URL (after /adm/lti) if it has format /domain/courseID
1.5       raeburn   171: # (e) from tail of requested URL (after /adm/lti) if it has format /tiny/domain/\w+
                    172: #     i.e., a shortened URL (see bug #6400).
1.1       raeburn   173: # (f) same as user's domain 
                    174: #
                    175: # Request invalid if custom_coursedomain is defined and is inconsistent with
                    176: # domain contained in requested URL.
                    177: #
                    178: # Note: "internet domain" for course's domain must be one of the
                    179: # internet domains for the institution's LON-CAPA servers.
                    180: #
                    181: 
                    182:     if (exists($params->{'custom_coursedomain'})) {
                    183:         if ($params->{'custom_coursedomain'} =~ /^$match_domain$/) {
                    184:             my $cprimary_id = &Apache::lonnet::domain($params->{'custom_coursedomain'},'primary');
                    185:             if ($cprimary_id ne '') {
                    186:                 my $cintdom = &Apache::lonnet::internet_dom($cprimary_id);
                    187:                 if (($cintdom ne '') && (grep(/^\Q$cintdom\E$/,@intdoms))) {
                    188:                     $cdom = $params->{'custom_coursedomain'};
                    189:                 }
                    190:             }
                    191:         }
                    192:     }
                    193: 
                    194:     my ($tail) = ($requri =~ m{^/adm/lti(|/.*)$});
                    195:     my $urlcnum;
                    196:     if ($tail ne '') {
                    197:         my $urlcdom;
                    198:         if ($tail =~ m{^/uploaded/($match_domain)/($match_courseid)/(?:default|supplemental)(?:|_\d+)\.(?:sequence|page)(|___\d+___.+)$}) {
                    199:             ($urlcdom,$urlcnum,my $rest) = ($1,$2,$3);
                    200:             if (($cdom ne '') && ($cdom ne $urlcdom)) {
                    201:                 &invalid_request($r,3);
                    202:                 return OK;
                    203:             }
                    204:             if ($rest eq '') {
                    205:                 $mapurl = $tail;
                    206:             } else {
                    207:                 $symb = $tail;
                    208:                 $symb =~ s{^/+}{};
                    209:             }
1.9     ! raeburn   210:         } elsif ($tail =~ m{^/res/(?:$match_domain)/(?:$match_username)/.+\.(?:sequence|page)(|___\d+___.+)$}) {
        !           211:             if ($1 eq '') {
        !           212:                 $mapurl = $tail;
        !           213:             } else {
        !           214:                 $symb = $tail;
        !           215:                 $symb =~ s{^/+}{};
        !           216:             }
1.1       raeburn   217:         } elsif ($tail =~ m{^/($match_domain)/($match_courseid)$}) {
                    218:             ($urlcdom,$urlcnum) = ($1,$2);
                    219:             if (($cdom ne '') && ($cdom ne $urlcdom)) {
                    220:                 &invalid_request($r,4);
                    221:                 return OK;
                    222:             }
1.5       raeburn   223:         } elsif ($tail =~ m{^/tiny/($match_domain)/(\w+)$}) {
                    224:             ($urlcdom,my $key) = ($1,$2);
                    225:             if (($cdom ne '') && ($cdom ne $urlcdom)) {
                    226:                 &invalid_request($r,5);
                    227:                 return OK;
                    228:             }
                    229:             my $tinyurl;
                    230:             my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$urlcdom."\0".$key);
                    231:             if (defined($cached)) {
                    232:                 $tinyurl = $result;
                    233:             } else {
                    234:                 my $configuname = &Apache::lonnet::get_domainconfiguser($urlcdom);
                    235:                 my %currtiny = &Apache::lonnet::get('tiny',[$key],$urlcdom,$configuname);
                    236:                 if ($currtiny{$key} ne '') {
                    237:                     $tinyurl = $currtiny{$key};
                    238:                     &Apache::lonnet::do_cache_new('tiny',$urlcdom."\0".$key,$currtiny{$key},600);
                    239:                 }
                    240:             }
                    241:             if ($tinyurl ne '') {
                    242:                 $urlcnum = (split(/\&/,$tinyurl))[0];
                    243:             }
1.1       raeburn   244:         }
                    245:         if (($cdom eq '') && ($urlcdom ne '')) { 
                    246:             my $cprimary_id = &Apache::lonnet::domain($urlcdom,'primary');
                    247:             if ($cprimary_id ne '') {
                    248:                 my $cintdom = &Apache::lonnet::internet_dom($cprimary_id);
                    249:                 if (($cintdom ne '') && (grep(/^\Q$cintdom\E$/,@intdoms))) {
                    250:                     $cdom = $urlcdom;
                    251:                 }
                    252:             } else {
                    253:                 $urlcnum = '';
                    254:             }
                    255:         }
                    256:     }
                    257:     if ($cdom eq '') {
                    258:         if ($udom ne '') {
                    259:             $cdom = $udom;
                    260:         } else {
                    261:             $cdom = $defdom;
                    262:         }
                    263:     }
                    264: 
                    265: #
                    266: # Retrieve information for LTI Consumers in course domain
                    267: # and populate hash --  %lti_by_key -- for which keys
                    268: # are those defined in domain configuration for LTI.
                    269: #
                    270:  
                    271:     my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider');
                    272:     unless (keys(%lti) > 0) {
1.5       raeburn   273:         &invalid_request($r,6);
1.1       raeburn   274:         return OK;
                    275:     }
                    276:     my %lti_by_key;
                    277:     if (keys(%lti)) {
                    278:         foreach my $id (keys(%lti)) {
                    279:             if (ref($lti{$id}) eq 'HASH') {
                    280:                 my $key = $lti{$id}{'key'};
                    281:                 push(@{$lti_by_key{$key}},$id);
                    282:             }
                    283:         }
                    284:     }
                    285: 
                    286: #
                    287: # Verify the signed request using the secret for those
                    288: # Consumers for which the key in the POSTed data matches 
                    289: # keys in the domain configuration for LTI.
                    290: #
                    291:     my $hostname = $r->hostname;
                    292:     my $protocol = 'http';
                    293:     if ($ENV{'SERVER_PORT'} == 443) {
                    294:         $protocol = 'https';
                    295:     }
                    296: 
1.6       raeburn   297:     my ($itemid,$consumer_key,$secret);
1.3       raeburn   298:     $consumer_key = $params->{'oauth_consumer_key'};
                    299:     if (ref($lti_by_key{$consumer_key}) eq 'ARRAY') {
                    300:         foreach my $id (@{$lti_by_key{$consumer_key}}) {
1.1       raeburn   301:             if (ref($lti{$id}) eq 'HASH') {
1.2       raeburn   302:                 $secret = $lti{$id}{'secret'};
1.1       raeburn   303:                 my $request = Net::OAuth->request('request token')->from_hash($params,
                    304:                                                    request_url => $protocol.'://'.$hostname.$requri,
                    305:                                                    request_method => $env{'request.method'},
                    306:                                                    consumer_secret => $secret,);
                    307:                 if ($request->verify()) {
                    308:                     $itemid = $id;
                    309:                     last;
                    310:                 }
                    311:             }
                    312:         }
                    313:     }
                    314: 
                    315: #
                    316: # Request is invalid if the signed request could not be verified
                    317: # for the Consumer key and Consumer secret from the domain
                    318: # configuration in LON-CAPA for that LTI Consumer.
                    319: #
                    320:     unless (($itemid) && (ref($lti{$itemid}) eq 'HASH')) {
1.5       raeburn   321:         &invalid_request($r,7);
1.1       raeburn   322:         return OK;
                    323:     }
                    324: 
                    325: #
                    326: # Determine if nonce in POSTed data has expired.
                    327: # If unexpired, confirm it has not already been used.
                    328: #
1.2       raeburn   329:     unless (&LONCAPA::ltiutils::check_nonce($params->{'oauth_nonce'},$params->{'oauth_timestamp'},
                    330:                                             $lti{$itemid}{'lifetime'},$cdom,$r->dir_config('lonLTIDir'))) {
1.5       raeburn   331:         &invalid_request($r,8);
1.1       raeburn   332:         return OK;
                    333:     }
                    334: 
                    335: #
1.6       raeburn   336: # Determine if source of username matches requirement from the 
1.1       raeburn   337: # domain configuration for the specific LTI Consumer.
                    338: # 
                    339: 
                    340:     if ($lti{$itemid}{'mapuser'} eq $possmapuser) {
                    341:         $uname = $possuname;
                    342:     } elsif ($lti{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {
                    343:         if ($params->{'lis_person_sourcedid'} =~ /^$match_username$/) {
                    344:             $uname = $possuname;
                    345:         }
                    346:     } elsif ($lti{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {
                    347:         if ($params->{'lis_person_contact_email_primary'} =~ /^$match_username$/) {
                    348:             $uname = $params->{'lis_person_contact_email_primary'};
                    349:         }
                    350:     } elsif (exists($params->{$lti{$itemid}{'mapuser'}})) {
                    351:         if ($params->{$lti{$itemid}{'mapuser'}} =~ /^$match_username$/) {
                    352:             $uname = $params->{$lti{$itemid}{'mapuser'}};
                    353:         }
                    354:     }
                    355: 
                    356: #
                    357: # Determine the courseID of the LON-CAPA course to which the
                    358: # launch of LON-CAPA should provide access.
                    359: #
                    360: # Order is:
                    361: #
                    362: # (a) from course mapping (if the link between Consumer "course" and 
                    363: # Provider "course" has been established previously).
1.9     ! raeburn   364: # (b) from tail of requested URL (after /adm/lti/) if it has format of a symb
1.1       raeburn   365: # (c) from tail of requested URL (after /adm/lti) if it has format of a map
                    366: # (d) from tail of requested URL (after /adm/lti) if it has format /domain/courseID
1.5       raeburn   367: # (e) from tail of requested URL (after /adm/lti) if it has format /tiny/domain/\w+
                    368: #     i.e., a shortened URL (see bug #6400).
1.1       raeburn   369: #
                    370: # If Consumer course included in POSTed data points as a target course which
                    371: # has a format which matches a LON-CAPA courseID, but the course does not
                    372: # exist, the request is invalid.
                    373: # 
                    374: 
                    375:     my ($sourcecrs,%consumers);
                    376:     if ($lti{$itemid}{'mapcrs'} eq 'course_offering_sourcedid') {
                    377:         $sourcecrs = $params->{'course_offering_sourcedid'};
                    378:     } elsif ($lti{$itemid}{'mapcrs'} eq 'context_id') {
                    379:         $sourcecrs = $params->{'context_id'};
                    380:     } elsif ($lti{$itemid}{'mapcrs'} ne '') {
                    381:         $sourcecrs = $params->{$lti{$itemid}{'mapcrs'}};
                    382:     }
                    383: 
                    384:     my $posscnum;
                    385:     if ($sourcecrs ne '') {
                    386:         %consumers = &Apache::lonnet::get_dom('lticonsumers',[$sourcecrs],$cdom);
                    387:         if (exists($consumers{$sourcecrs})) {
                    388:             if ($consumers{$sourcecrs} =~ /^$match_courseid$/) {
                    389:                 my $crshome = &Apache::lonnet::homeserver($consumers{$sourcecrs},$cdom);
                    390:                 if ($crshome =~ /(con_lost|no_host|no_such_host)/) {
1.5       raeburn   391:                     &invalid_request($r,9);
1.1       raeburn   392:                     return OK;
                    393:                 } else {
                    394:                     $posscnum = $consumers{$sourcecrs};
                    395:                 }
                    396:             }
                    397:         }
                    398:     }
                    399: 
                    400:     if ($urlcnum ne '') {
                    401:         if ($posscnum ne '') {
                    402:             if ($posscnum ne $urlcnum) {
1.5       raeburn   403:                 &invalid_request($r,10);
1.1       raeburn   404:                 return OK;
                    405:             } else {
                    406:                 $cnum = $posscnum;
                    407:             }
                    408:         } else {
                    409:             my $crshome = &Apache::lonnet::homeserver($urlcnum,$cdom);
                    410:             if ($crshome =~ /(con_lost|no_host|no_such_host)/) {
1.5       raeburn   411:                 &invalid_request($r,11);
1.1       raeburn   412:                 return OK;
                    413:             } else {
                    414:                 $cnum = $urlcnum;
                    415:             }
                    416:         }
                    417:     } elsif ($posscnum ne '') {
                    418:         $cnum = $posscnum;
                    419:     }
                    420: 
                    421: #
1.6       raeburn   422: # Get LON-CAPA role(s) to use from role-mapping of Consumer roles
1.1       raeburn   423: # defined in domain configuration for the appropriate LTI
                    424: # Consumer.
                    425: #
1.6       raeburn   426: # If multiple LON-CAPA roles are indicated for the current user,
                    427: # ordering (from first to last) is: cc/co, in, ta, ep, st.
1.1       raeburn   428: #
                    429: 
1.6       raeburn   430:     my (@ltiroles,@lcroles);
1.1       raeburn   431: 
1.6       raeburn   432:     my @lcroleorder = ('cc','in','ta','ep','st');
                    433:     my @ltiroleorder = ('Instructor','TeachingAssistant','Mentor','Learner');
1.1       raeburn   434:     if ($params->{'roles'} =~ /,/) {
1.6       raeburn   435:         my @possltiroles = split(/\s*,\s*/,$params->{'role'});
                    436:         foreach my $ltirole (@ltiroleorder) {
                    437:             if (grep(/^\Q$ltirole\E$/,@possltiroles)) {
                    438:                 push(@ltiroles,$ltirole);
                    439:             }
                    440:         }
1.1       raeburn   441:     } else {
                    442:         my $singlerole = $params->{'roles'};
                    443:         $singlerole =~ s/^\s|\s+$//g;
1.6       raeburn   444:         if (grep(/^\Q$singlerole\E$/,@ltiroleorder)) {
                    445:             @ltiroles = ($singlerole);
                    446:         }
1.1       raeburn   447:     }
                    448:     if (@ltiroles) {
                    449:         if (ref($lti{$itemid}{maproles}) eq 'HASH') {
                    450:             my %possroles;
                    451:             map { $possroles{$lti{$itemid}{maproles}{$_}} = 1; } @ltiroles;
1.6       raeburn   452:             if (keys(%possroles) > 0) {
                    453:                 foreach my $item (@lcroleorder) {
1.1       raeburn   454:                     if ($possroles{$item}) {
1.6       raeburn   455:                         push(@lcroles,$item);
1.1       raeburn   456:                     }
                    457:                 }
                    458:             }
                    459:         }
                    460:     }
                    461: 
                    462: #
                    463: # If no LON-CAPA username  -- is user allowed to create one?
                    464: #
                    465: 
                    466:     my $selfcreate;
                    467:     if (($uname ne '') && ($udom ne '')) {
                    468:         $uhome = &Apache::lonnet::homeserver($uname,$udom);
                    469:         if ($uhome =~ /(con_lost|no_host|no_such_host)/) {
                    470:             &Apache::lonnet::logthis(" LTI authorized unknown user $uname:$udom ");
                    471:             if (ref($lti{$itemid}{'makeuser'}) eq 'ARRAY') {
                    472:                 if (@{$lti{$itemid}{'makeuser'}} > 0) {
                    473:                     foreach my $ltirole (@ltiroles) {
                    474:                         if (grep(/^\Q$ltirole\E$/,@{$lti{$itemid}{'makeuser'}})) {
                    475:                             $selfcreate = 1;
1.6       raeburn   476:                             last;
1.1       raeburn   477:                         }
                    478:                     }
                    479:                 }
                    480:             }
                    481:             if ($selfcreate) {
1.6       raeburn   482:                 my (%rulematch,%inst_results,%curr_rules,%got_rules,%alerts,%info);
                    483:                 my $checkhash = { "$uname:$udom" => { 'newuser' => 1, }, };
                    484:                 my $checks = { 'username' => 1, };
                    485:                 &Apache::loncommon::user_rule_check($checkhash,$checks,\%alerts,\%rulematch,
                    486:                                                     \%inst_results,\%curr_rules,\%got_rules);
                    487:                 my ($userchkmsg,$lcauth,$lcauthparm);
                    488:                 my $allowed = 1;
                    489:                 if (ref($alerts{'username'}) eq 'HASH') {
                    490:                     if (ref($alerts{'username'}{$udom}) eq 'HASH') {
                    491:                         my $domdesc =
                    492:                             &Apache::lonnet::domain($udom,'description');
                    493:                         if ($alerts{'username'}{$udom}{$uname}) {
                    494:                             if (ref($curr_rules{$udom}) eq 'HASH') {
                    495:                                 $userchkmsg =
                    496:                                     &Apache::loncommon::instrule_disallow_msg('username',$domdesc,1).
                    497:                                     &Apache::loncommon::user_rule_formats($udom,$domdesc,
                    498:                                                                           $curr_rules{$udom}{'username'},
                    499:                                                                            'username');
                    500:                             }
                    501:                             $allowed = 0;
                    502:                         }
                    503:                     }
                    504:                 }
                    505:                 if ($allowed) {
                    506:                     if (ref($rulematch{$uname.':'.$udom}) eq 'HASH') {
                    507:                         my $matchedrule = $rulematch{$uname.':'.$udom}{'username'};
                    508:                         my ($rules,$ruleorder) =
                    509:                             &Apache::lonnet::inst_userrules($udom,'username');
                    510:                         if (ref($rules) eq 'HASH') {
                    511:                             if (ref($rules->{$matchedrule}) eq 'HASH') {
                    512:                                 $lcauth = $rules->{$matchedrule}{'authtype'};
                    513:                                 $lcauthparm = $rules->{$matchedrule}{'authparm'};
                    514:                             }
                    515:                         }
                    516:                     }
                    517:                     if ($lcauth eq '') {
                    518:                         $lcauth = $lti{$itemid}{'lcauth'};
1.7       raeburn   519:                         if ($lcauth eq 'internal') {
                    520:                             $lcauthparm = &create_passwd();
                    521:                         } else {
                    522:                             $lcauthparm = $lti{$itemid}{'lcauthparm'};
                    523:                         }
1.6       raeburn   524:                     }
                    525:                 } else {
                    526:                     &invalid_request($r,12);
                    527:                 }
                    528:                 my @userinfo = ('firstname','middlename','lastname','generation',
                    529:                                 'permanentemail','id');
                    530:                 my %useinstdata;
                    531:                 if (ref($lti{$itemid}{'instdata'}) eq 'ARRAY') {
                    532:                     map { $useinstdata{$_} = 1; } @{$lti{$itemid}{'instdata'}};
                    533:                 }
                    534:                 foreach my $item (@userinfo) {
                    535:                     if (($useinstdata{$item}) && (ref($inst_results{$uname.':'.$udom}) eq 'HASH') &&
                    536:                         ($inst_results{$uname.':'.$udom}{$item} ne '')) {
                    537:                         $info{$item} = $inst_results{$uname.':'.$udom}{$item};
                    538:                     } else {
                    539:                         if ($item eq 'permanentemail') {
                    540:                             if ($env{'form.lis_person_contact_email_primary'} =~/^[^\@]+\@[^@]+$/) {
                    541:                                 $info{$item} = $env{'form.lis_person_contact_email_primary'};
                    542:                             }
                    543:                         } elsif ($item eq 'firstname') {
                    544:                             $info{$item} = $env{'form.lis_person_name_given'};
                    545:                         } elsif ($item eq 'lastname') {
                    546:                             $info{$item} = $env{'form.lis_person_name_family'};
                    547:                         }
                    548:                     }
                    549:                 }
                    550:                 if (($info{'middlename'} eq '') && ($env{'form.lis_person_name_full'} ne '')) {
                    551:                     unless ($useinstdata{'middlename'}) {
                    552:                         my $fullname = $env{'form.lis_person_name_full'};
                    553:                         if ($info{'firstname'}) {
                    554:                             $fullname =~ s/^\s*\Q$info{'firstname'}\E\s*//i;
                    555:                         }
                    556:                         if ($info{'lastname'}) {
                    557:                             $fullname =~ s/\s*\Q$info{'lastname'}\E\s*$//i;
                    558:                         }
                    559:                         if ($fullname ne '') {
                    560:                             $fullname =~ s/^\s+|\s+$//g;
                    561:                             if ($fullname ne '') {
                    562:                                 $info{'middlename'} = $fullname;
                    563:                             }
                    564:                         }
                    565:                     }
                    566:                 }
                    567:                 if (ref($inst_results{$uname.':'.$udom}{'inststatus'}) eq 'ARRAY') {
                    568:                     my @inststatuses = @{$inst_results{$uname.':'.$udom}{'inststatus'}};
                    569:                     $info{'inststatus'} = join(':',map { &escape($_); } @inststatuses);
                    570:                 }
                    571:                 my $result =
                    572:                     &Apache::lonnet::modifyuser($udom,$uname,$info{'id'},
                    573:                                                 $lcauth,$lcauthparm,$info{'firstname'},
                    574:                                                 $info{'middlename'},$info{'lastname'},
                    575:                                                 $info{'generation'},undef,undef,
                    576:                                                 $info{'permanentemail'},$info{'inststatus'});
                    577:                 if ($result eq 'ok') {
                    578:                     if (($ltiroles[0] eq 'Instructor') && ($lcroles[0] eq 'cc') && ($lti{$itemid}{'mapcrs'}) &&
                    579:                         ($lti{$itemid}{'makecrs'})) {
                    580:                         unless (&Apache::lonnet::usertools_access($uname,$udom,'lti','reload','requestcourses')) {
                    581:                             &Apache::lonnet::put('environment',{ 'requestcourses.lti' => 1, },$udom,$uname);
                    582:                         }
                    583:                     }
                    584:                 } else {
                    585:                     &invalid_request($r,13);
                    586:                     return OK;
                    587:                 }
1.1       raeburn   588:             } else {
1.6       raeburn   589:                 &invalid_request($r,14);
1.1       raeburn   590:                 return OK;
1.6       raeburn   591:             }
                    592:         }
1.1       raeburn   593:     } else {
1.6       raeburn   594:         &invalid_request($r,15);
1.1       raeburn   595:         return OK;
                    596:     }
                    597: 
                    598: #
                    599: # If no LON-CAPA course available, check if domain's configuration
                    600: # for the specific LTI Consumer allows a new course to be created 
1.6       raeburn   601: # (requires role in Consumer to be: Instructor and Instructor to map to CC)
1.1       raeburn   602: #
                    603: 
1.6       raeburn   604:     my $reqcrs;
1.1       raeburn   605:     if ($cnum eq '') {
1.6       raeburn   606:         if ((@ltiroles) && ($lti{$itemid}{'mapcrs'}) &&
                    607:             ($ltiroles[0] eq 'Instructor') && ($lcroles[0] eq 'cc') && ($lti{$itemid}{'makecrs'})) {
                    608:             my (%can_request,%request_domains);
                    609:             &Apache::lonnet::check_can_request($cdom,\%can_request,\%request_domains,$uname,$udom);
                    610:             if ($can_request{'lti'}) {
                    611:                 $reqcrs = 1;
                    612:                 &lti_session($r,$itemid,$uname,$udom,$uhome,$lonhost,undef,$mapurl,$tail,
                    613:                              $symb,$cdom,$cnum,$params,\@ltiroles,$lti{$itemid},\@lcroles,
                    614:                              $reqcrs,$sourcecrs);
                    615:             } else {
                    616:                 &invalid_request($r,16);
                    617:             }
1.1       raeburn   618:         } else {
1.6       raeburn   619:             &invalid_request($r,17);
1.1       raeburn   620:         }
1.6       raeburn   621:         return OK;
1.1       raeburn   622:     }
                    623: 
                    624: #
                    625: # If LON-CAPA course is a Community, and LON-CAPA role
                    626: # indicated is cc, change role indicated to co.
                    627: # 
                    628: 
1.6       raeburn   629:     my %crsenv;
                    630:     if ($lcroles[0] eq 'cc') {
1.1       raeburn   631:         if (($cdom ne '') && ($cnum ne '')) {
1.6       raeburn   632:             %crsenv = &Apache::lonnet::coursedescription($cdom.'_'.$cnum,{ 'one_time' => 1,});
1.1       raeburn   633:             if ($crsenv{'type'} eq 'Community') {
1.6       raeburn   634:                 $lcroles[0] = 'co';
                    635:             }
                    636:         }
                    637:     }
                    638: 
                    639: #
                    640: # Determine if user has a LON-CAPA role in the mapped LON-CAPA course.
                    641: # If multiple LON-CAPA roles are available for the user's assigned LTI roles,
                    642: # choose the first available LON-CAPA role in the order: cc/co, in, ta, ep, st
                    643: #
                    644: 
                    645:     my ($role,$usec,$withsec);
                    646:     unless ((($lcroles[0] eq 'cc') || ($lcroles[0] eq 'co')) && (@lcroles == 1)) {
                    647:         if ($lti{$itemid}{'section'} ne '') {
                    648:             if ($lti{$itemid}{'section'} eq 'course_section_sourcedid') {
                    649:                 if ($env{'form.course_section_sourcedid'} !~ /\W/) {
                    650:                     $usec = $env{'form.course_section_sourcedid'};
                    651:                 }
                    652:             } elsif ($env{'form.'.$lti{$itemid}{'section'}} !~ /\W/) {
                    653:                 $usec = $env{'form.'.$lti{$itemid}{'section'}};
                    654:             }
                    655:         }
                    656:         if ($usec ne '') {
                    657:             $withsec = 1;
                    658:         }
                    659:     }
                    660: 
                    661:     if (@lcroles) {
                    662:         my %crsroles = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',undef,\@lcroles,
                    663:                                                      [$cdom],$withsec);
                    664:         foreach my $reqrole (@lcroles) {
                    665:             if ($withsec) {
                    666:                 my $incsec;
                    667:                 if (($reqrole eq 'cc') || ($reqrole eq 'co')) {
                    668:                     $incsec = '';
                    669:                 } else {
                    670:                     $incsec = $usec;
                    671:                 }
                    672:                 if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole.':'.$incsec})) {
                    673:                     $role = $reqrole.'./'.$cdom.'/'.$cnum;
                    674:                     if ($incsec ne '') {
                    675:                         $role .= '/'.$usec;
                    676:                     }
                    677:                     last;
                    678:                 }
                    679:             } else {
                    680:                 if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole})) {
                    681:                     $role = $reqrole.'./'.$cdom.'/'.$cnum;
                    682:                     last;
                    683:                 }
1.1       raeburn   684:             }
                    685:         }
                    686:     }
                    687: 
                    688: #
1.6       raeburn   689: # Determine if user can selfenroll
1.1       raeburn   690: #
                    691: 
1.6       raeburn   692:     my ($reqrole,$selfenrollrole);
                    693:     if ($role eq '') {
                    694:         if ((@ltiroles) && (ref($lti{$itemid}{'selfenroll'}) eq 'ARRAY')) {
                    695:             foreach my $ltirole (@ltiroles) {
                    696:                 if (grep(/^\Q$ltirole\E$/,@{$lti{$itemid}{'selfenroll'}})) {
                    697:                     if (ref($lti{$itemid}{maproles}) eq 'HASH') {
                    698:                         $reqrole = $lti{$itemid}{maproles}{$ltirole};
                    699:                         last;
                    700:                     }
                    701:                 }
                    702:             }
                    703:         }
                    704:         if ($reqrole eq '') {
                    705:             &invalid_request($r,18);
1.1       raeburn   706:             return OK;
                    707:         } else {
1.6       raeburn   708:             unless (%crsenv) {
                    709:                 %crsenv = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                    710:             }
                    711:             my $default_enrollment_start_date = $crsenv{'default_enrollment_start_date'};
                    712:             my $default_enrollment_end_date   = $crsenv{'default_enrollment_end_date'};
                    713:             my $now = time;
                    714:             if ($default_enrollment_end_date && $default_enrollment_end_date <= $now) {
                    715:                 &invalid_request($r,19);
                    716:                 return OK;
                    717:             } elsif ($default_enrollment_start_date && $default_enrollment_start_date >$now) {
                    718:                 &invalid_request($r,20);
                    719:                 return OK;
                    720:             } else {
                    721:                 $selfenrollrole = $reqrole.'./'.$cdom.'/'.$cnum;
                    722:                 if (($withsec) && ($reqrole ne 'cc') && ($reqrole ne 'co')) {
                    723:                     if ($usec ne '') {
                    724:                         $selfenrollrole .= '/'.$usec;
                    725:                     }
                    726:                 }
                    727:             }
1.1       raeburn   728:         }
                    729:     }
                    730: 
                    731: #
                    732: # Store consumer-to-LON-CAPA course mapping
                    733: #
1.6       raeburn   734: 
1.1       raeburn   735:     if (($sourcecrs ne '')  && ($consumers{$sourcecrs} eq '') && ($cnum ne '')) {
                    736:         &Apache::lonnet::put_dom('lticonsumers',{ $sourcecrs => $cnum },$cdom);
                    737:     }
                    738: 
                    739: #
1.6       raeburn   740: # Start user session
                    741: #
                    742: 
                    743:     &lti_session($r,$itemid,$uname,$udom,$uhome,$lonhost,$role,$mapurl,$tail,$symb,
                    744:                  $cdom,$cnum,$params,\@ltiroles,$lti{$itemid},\@lcroles,undef,$sourcecrs,
                    745:                  $selfenrollrole);
                    746:     return OK;
                    747: }
                    748: 
                    749: sub lti_enroll {
                    750:     my ($uname,$udom,$selfenrollrole) = @_;
                    751:     my $enrollresult;
                    752:     my ($role,$cdom,$cnum,$sec) =
                    753:            ($selfenrollrole =~ m{^(\w+)\./($match_domain)/($match_courseid)(?:|/(\w*))$});
                    754:     if (($cnum ne '') && ($cdom ne '')) {
                    755:         my $chome = &Apache::lonnet::homeserver($cnum,$cdom);
                    756:         if ($chome ne 'no_host') {
                    757:             my %coursehash = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                    758:             my $start = $coursehash{'default_enrollment_start_date'};
                    759:             my $end = $coursehash{'default_enrollment_end_date'};
                    760:             my $area = "/$cdom/$cnum";
                    761:             if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) {
                    762:                 $area .= '/'.$sec;
                    763:             }
                    764:             my $spec = $role.'.'.$area;
                    765:             my $instcid;
                    766:             if ($role eq 'st') {
                    767:                 $enrollresult =
                    768:                     &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,
                    769:                                                                undef,undef,$sec,$end,$start,
                    770:                                                                'ltienroll',undef,$cdom.'_'.$cnum,1,
                    771:                                                                'ltienroll','',$instcid);
                    772:             } elsif ($role =~ /^(cc|in|ta|ep)$/) {
                    773:                 $enrollresult =
                    774:                     &Apache::lonnet::assignrole($udom,$uname,$area,$role,$end,$start,
                    775:                                                 undef,1,'ltienroll');
                    776:             }
                    777:             if ($enrollresult eq 'ok') {
                    778:                 my (%userroles,%newrole,%newgroups);
                    779:                 &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum,
                    780:                                                     $area);
                    781:                 &Apache::lonnet::set_userprivs(\%userroles,\%newrole,\%newgroups);
                    782:                 $userroles{'user.role.'.$spec} = $start.'.'.$end;
                    783:                 &Apache::lonnet::appenv(\%userroles,[$role,'cm']);
                    784:             }
                    785:         }
                    786:     }
                    787:     return $enrollresult;
                    788: }
                    789: 
                    790: sub lti_reqcrs {
                    791:     my ($r,$cdom,$form,$uname,$udom) = @_;
                    792:     my (%can_request,%request_domains);
                    793:     &Apache::lonnet::check_can_request($cdom,\%can_request,\%request_domains,$uname,$udom);
                    794:     if ($can_request{'lti'}) {
                    795:         my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$cdom);
                    796:         my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
                    797:         &Apache::lonrequestcourse::print_textbook_form($r,$cdom,[$cdom],\%domdefs,
                    798:                                                        $domconfig{'requestcourses'},
                    799:                                                        \%can_request,'lti',$form);
                    800:     } else {
                    801:         $r->print(
                    802:               &Apache::loncommon::start_page('Invalid LTI call',undef,{'only_body' => 1}).
                    803:               &mt('Invalid LTI call').
                    804:               &Apache::loncommon::end_page()
                    805:         );
                    806:     }
                    807: }
                    808: 
                    809: sub lti_session {
                    810:     my ($r,$itemid,$uname,$udom,$uhome,$lonhost,$role,$mapurl,$tail,$symb,$cdom,$cnum,
                    811:         $params,$ltiroles,$ltihash,$lcroles,$reqcrs,$sourcecrs,$selfenrollrole) = @_;
                    812:     return unless ((ref($params) eq 'HASH') && (ref($ltiroles) eq 'ARRAY') &&
                    813:                    (ref($ltihash) eq 'HASH') && (ref($lcroles) eq 'ARRAY'));
                    814: #
1.1       raeburn   815: # Check if user should be hosted here or switched to another server.
                    816: #
                    817:     $r->user($uname);
1.6       raeburn   818:     if ($cnum) {
                    819:         if ($role) {
                    820:             &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, role: $role, course: $cdom\_$cnum");
                    821:         } elsif ($selfenrollrole =~ m{^(\w+)\./$cdom/$cnum}) {
                    822:             &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, desired role: $1 course: $cdom\_$cnum");
                    823:         }
                    824:     } else {
                    825:         &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, course dom: $cdom");
                    826:     }
1.1       raeburn   827:     my ($is_balancer,$otherserver,$hosthere);
                    828:     ($is_balancer,$otherserver) =
                    829:         &Apache::lonnet::check_loadbalancing($uname,$udom,'login');
                    830:     if ($is_balancer) {
                    831:         if ($otherserver eq '') {
                    832:             my $lowest_load;
                    833:             ($otherserver,undef,undef,undef,$lowest_load) = &Apache::lonnet::choose_server($udom);
                    834:             if ($lowest_load > 100) {
                    835:                 $otherserver = &Apache::lonnet::spareserver($lowest_load,$lowest_load,1,$udom);
                    836:             }
                    837:         }
                    838:         if ($otherserver ne '') {
                    839:             my @hosts = &Apache::lonnet::current_machine_ids();
                    840:             if (grep(/^\Q$otherserver\E$/,@hosts)) {
                    841:                 $hosthere = $otherserver;
                    842:             }
                    843:         }
                    844:     }
                    845:     if (($is_balancer) && (!$hosthere)) {
                    846:         # login but immediately go to switch server.
                    847:         &Apache::lonauth::success($r,$uname,$udom,$uhome,'noredirect');
                    848:         if ($symb) {
                    849:             $env{'form.symb'} = $symb;
1.8       raeburn   850:             $env{'request.lti.uri'} = $symb;
1.6       raeburn   851:         } else {
                    852:             if ($mapurl) {
                    853:                 $env{'form.origurl'} = $mapurl;
1.8       raeburn   854:                 $env{'request.lti.uri'} = $mapurl;
1.6       raeburn   855:             } elsif ($tail =~ m{^\Q/tiny/$cdom/\E\w+$}) {
                    856:                 $env{'form.origurl'} = $tail;
1.8       raeburn   857:                 $env{'request.lti.uri'} = $tail;
1.9     ! raeburn   858:             } elsif ($tail eq "/$cdom/$cnum") {
        !           859:                 $env{'form.origurl'} = '/adm/navmaps';
        !           860:                 $env{'request.lti.uri'} = $tail;
1.6       raeburn   861:             } else {
                    862:                 unless ($tail eq '/adm/roles') {
                    863:                     $env{'form.origurl'} = '/adm/navmaps';
                    864:                 }
                    865:             }
1.1       raeburn   866:         }
                    867:         if ($role) {
                    868:             $env{'form.role'} = $role;
                    869:         }
1.6       raeburn   870:         if (($lcroles->[0] eq 'cc') && ($reqcrs)) {
                    871:             $env{'request.lti.reqcrs'} = 1;
                    872:             $env{'request.lti.reqrole'} = 'cc';
                    873:             $env{'request.lti.sourcecrs'} = $sourcecrs;
                    874:         }
                    875:         if ($selfenrollrole) {
                    876:             $env{'request.lti.selfenroll'} = $selfenrollrole;
                    877:             $env{'request.lti.sourcecrs'} = $sourcecrs;
                    878:         }
                    879:         if ($ltihash->{'passback'}) {
1.1       raeburn   880:             if ($params->{'lis_result_sourcedid'}) {
                    881:                 $env{'request.lti.passbackid'} = $params->{'lis_result_sourcedid'};
                    882:             }
                    883:             if ($params->{'lis_outcome_service_url'}) {
                    884:                 $env{'request.lti.passbackurl'} = $params->{'lis_outcome_service_url'};
                    885:             }
                    886:         }
1.6       raeburn   887:         if (($ltihash->{'roster'}) && (grep(/^Instructor$/,@{$ltiroles}))) {
1.1       raeburn   888:             if ($params->{'ext_ims_lis_memberships_id'}) {
1.6       raeburn   889:                 $env{'request.lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'};
1.1       raeburn   890:             }
                    891:             if ($params->{'ext_ims_lis_memberships_url'}) {
                    892:                 $env{'request.lti.rosterurl'} = $params->{'ext_ims_lis_memberships_url'};
                    893:             }
                    894:         }
                    895:         $env{'request.lti.login'} = 1;
1.8       raeburn   896:         if ($params->{'launch_presentation_document_target'}) {
                    897:             $env{'request.lti.target'} = $params->{'launch_presentation_document_target'};
                    898:         }
1.1       raeburn   899:         foreach my $key (%{$params}) {
                    900:             delete($env{'form.'.$key});
                    901:         }
                    902:         my $redirecturl = '/adm/switchserver';
                    903:         if ($otherserver ne '') {
                    904:             $redirecturl .= '?otherserver='.$otherserver;
                    905:         }
                    906:         $r->internal_redirect($redirecturl);
                    907:         $r->set_handlers('PerlHandler'=> undef);
                    908:     } else {
                    909:         # need to login them in, so generate the need data that
                    910:         # migrate expects to do login
                    911:         foreach my $key (%{$params}) {
                    912:             delete($env{'form.'.$key});
                    913:         }
                    914:         my $ip = $r->get_remote_host();
                    915:         my %info=('ip'        => $ip,
                    916:                   'domain'    => $udom,
                    917:                   'username'  => $uname,
                    918:                   'server'    => $lonhost,
                    919:                   'lti.login' => 1,
1.8       raeburn   920:                   'lti.uri'   => $tail,
1.1       raeburn   921:                  );
                    922:         if ($role) {
                    923:             $info{'role'} = $role;
                    924:         }
                    925:         if ($symb) {
1.6       raeburn   926:             $info{'symb'} = $symb;
                    927:         }
                    928:         if (($lcroles->[0] eq 'cc') && ($reqcrs)) {
                    929:             $info{'lti.reqcrs'} = 1;
                    930:             $info{'lti.reqrole'} = 'cc';
                    931:             $info{'lti.sourcecrs'} = $sourcecrs;
                    932:         }
                    933:         if ($selfenrollrole) {
                    934:             $info{'lti.selfenrollrole'} = $selfenrollrole;
1.1       raeburn   935:         }
1.6       raeburn   936:         if ($ltihash->{'passback'}) {
1.1       raeburn   937:             if ($params->{'lis_result_sourcedid'}) {
                    938:                 $info{'lti.passbackid'} = $params->{'lis_result_sourcedid'}
                    939:             }
                    940:             if ($params->{'lis_outcome_service_url'}) {
                    941:                 $info{'lti.passbackurl'} = $params->{'lis_outcome_service_url'}
                    942:             }
                    943:         }
1.6       raeburn   944:         if (($ltihash->{'roster'}) && (grep(/^Instructor$/,@{$ltiroles}))) {
1.1       raeburn   945:             if ($params->{'ext_ims_lis_memberships_id'}) {
                    946:                 $info{'lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'};
                    947:             }
                    948:             if ($params->{'ext_ims_lis_memberships_url'}) {
                    949:                 $info{'lti.rosterurl'} = $params->{'ext_ims_lis_memberships_url'};
                    950:             }
                    951:         }
1.8       raeburn   952:         if ($params->{'launch_presentation_document_target'}) {
                    953:             $info{'lti.target'} = $params->{'launch_presentation_document_target'};
                    954:         }
                    955: 
1.1       raeburn   956:         unless ($info{'symb'}) {
                    957:             if ($mapurl) {
                    958:                 $info{'origurl'} = $mapurl;
1.6       raeburn   959:             } elsif ($tail =~ m{^\Q/tiny/$cdom/\E\w+$}) {
                    960:                 $info{'origurl'} = $tail;
1.1       raeburn   961:             } else {
                    962:                 unless ($tail eq '/adm/roles') {
                    963:                     $info{'origurl'} = '/adm/navmaps';
                    964:                 }
                    965:             }
                    966:         }
                    967:         if (($is_balancer) && ($hosthere)) {
                    968:             $info{'noloadbalance'} = $hosthere;
                    969:         }
                    970:         my $token = &Apache::lonnet::tmpput(\%info,$lonhost);
                    971:         $env{'form.token'} = $token;
                    972:         $r->internal_redirect('/adm/migrateuser');
                    973:         $r->set_handlers('PerlHandler'=> undef);
                    974:     }
1.6       raeburn   975:     return;
1.1       raeburn   976: }
                    977: 
                    978: sub invalid_request {
                    979:     my ($r,$num) = @_;
                    980:     &Apache::loncommon::content_type($r,'text/html');
                    981:     $r->send_http_header;
                    982:     if ($r->header_only) {
                    983:         return;
                    984:     }
                    985:     &Apache::lonlocal::get_language_handle($r);
                    986:     $r->print(
                    987:         &Apache::loncommon::start_page('Invalid LTI call').
                    988:         &mt('Invalid LTI call [_1]',$num).
                    989:         &Apache::loncommon::end_page());
                    990:     return;
                    991: }
                    992: 
1.7       raeburn   993: sub create_passwd {
                    994:     my $passwd = '';
                    995:     my @letts = ("a".."z");
                    996:     for (my $i=0; $i<8; $i++) {
                    997:         my $lettnum = int(rand(2));
                    998:         my $item = '';
                    999:         if ($lettnum) {
                   1000:             $item = $letts[int(rand(26))];
                   1001:             my $uppercase = int(rand(2));
                   1002:             if ($uppercase) {
                   1003:                 $item =~ tr/a-z/A-Z/;
                   1004:             }
                   1005:         } else {
                   1006:             $item = int(rand(10));
                   1007:         }
                   1008:         $passwd .= $item;
                   1009:     }
                   1010:     return ($passwd);
                   1011: }
                   1012: 
1.1       raeburn  1013: 1;

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