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

1.1       raeburn     1: # The LearningOnline Network
                      2: # Basic LTI Authentication Module
                      3: #
1.12    ! raeburn     4: # $Id: ltiauth.pm,v 1.11 2018/05/14 19:56:05 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.12    ! raeburn   297:     if (exists($params->{'oauth_callback'})) {
        !           298:         $Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A;
        !           299:     } else {
        !           300:         $Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0;
        !           301:     }
        !           302: 
1.6       raeburn   303:     my ($itemid,$consumer_key,$secret);
1.3       raeburn   304:     $consumer_key = $params->{'oauth_consumer_key'};
                    305:     if (ref($lti_by_key{$consumer_key}) eq 'ARRAY') {
                    306:         foreach my $id (@{$lti_by_key{$consumer_key}}) {
1.1       raeburn   307:             if (ref($lti{$id}) eq 'HASH') {
1.2       raeburn   308:                 $secret = $lti{$id}{'secret'};
1.1       raeburn   309:                 my $request = Net::OAuth->request('request token')->from_hash($params,
                    310:                                                    request_url => $protocol.'://'.$hostname.$requri,
                    311:                                                    request_method => $env{'request.method'},
                    312:                                                    consumer_secret => $secret,);
                    313:                 if ($request->verify()) {
                    314:                     $itemid = $id;
                    315:                     last;
                    316:                 }
                    317:             }
                    318:         }
                    319:     }
                    320: 
                    321: #
                    322: # Request is invalid if the signed request could not be verified
                    323: # for the Consumer key and Consumer secret from the domain
                    324: # configuration in LON-CAPA for that LTI Consumer.
                    325: #
                    326:     unless (($itemid) && (ref($lti{$itemid}) eq 'HASH')) {
1.5       raeburn   327:         &invalid_request($r,7);
1.1       raeburn   328:         return OK;
                    329:     }
                    330: 
                    331: #
                    332: # Determine if nonce in POSTed data has expired.
                    333: # If unexpired, confirm it has not already been used.
                    334: #
1.2       raeburn   335:     unless (&LONCAPA::ltiutils::check_nonce($params->{'oauth_nonce'},$params->{'oauth_timestamp'},
                    336:                                             $lti{$itemid}{'lifetime'},$cdom,$r->dir_config('lonLTIDir'))) {
1.5       raeburn   337:         &invalid_request($r,8);
1.1       raeburn   338:         return OK;
                    339:     }
                    340: 
                    341: #
1.6       raeburn   342: # Determine if source of username matches requirement from the 
1.1       raeburn   343: # domain configuration for the specific LTI Consumer.
                    344: # 
                    345: 
                    346:     if ($lti{$itemid}{'mapuser'} eq $possmapuser) {
                    347:         $uname = $possuname;
                    348:     } elsif ($lti{$itemid}{'mapuser'} eq 'lis_person_sourcedid') {
                    349:         if ($params->{'lis_person_sourcedid'} =~ /^$match_username$/) {
                    350:             $uname = $possuname;
                    351:         }
                    352:     } elsif ($lti{$itemid}{'mapuser'} eq 'lis_person_contact_email_primary') {
                    353:         if ($params->{'lis_person_contact_email_primary'} =~ /^$match_username$/) {
                    354:             $uname = $params->{'lis_person_contact_email_primary'};
                    355:         }
                    356:     } elsif (exists($params->{$lti{$itemid}{'mapuser'}})) {
                    357:         if ($params->{$lti{$itemid}{'mapuser'}} =~ /^$match_username$/) {
                    358:             $uname = $params->{$lti{$itemid}{'mapuser'}};
                    359:         }
                    360:     }
                    361: 
                    362: #
                    363: # Determine the courseID of the LON-CAPA course to which the
                    364: # launch of LON-CAPA should provide access.
                    365: #
                    366: # Order is:
                    367: #
                    368: # (a) from course mapping (if the link between Consumer "course" and 
                    369: # Provider "course" has been established previously).
1.9       raeburn   370: # (b) from tail of requested URL (after /adm/lti/) if it has format of a symb
1.1       raeburn   371: # (c) from tail of requested URL (after /adm/lti) if it has format of a map
                    372: # (d) from tail of requested URL (after /adm/lti) if it has format /domain/courseID
1.5       raeburn   373: # (e) from tail of requested URL (after /adm/lti) if it has format /tiny/domain/\w+
                    374: #     i.e., a shortened URL (see bug #6400).
1.1       raeburn   375: #
                    376: # If Consumer course included in POSTed data points as a target course which
                    377: # has a format which matches a LON-CAPA courseID, but the course does not
                    378: # exist, the request is invalid.
                    379: # 
                    380: 
                    381:     my ($sourcecrs,%consumers);
                    382:     if ($lti{$itemid}{'mapcrs'} eq 'course_offering_sourcedid') {
                    383:         $sourcecrs = $params->{'course_offering_sourcedid'};
                    384:     } elsif ($lti{$itemid}{'mapcrs'} eq 'context_id') {
                    385:         $sourcecrs = $params->{'context_id'};
                    386:     } elsif ($lti{$itemid}{'mapcrs'} ne '') {
                    387:         $sourcecrs = $params->{$lti{$itemid}{'mapcrs'}};
                    388:     }
                    389: 
                    390:     my $posscnum;
                    391:     if ($sourcecrs ne '') {
                    392:         %consumers = &Apache::lonnet::get_dom('lticonsumers',[$sourcecrs],$cdom);
                    393:         if (exists($consumers{$sourcecrs})) {
                    394:             if ($consumers{$sourcecrs} =~ /^$match_courseid$/) {
                    395:                 my $crshome = &Apache::lonnet::homeserver($consumers{$sourcecrs},$cdom);
                    396:                 if ($crshome =~ /(con_lost|no_host|no_such_host)/) {
1.5       raeburn   397:                     &invalid_request($r,9);
1.1       raeburn   398:                     return OK;
                    399:                 } else {
                    400:                     $posscnum = $consumers{$sourcecrs};
                    401:                 }
                    402:             }
                    403:         }
                    404:     }
                    405: 
                    406:     if ($urlcnum ne '') {
                    407:         if ($posscnum ne '') {
                    408:             if ($posscnum ne $urlcnum) {
1.5       raeburn   409:                 &invalid_request($r,10);
1.1       raeburn   410:                 return OK;
                    411:             } else {
                    412:                 $cnum = $posscnum;
                    413:             }
                    414:         } else {
                    415:             my $crshome = &Apache::lonnet::homeserver($urlcnum,$cdom);
                    416:             if ($crshome =~ /(con_lost|no_host|no_such_host)/) {
1.5       raeburn   417:                 &invalid_request($r,11);
1.1       raeburn   418:                 return OK;
                    419:             } else {
                    420:                 $cnum = $urlcnum;
                    421:             }
                    422:         }
                    423:     } elsif ($posscnum ne '') {
                    424:         $cnum = $posscnum;
                    425:     }
                    426: 
                    427: #
1.6       raeburn   428: # Get LON-CAPA role(s) to use from role-mapping of Consumer roles
1.1       raeburn   429: # defined in domain configuration for the appropriate LTI
                    430: # Consumer.
                    431: #
1.6       raeburn   432: # If multiple LON-CAPA roles are indicated for the current user,
                    433: # ordering (from first to last) is: cc/co, in, ta, ep, st.
1.1       raeburn   434: #
                    435: 
1.6       raeburn   436:     my (@ltiroles,@lcroles);
1.1       raeburn   437: 
1.6       raeburn   438:     my @lcroleorder = ('cc','in','ta','ep','st');
                    439:     my @ltiroleorder = ('Instructor','TeachingAssistant','Mentor','Learner');
1.1       raeburn   440:     if ($params->{'roles'} =~ /,/) {
1.11      raeburn   441:         my @possltiroles = split(/\s*,\s*/,$params->{'roles'});
1.6       raeburn   442:         foreach my $ltirole (@ltiroleorder) {
                    443:             if (grep(/^\Q$ltirole\E$/,@possltiroles)) {
                    444:                 push(@ltiroles,$ltirole);
                    445:             }
                    446:         }
1.1       raeburn   447:     } else {
                    448:         my $singlerole = $params->{'roles'};
                    449:         $singlerole =~ s/^\s|\s+$//g;
1.6       raeburn   450:         if (grep(/^\Q$singlerole\E$/,@ltiroleorder)) {
                    451:             @ltiroles = ($singlerole);
                    452:         }
1.1       raeburn   453:     }
                    454:     if (@ltiroles) {
                    455:         if (ref($lti{$itemid}{maproles}) eq 'HASH') {
                    456:             my %possroles;
                    457:             map { $possroles{$lti{$itemid}{maproles}{$_}} = 1; } @ltiroles;
1.6       raeburn   458:             if (keys(%possroles) > 0) {
                    459:                 foreach my $item (@lcroleorder) {
1.1       raeburn   460:                     if ($possroles{$item}) {
1.6       raeburn   461:                         push(@lcroles,$item);
1.1       raeburn   462:                     }
                    463:                 }
                    464:             }
                    465:         }
                    466:     }
                    467: 
                    468: #
                    469: # If no LON-CAPA username  -- is user allowed to create one?
                    470: #
                    471: 
                    472:     my $selfcreate;
                    473:     if (($uname ne '') && ($udom ne '')) {
                    474:         $uhome = &Apache::lonnet::homeserver($uname,$udom);
                    475:         if ($uhome =~ /(con_lost|no_host|no_such_host)/) {
                    476:             &Apache::lonnet::logthis(" LTI authorized unknown user $uname:$udom ");
                    477:             if (ref($lti{$itemid}{'makeuser'}) eq 'ARRAY') {
                    478:                 if (@{$lti{$itemid}{'makeuser'}} > 0) {
                    479:                     foreach my $ltirole (@ltiroles) {
                    480:                         if (grep(/^\Q$ltirole\E$/,@{$lti{$itemid}{'makeuser'}})) {
                    481:                             $selfcreate = 1;
1.6       raeburn   482:                             last;
1.1       raeburn   483:                         }
                    484:                     }
                    485:                 }
                    486:             }
                    487:             if ($selfcreate) {
1.6       raeburn   488:                 my (%rulematch,%inst_results,%curr_rules,%got_rules,%alerts,%info);
                    489:                 my $checkhash = { "$uname:$udom" => { 'newuser' => 1, }, };
                    490:                 my $checks = { 'username' => 1, };
                    491:                 &Apache::loncommon::user_rule_check($checkhash,$checks,\%alerts,\%rulematch,
                    492:                                                     \%inst_results,\%curr_rules,\%got_rules);
                    493:                 my ($userchkmsg,$lcauth,$lcauthparm);
                    494:                 my $allowed = 1;
                    495:                 if (ref($alerts{'username'}) eq 'HASH') {
                    496:                     if (ref($alerts{'username'}{$udom}) eq 'HASH') {
                    497:                         my $domdesc =
                    498:                             &Apache::lonnet::domain($udom,'description');
                    499:                         if ($alerts{'username'}{$udom}{$uname}) {
                    500:                             if (ref($curr_rules{$udom}) eq 'HASH') {
                    501:                                 $userchkmsg =
                    502:                                     &Apache::loncommon::instrule_disallow_msg('username',$domdesc,1).
                    503:                                     &Apache::loncommon::user_rule_formats($udom,$domdesc,
                    504:                                                                           $curr_rules{$udom}{'username'},
                    505:                                                                            'username');
                    506:                             }
                    507:                             $allowed = 0;
                    508:                         }
                    509:                     }
                    510:                 }
                    511:                 if ($allowed) {
                    512:                     if (ref($rulematch{$uname.':'.$udom}) eq 'HASH') {
                    513:                         my $matchedrule = $rulematch{$uname.':'.$udom}{'username'};
                    514:                         my ($rules,$ruleorder) =
                    515:                             &Apache::lonnet::inst_userrules($udom,'username');
                    516:                         if (ref($rules) eq 'HASH') {
                    517:                             if (ref($rules->{$matchedrule}) eq 'HASH') {
                    518:                                 $lcauth = $rules->{$matchedrule}{'authtype'};
                    519:                                 $lcauthparm = $rules->{$matchedrule}{'authparm'};
                    520:                             }
                    521:                         }
                    522:                     }
                    523:                     if ($lcauth eq '') {
                    524:                         $lcauth = $lti{$itemid}{'lcauth'};
1.7       raeburn   525:                         if ($lcauth eq 'internal') {
                    526:                             $lcauthparm = &create_passwd();
                    527:                         } else {
                    528:                             $lcauthparm = $lti{$itemid}{'lcauthparm'};
                    529:                         }
1.6       raeburn   530:                     }
                    531:                 } else {
                    532:                     &invalid_request($r,12);
                    533:                 }
                    534:                 my @userinfo = ('firstname','middlename','lastname','generation',
                    535:                                 'permanentemail','id');
                    536:                 my %useinstdata;
                    537:                 if (ref($lti{$itemid}{'instdata'}) eq 'ARRAY') {
                    538:                     map { $useinstdata{$_} = 1; } @{$lti{$itemid}{'instdata'}};
                    539:                 }
                    540:                 foreach my $item (@userinfo) {
                    541:                     if (($useinstdata{$item}) && (ref($inst_results{$uname.':'.$udom}) eq 'HASH') &&
                    542:                         ($inst_results{$uname.':'.$udom}{$item} ne '')) {
                    543:                         $info{$item} = $inst_results{$uname.':'.$udom}{$item};
                    544:                     } else {
                    545:                         if ($item eq 'permanentemail') {
                    546:                             if ($env{'form.lis_person_contact_email_primary'} =~/^[^\@]+\@[^@]+$/) {
                    547:                                 $info{$item} = $env{'form.lis_person_contact_email_primary'};
                    548:                             }
                    549:                         } elsif ($item eq 'firstname') {
                    550:                             $info{$item} = $env{'form.lis_person_name_given'};
                    551:                         } elsif ($item eq 'lastname') {
                    552:                             $info{$item} = $env{'form.lis_person_name_family'};
                    553:                         }
                    554:                     }
                    555:                 }
                    556:                 if (($info{'middlename'} eq '') && ($env{'form.lis_person_name_full'} ne '')) {
                    557:                     unless ($useinstdata{'middlename'}) {
                    558:                         my $fullname = $env{'form.lis_person_name_full'};
                    559:                         if ($info{'firstname'}) {
                    560:                             $fullname =~ s/^\s*\Q$info{'firstname'}\E\s*//i;
                    561:                         }
                    562:                         if ($info{'lastname'}) {
                    563:                             $fullname =~ s/\s*\Q$info{'lastname'}\E\s*$//i;
                    564:                         }
                    565:                         if ($fullname ne '') {
                    566:                             $fullname =~ s/^\s+|\s+$//g;
                    567:                             if ($fullname ne '') {
                    568:                                 $info{'middlename'} = $fullname;
                    569:                             }
                    570:                         }
                    571:                     }
                    572:                 }
                    573:                 if (ref($inst_results{$uname.':'.$udom}{'inststatus'}) eq 'ARRAY') {
                    574:                     my @inststatuses = @{$inst_results{$uname.':'.$udom}{'inststatus'}};
                    575:                     $info{'inststatus'} = join(':',map { &escape($_); } @inststatuses);
                    576:                 }
                    577:                 my $result =
                    578:                     &Apache::lonnet::modifyuser($udom,$uname,$info{'id'},
                    579:                                                 $lcauth,$lcauthparm,$info{'firstname'},
                    580:                                                 $info{'middlename'},$info{'lastname'},
                    581:                                                 $info{'generation'},undef,undef,
                    582:                                                 $info{'permanentemail'},$info{'inststatus'});
                    583:                 if ($result eq 'ok') {
                    584:                     if (($ltiroles[0] eq 'Instructor') && ($lcroles[0] eq 'cc') && ($lti{$itemid}{'mapcrs'}) &&
                    585:                         ($lti{$itemid}{'makecrs'})) {
                    586:                         unless (&Apache::lonnet::usertools_access($uname,$udom,'lti','reload','requestcourses')) {
1.10      raeburn   587:                             &Apache::lonnet::put('environment',{ 'requestcourses.lti' => 'autolimit=', },$udom,$uname);
1.6       raeburn   588:                         }
                    589:                     }
                    590:                 } else {
                    591:                     &invalid_request($r,13);
                    592:                     return OK;
                    593:                 }
1.1       raeburn   594:             } else {
1.6       raeburn   595:                 &invalid_request($r,14);
1.1       raeburn   596:                 return OK;
1.6       raeburn   597:             }
                    598:         }
1.1       raeburn   599:     } else {
1.6       raeburn   600:         &invalid_request($r,15);
1.1       raeburn   601:         return OK;
                    602:     }
                    603: 
                    604: #
                    605: # If no LON-CAPA course available, check if domain's configuration
                    606: # for the specific LTI Consumer allows a new course to be created 
1.6       raeburn   607: # (requires role in Consumer to be: Instructor and Instructor to map to CC)
1.1       raeburn   608: #
                    609: 
1.6       raeburn   610:     my $reqcrs;
1.1       raeburn   611:     if ($cnum eq '') {
1.6       raeburn   612:         if ((@ltiroles) && ($lti{$itemid}{'mapcrs'}) &&
                    613:             ($ltiroles[0] eq 'Instructor') && ($lcroles[0] eq 'cc') && ($lti{$itemid}{'makecrs'})) {
                    614:             my (%can_request,%request_domains);
                    615:             &Apache::lonnet::check_can_request($cdom,\%can_request,\%request_domains,$uname,$udom);
                    616:             if ($can_request{'lti'}) {
                    617:                 $reqcrs = 1;
                    618:                 &lti_session($r,$itemid,$uname,$udom,$uhome,$lonhost,undef,$mapurl,$tail,
                    619:                              $symb,$cdom,$cnum,$params,\@ltiroles,$lti{$itemid},\@lcroles,
                    620:                              $reqcrs,$sourcecrs);
                    621:             } else {
                    622:                 &invalid_request($r,16);
                    623:             }
1.1       raeburn   624:         } else {
1.6       raeburn   625:             &invalid_request($r,17);
1.1       raeburn   626:         }
1.6       raeburn   627:         return OK;
1.1       raeburn   628:     }
                    629: 
                    630: #
                    631: # If LON-CAPA course is a Community, and LON-CAPA role
                    632: # indicated is cc, change role indicated to co.
                    633: # 
                    634: 
1.6       raeburn   635:     my %crsenv;
                    636:     if ($lcroles[0] eq 'cc') {
1.1       raeburn   637:         if (($cdom ne '') && ($cnum ne '')) {
1.6       raeburn   638:             %crsenv = &Apache::lonnet::coursedescription($cdom.'_'.$cnum,{ 'one_time' => 1,});
1.1       raeburn   639:             if ($crsenv{'type'} eq 'Community') {
1.6       raeburn   640:                 $lcroles[0] = 'co';
                    641:             }
                    642:         }
                    643:     }
                    644: 
                    645: #
                    646: # Determine if user has a LON-CAPA role in the mapped LON-CAPA course.
                    647: # If multiple LON-CAPA roles are available for the user's assigned LTI roles,
                    648: # choose the first available LON-CAPA role in the order: cc/co, in, ta, ep, st
                    649: #
                    650: 
                    651:     my ($role,$usec,$withsec);
                    652:     unless ((($lcroles[0] eq 'cc') || ($lcroles[0] eq 'co')) && (@lcroles == 1)) {
                    653:         if ($lti{$itemid}{'section'} ne '') {
                    654:             if ($lti{$itemid}{'section'} eq 'course_section_sourcedid') {
                    655:                 if ($env{'form.course_section_sourcedid'} !~ /\W/) {
                    656:                     $usec = $env{'form.course_section_sourcedid'};
                    657:                 }
                    658:             } elsif ($env{'form.'.$lti{$itemid}{'section'}} !~ /\W/) {
                    659:                 $usec = $env{'form.'.$lti{$itemid}{'section'}};
                    660:             }
                    661:         }
                    662:         if ($usec ne '') {
                    663:             $withsec = 1;
                    664:         }
                    665:     }
                    666: 
                    667:     if (@lcroles) {
                    668:         my %crsroles = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',undef,\@lcroles,
                    669:                                                      [$cdom],$withsec);
                    670:         foreach my $reqrole (@lcroles) {
                    671:             if ($withsec) {
                    672:                 my $incsec;
                    673:                 if (($reqrole eq 'cc') || ($reqrole eq 'co')) {
                    674:                     $incsec = '';
                    675:                 } else {
                    676:                     $incsec = $usec;
                    677:                 }
                    678:                 if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole.':'.$incsec})) {
                    679:                     $role = $reqrole.'./'.$cdom.'/'.$cnum;
                    680:                     if ($incsec ne '') {
                    681:                         $role .= '/'.$usec;
                    682:                     }
                    683:                     last;
                    684:                 }
                    685:             } else {
                    686:                 if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole})) {
                    687:                     $role = $reqrole.'./'.$cdom.'/'.$cnum;
                    688:                     last;
                    689:                 }
1.1       raeburn   690:             }
                    691:         }
                    692:     }
                    693: 
                    694: #
1.6       raeburn   695: # Determine if user can selfenroll
1.1       raeburn   696: #
                    697: 
1.6       raeburn   698:     my ($reqrole,$selfenrollrole);
                    699:     if ($role eq '') {
                    700:         if ((@ltiroles) && (ref($lti{$itemid}{'selfenroll'}) eq 'ARRAY')) {
                    701:             foreach my $ltirole (@ltiroles) {
                    702:                 if (grep(/^\Q$ltirole\E$/,@{$lti{$itemid}{'selfenroll'}})) {
                    703:                     if (ref($lti{$itemid}{maproles}) eq 'HASH') {
                    704:                         $reqrole = $lti{$itemid}{maproles}{$ltirole};
                    705:                         last;
                    706:                     }
                    707:                 }
                    708:             }
                    709:         }
                    710:         if ($reqrole eq '') {
                    711:             &invalid_request($r,18);
1.1       raeburn   712:             return OK;
                    713:         } else {
1.6       raeburn   714:             unless (%crsenv) {
                    715:                 %crsenv = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                    716:             }
                    717:             my $default_enrollment_start_date = $crsenv{'default_enrollment_start_date'};
                    718:             my $default_enrollment_end_date   = $crsenv{'default_enrollment_end_date'};
                    719:             my $now = time;
                    720:             if ($default_enrollment_end_date && $default_enrollment_end_date <= $now) {
                    721:                 &invalid_request($r,19);
                    722:                 return OK;
                    723:             } elsif ($default_enrollment_start_date && $default_enrollment_start_date >$now) {
                    724:                 &invalid_request($r,20);
                    725:                 return OK;
                    726:             } else {
                    727:                 $selfenrollrole = $reqrole.'./'.$cdom.'/'.$cnum;
                    728:                 if (($withsec) && ($reqrole ne 'cc') && ($reqrole ne 'co')) {
                    729:                     if ($usec ne '') {
                    730:                         $selfenrollrole .= '/'.$usec;
                    731:                     }
                    732:                 }
                    733:             }
1.1       raeburn   734:         }
                    735:     }
                    736: 
                    737: #
                    738: # Store consumer-to-LON-CAPA course mapping
                    739: #
1.6       raeburn   740: 
1.1       raeburn   741:     if (($sourcecrs ne '')  && ($consumers{$sourcecrs} eq '') && ($cnum ne '')) {
                    742:         &Apache::lonnet::put_dom('lticonsumers',{ $sourcecrs => $cnum },$cdom);
                    743:     }
                    744: 
                    745: #
1.6       raeburn   746: # Start user session
                    747: #
                    748: 
                    749:     &lti_session($r,$itemid,$uname,$udom,$uhome,$lonhost,$role,$mapurl,$tail,$symb,
                    750:                  $cdom,$cnum,$params,\@ltiroles,$lti{$itemid},\@lcroles,undef,$sourcecrs,
                    751:                  $selfenrollrole);
                    752:     return OK;
                    753: }
                    754: 
                    755: sub lti_enroll {
                    756:     my ($uname,$udom,$selfenrollrole) = @_;
                    757:     my $enrollresult;
                    758:     my ($role,$cdom,$cnum,$sec) =
                    759:            ($selfenrollrole =~ m{^(\w+)\./($match_domain)/($match_courseid)(?:|/(\w*))$});
                    760:     if (($cnum ne '') && ($cdom ne '')) {
                    761:         my $chome = &Apache::lonnet::homeserver($cnum,$cdom);
                    762:         if ($chome ne 'no_host') {
                    763:             my %coursehash = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
                    764:             my $start = $coursehash{'default_enrollment_start_date'};
                    765:             my $end = $coursehash{'default_enrollment_end_date'};
                    766:             my $area = "/$cdom/$cnum";
                    767:             if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) {
                    768:                 $area .= '/'.$sec;
                    769:             }
                    770:             my $spec = $role.'.'.$area;
                    771:             my $instcid;
                    772:             if ($role eq 'st') {
                    773:                 $enrollresult =
                    774:                     &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,
                    775:                                                                undef,undef,$sec,$end,$start,
                    776:                                                                'ltienroll',undef,$cdom.'_'.$cnum,1,
                    777:                                                                'ltienroll','',$instcid);
                    778:             } elsif ($role =~ /^(cc|in|ta|ep)$/) {
                    779:                 $enrollresult =
                    780:                     &Apache::lonnet::assignrole($udom,$uname,$area,$role,$end,$start,
                    781:                                                 undef,1,'ltienroll');
                    782:             }
                    783:             if ($enrollresult eq 'ok') {
                    784:                 my (%userroles,%newrole,%newgroups);
                    785:                 &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum,
                    786:                                                     $area);
                    787:                 &Apache::lonnet::set_userprivs(\%userroles,\%newrole,\%newgroups);
                    788:                 $userroles{'user.role.'.$spec} = $start.'.'.$end;
                    789:                 &Apache::lonnet::appenv(\%userroles,[$role,'cm']);
                    790:             }
                    791:         }
                    792:     }
                    793:     return $enrollresult;
                    794: }
                    795: 
                    796: sub lti_reqcrs {
                    797:     my ($r,$cdom,$form,$uname,$udom) = @_;
                    798:     my (%can_request,%request_domains);
                    799:     &Apache::lonnet::check_can_request($cdom,\%can_request,\%request_domains,$uname,$udom);
                    800:     if ($can_request{'lti'}) {
                    801:         my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$cdom);
                    802:         my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
                    803:         &Apache::lonrequestcourse::print_textbook_form($r,$cdom,[$cdom],\%domdefs,
                    804:                                                        $domconfig{'requestcourses'},
                    805:                                                        \%can_request,'lti',$form);
                    806:     } else {
                    807:         $r->print(
                    808:               &Apache::loncommon::start_page('Invalid LTI call',undef,{'only_body' => 1}).
                    809:               &mt('Invalid LTI call').
                    810:               &Apache::loncommon::end_page()
                    811:         );
                    812:     }
                    813: }
                    814: 
                    815: sub lti_session {
                    816:     my ($r,$itemid,$uname,$udom,$uhome,$lonhost,$role,$mapurl,$tail,$symb,$cdom,$cnum,
                    817:         $params,$ltiroles,$ltihash,$lcroles,$reqcrs,$sourcecrs,$selfenrollrole) = @_;
                    818:     return unless ((ref($params) eq 'HASH') && (ref($ltiroles) eq 'ARRAY') &&
                    819:                    (ref($ltihash) eq 'HASH') && (ref($lcroles) eq 'ARRAY'));
                    820: #
1.1       raeburn   821: # Check if user should be hosted here or switched to another server.
                    822: #
                    823:     $r->user($uname);
1.6       raeburn   824:     if ($cnum) {
                    825:         if ($role) {
                    826:             &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, role: $role, course: $cdom\_$cnum");
                    827:         } elsif ($selfenrollrole =~ m{^(\w+)\./$cdom/$cnum}) {
                    828:             &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, desired role: $1 course: $cdom\_$cnum");
                    829:         }
                    830:     } else {
                    831:         &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, course dom: $cdom");
                    832:     }
1.1       raeburn   833:     my ($is_balancer,$otherserver,$hosthere);
                    834:     ($is_balancer,$otherserver) =
                    835:         &Apache::lonnet::check_loadbalancing($uname,$udom,'login');
                    836:     if ($is_balancer) {
                    837:         if ($otherserver eq '') {
                    838:             my $lowest_load;
                    839:             ($otherserver,undef,undef,undef,$lowest_load) = &Apache::lonnet::choose_server($udom);
                    840:             if ($lowest_load > 100) {
                    841:                 $otherserver = &Apache::lonnet::spareserver($lowest_load,$lowest_load,1,$udom);
                    842:             }
                    843:         }
                    844:         if ($otherserver ne '') {
                    845:             my @hosts = &Apache::lonnet::current_machine_ids();
                    846:             if (grep(/^\Q$otherserver\E$/,@hosts)) {
                    847:                 $hosthere = $otherserver;
                    848:             }
                    849:         }
                    850:     }
                    851:     if (($is_balancer) && (!$hosthere)) {
                    852:         # login but immediately go to switch server.
                    853:         &Apache::lonauth::success($r,$uname,$udom,$uhome,'noredirect');
                    854:         if ($symb) {
                    855:             $env{'form.symb'} = $symb;
1.8       raeburn   856:             $env{'request.lti.uri'} = $symb;
1.6       raeburn   857:         } else {
                    858:             if ($mapurl) {
                    859:                 $env{'form.origurl'} = $mapurl;
1.8       raeburn   860:                 $env{'request.lti.uri'} = $mapurl;
1.6       raeburn   861:             } elsif ($tail =~ m{^\Q/tiny/$cdom/\E\w+$}) {
                    862:                 $env{'form.origurl'} = $tail;
1.8       raeburn   863:                 $env{'request.lti.uri'} = $tail;
1.9       raeburn   864:             } elsif ($tail eq "/$cdom/$cnum") {
                    865:                 $env{'form.origurl'} = '/adm/navmaps';
                    866:                 $env{'request.lti.uri'} = $tail;
1.6       raeburn   867:             } else {
                    868:                 unless ($tail eq '/adm/roles') {
                    869:                     $env{'form.origurl'} = '/adm/navmaps';
                    870:                 }
                    871:             }
1.1       raeburn   872:         }
                    873:         if ($role) {
                    874:             $env{'form.role'} = $role;
                    875:         }
1.6       raeburn   876:         if (($lcroles->[0] eq 'cc') && ($reqcrs)) {
                    877:             $env{'request.lti.reqcrs'} = 1;
                    878:             $env{'request.lti.reqrole'} = 'cc';
                    879:             $env{'request.lti.sourcecrs'} = $sourcecrs;
                    880:         }
                    881:         if ($selfenrollrole) {
                    882:             $env{'request.lti.selfenroll'} = $selfenrollrole;
                    883:             $env{'request.lti.sourcecrs'} = $sourcecrs;
                    884:         }
                    885:         if ($ltihash->{'passback'}) {
1.1       raeburn   886:             if ($params->{'lis_result_sourcedid'}) {
                    887:                 $env{'request.lti.passbackid'} = $params->{'lis_result_sourcedid'};
                    888:             }
                    889:             if ($params->{'lis_outcome_service_url'}) {
                    890:                 $env{'request.lti.passbackurl'} = $params->{'lis_outcome_service_url'};
                    891:             }
                    892:         }
1.6       raeburn   893:         if (($ltihash->{'roster'}) && (grep(/^Instructor$/,@{$ltiroles}))) {
1.1       raeburn   894:             if ($params->{'ext_ims_lis_memberships_id'}) {
1.6       raeburn   895:                 $env{'request.lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'};
1.1       raeburn   896:             }
                    897:             if ($params->{'ext_ims_lis_memberships_url'}) {
                    898:                 $env{'request.lti.rosterurl'} = $params->{'ext_ims_lis_memberships_url'};
                    899:             }
                    900:         }
1.10      raeburn   901:         $env{'request.lti.login'} = $itemid;
1.8       raeburn   902:         if ($params->{'launch_presentation_document_target'}) {
                    903:             $env{'request.lti.target'} = $params->{'launch_presentation_document_target'};
                    904:         }
1.1       raeburn   905:         foreach my $key (%{$params}) {
                    906:             delete($env{'form.'.$key});
                    907:         }
                    908:         my $redirecturl = '/adm/switchserver';
                    909:         if ($otherserver ne '') {
                    910:             $redirecturl .= '?otherserver='.$otherserver;
                    911:         }
                    912:         $r->internal_redirect($redirecturl);
                    913:         $r->set_handlers('PerlHandler'=> undef);
                    914:     } else {
                    915:         # need to login them in, so generate the need data that
                    916:         # migrate expects to do login
                    917:         foreach my $key (%{$params}) {
                    918:             delete($env{'form.'.$key});
                    919:         }
                    920:         my $ip = $r->get_remote_host();
                    921:         my %info=('ip'        => $ip,
                    922:                   'domain'    => $udom,
                    923:                   'username'  => $uname,
                    924:                   'server'    => $lonhost,
1.10      raeburn   925:                   'lti.login' => $itemid,
1.8       raeburn   926:                   'lti.uri'   => $tail,
1.1       raeburn   927:                  );
                    928:         if ($role) {
                    929:             $info{'role'} = $role;
                    930:         }
                    931:         if ($symb) {
1.6       raeburn   932:             $info{'symb'} = $symb;
                    933:         }
                    934:         if (($lcroles->[0] eq 'cc') && ($reqcrs)) {
                    935:             $info{'lti.reqcrs'} = 1;
                    936:             $info{'lti.reqrole'} = 'cc';
                    937:             $info{'lti.sourcecrs'} = $sourcecrs;
                    938:         }
                    939:         if ($selfenrollrole) {
                    940:             $info{'lti.selfenrollrole'} = $selfenrollrole;
1.1       raeburn   941:         }
1.6       raeburn   942:         if ($ltihash->{'passback'}) {
1.1       raeburn   943:             if ($params->{'lis_result_sourcedid'}) {
                    944:                 $info{'lti.passbackid'} = $params->{'lis_result_sourcedid'}
                    945:             }
                    946:             if ($params->{'lis_outcome_service_url'}) {
                    947:                 $info{'lti.passbackurl'} = $params->{'lis_outcome_service_url'}
                    948:             }
                    949:         }
1.6       raeburn   950:         if (($ltihash->{'roster'}) && (grep(/^Instructor$/,@{$ltiroles}))) {
1.1       raeburn   951:             if ($params->{'ext_ims_lis_memberships_id'}) {
                    952:                 $info{'lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'};
                    953:             }
                    954:             if ($params->{'ext_ims_lis_memberships_url'}) {
                    955:                 $info{'lti.rosterurl'} = $params->{'ext_ims_lis_memberships_url'};
                    956:             }
                    957:         }
1.8       raeburn   958:         if ($params->{'launch_presentation_document_target'}) {
                    959:             $info{'lti.target'} = $params->{'launch_presentation_document_target'};
                    960:         }
                    961: 
1.1       raeburn   962:         unless ($info{'symb'}) {
                    963:             if ($mapurl) {
                    964:                 $info{'origurl'} = $mapurl;
1.6       raeburn   965:             } elsif ($tail =~ m{^\Q/tiny/$cdom/\E\w+$}) {
                    966:                 $info{'origurl'} = $tail;
1.1       raeburn   967:             } else {
                    968:                 unless ($tail eq '/adm/roles') {
                    969:                     $info{'origurl'} = '/adm/navmaps';
                    970:                 }
                    971:             }
                    972:         }
                    973:         if (($is_balancer) && ($hosthere)) {
                    974:             $info{'noloadbalance'} = $hosthere;
                    975:         }
                    976:         my $token = &Apache::lonnet::tmpput(\%info,$lonhost);
                    977:         $env{'form.token'} = $token;
                    978:         $r->internal_redirect('/adm/migrateuser');
                    979:         $r->set_handlers('PerlHandler'=> undef);
                    980:     }
1.6       raeburn   981:     return;
1.1       raeburn   982: }
                    983: 
                    984: sub invalid_request {
                    985:     my ($r,$num) = @_;
                    986:     &Apache::loncommon::content_type($r,'text/html');
                    987:     $r->send_http_header;
                    988:     if ($r->header_only) {
                    989:         return;
                    990:     }
                    991:     &Apache::lonlocal::get_language_handle($r);
                    992:     $r->print(
1.10      raeburn   993:         &Apache::loncommon::start_page('Invalid LTI call','',{ 'only_body' => 1,}).
1.1       raeburn   994:         &mt('Invalid LTI call [_1]',$num).
                    995:         &Apache::loncommon::end_page());
                    996:     return;
                    997: }
                    998: 
1.7       raeburn   999: sub create_passwd {
                   1000:     my $passwd = '';
                   1001:     my @letts = ("a".."z");
                   1002:     for (my $i=0; $i<8; $i++) {
                   1003:         my $lettnum = int(rand(2));
                   1004:         my $item = '';
                   1005:         if ($lettnum) {
                   1006:             $item = $letts[int(rand(26))];
                   1007:             my $uppercase = int(rand(2));
                   1008:             if ($uppercase) {
                   1009:                 $item =~ tr/a-z/A-Z/;
                   1010:             }
                   1011:         } else {
                   1012:             $item = int(rand(10));
                   1013:         }
                   1014:         $passwd .= $item;
                   1015:     }
                   1016:     return ($passwd);
                   1017: }
                   1018: 
1.1       raeburn  1019: 1;

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