Annotation of loncom/auth/migrateuser.pm, revision 1.35
1.1 albertel 1: # The LearningOnline Network
2: # Starts a user off based of an existing token.
3: #
1.35 ! raeburn 4: # $Id: migrateuser.pm,v 1.34 2018/07/04 16:58:19 raeburn Exp $
1.1 albertel 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:
1.2 albertel 29: package Apache::migrateuser;
1.1 albertel 30:
31: use strict;
1.19 raeburn 32: use LONCAPA qw(:DEFAULT :match);
1.1 albertel 33: use Apache::Constants qw(:common :http :methods);
34: use Apache::lonauth;
35: use Apache::lonnet;
1.6 albertel 36: use Apache::lonlocal;
1.18 raeburn 37: use Apache::lonlogin();
1.27 raeburn 38: use Apache::ltiauth;
1.28 raeburn 39: use CGI::Cookie;
1.1 albertel 40:
41: sub goto_login {
1.27 raeburn 42: my ($r,$domain,$data) = @_;
43: if ((ref($data) eq 'HASH') && ($data->{'lti.login'})) {
44: &Apache::ltiauth::invalid_request($r,'22');
45: } else {
46: &Apache::loncommon::content_type($r,'text/html');
47: $r->send_http_header;
48: my $url = '/adm/login';
49: if ($domain) {
50: $url .= '?domain='.$domain;
51: }
52: $r->print(&Apache::loncommon::start_page('Going to login',undef,
53: {'redirect' => [0,$url],}).
54: '<h1>'.&mt('One moment please...').'</h1>'.
55: '<p>'.&mt('Transferring to login page.').'</p>'.
56: &Apache::loncommon::end_page());
57: }
1.2 albertel 58: return OK;
1.1 albertel 59: }
60:
1.27 raeburn 61: sub sso_check {
1.7 albertel 62: my ($data) = @_;
1.8 albertel 63: my %extra_env;
1.18 raeburn 64: if (ref($data) eq 'HASH') {
65: if ($data->{'sso.login'}) {
66: $extra_env{'request.sso.login'} = $data->{'sso.login'};
67: }
68: if ($data->{'sso.reloginserver'}) {
69: $extra_env{'request.sso.reloginserver'} =
70: $data->{'sso.reloginserver'};
71: }
1.35 ! raeburn 72: if (($data->{'balancer'}) && ($data->{'server'}) && ($data->{'balcookie'})) {
! 73: $extra_env{'request.balancercookie'} = $data->{'server'}.':'.$data->{'balcookie'};
! 74: }
1.27 raeburn 75: }
76: return \%extra_env;
77: }
78:
79: sub lti_check {
80: my ($data) = @_;
81: my %lti_env;
82: if (ref($data) eq 'HASH') {
1.26 raeburn 83: if ($data->{'lti.login'}) {
1.27 raeburn 84: $lti_env{'request.lti.login'} = $data->{'lti.login'};
85: if ($data->{'lti.reqcrs'}) {
86: $lti_env{'request.lti.reqcrs'} = $data->{'lti.reqcrs'};
87: }
88: if ($data->{'lti.reqrole'}) {
89: $lti_env{'request.lti.reqrole'} = $data->{'lti.reqrole'};
90: }
91: if ($data->{'lti.selfenrollrole'}) {
92: $lti_env{'request.lti.selfenrollrole'} = $data->{'lti.selfenrollrole'};
93: }
1.29 raeburn 94: if ($data->{'lti.uri'}) {
95: $lti_env{'request.lti.uri'} = $data->{'lti.uri'};
96: }
97: if ($data->{'lti.target'}) {
98: $lti_env{'request.lti.target'} = $data->{'lti.target'};
99: }
1.32 raeburn 100: if ($data->{'lti.sourcecrs'}) {
101: $lti_env{'request.lti.sourcecrs'} = $data->{'lti.sourcecrs'};
102: }
1.26 raeburn 103: }
104: if ($data->{'lti.passbackid'}) {
1.27 raeburn 105: $lti_env{'request.lti.passbackid'} = $data->{'lti.passbackid'};
1.26 raeburn 106: }
107: if ($data->{'lti.passbackurl'}) {
1.27 raeburn 108: $lti_env{'request.lti.passbackurl'} = $data->{'lti.passbackurl'};
1.26 raeburn 109: }
110: if ($data->{'lti.rosterid'}) {
1.27 raeburn 111: $lti_env{'request.lti.rosterid'} = $data->{'lti.rosterid'};
1.26 raeburn 112: }
113: if ($data->{'lti.rosterurl'}) {
1.27 raeburn 114: $lti_env{'request.lti.rosterurl'} = $data->{'lti.rosterurl'};
1.26 raeburn 115: }
1.7 albertel 116: }
1.27 raeburn 117: return \%lti_env;
1.18 raeburn 118: }
119:
120: sub ip_changed {
121: my ($r,$udom,$camefrom,$dataref) = @_;
122: &Apache::loncommon::content_type($r,'text/html');
123: $r->send_http_header;
124: if (ref($dataref) eq 'HASH') {
125: my $title = 'LON-CAPA Session redirected';
126: my $message = &mt('Your internet address has changed since you logged in.');
127: my $rule_in_effect;
1.22 raeburn 128: if ($dataref->{'balancer'}) {
129: my $baldom = &Apache::lonnet::host_domain($camefrom);
130: my $balprimaryid = &Apache::lonnet::domain($baldom,'primary');
131: my $balintdom = &Apache::lonnet::internet_dom($balprimaryid);
132: my $uprimaryid = &Apache::lonnet::domain($udom,'primary');
133: my $uintdom = &Apache::lonnet::internet_dom($uprimaryid);
134: my $dom_in_use;
135: if (($uintdom ne '') && ($uintdom eq $balintdom)) {
136: $dom_in_use = $udom;
137: } else {
138: $dom_in_use = $baldom;
1.21 raeburn 139: }
1.22 raeburn 140: my ($result,$cached)=&Apache::lonnet::is_cached_new('loadbalancing',$dom_in_use);
1.18 raeburn 141: unless (defined($cached)) {
142: my $cachetime = 60*60*24;
143: my %domconfig =
1.22 raeburn 144: &Apache::lonnet::get_dom('configuration',['loadbalancing'],$dom_in_use);
1.18 raeburn 145: if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
1.22 raeburn 146: $result = &Apache::lonnet::do_cache_new('loadbalancing',$dom_in_use,
1.18 raeburn 147: $domconfig{'loadbalancing'},$cachetime);
148: }
149: }
150: if (ref($result) eq 'HASH') {
151: (undef,my $currtargets,my $currrules) =
152: &Apache::lonnet::check_balancer_result($result,$dataref->{'server'});
153: if (ref($currrules) eq 'HASH') {
154: if ($dataref->{'sso.login'}) {
155: if ($currrules->{'_LC_ipchangesso'} ne '') {
156: $rule_in_effect = $currrules->{'_LC_ipchangesso'};
157: }
158: } else {
159: if ($currrules->{'_LC_ipchange'} ne '') {
160: $rule_in_effect = $currrules->{'_LC_ipchange'};
161: }
162: }
163: }
164: }
165: }
166: my $url;
167: my $lonhost= $r->dir_config('lonHostID');
168: my $switchto = $lonhost;
1.23 raeburn 169: if ($rule_in_effect ne 'offloadedto') {
1.18 raeburn 170: my $hosthere;
1.23 raeburn 171: my @ids=&Apache::lonnet::current_machine_ids();
172: unless ($rule_in_effect eq 'balancer') {
173: if (grep(/^\Q$rule_in_effect\E$/,@ids)) {
174: $hosthere = 1;
175: }
176: }
177: unless ($hosthere) {
178: if ($dataref->{'role'}) {
179: my ($adom,$aname);
180: if ($dataref->{'role'} =~ m{^au\./($match_domain)/$}) {
181: $adom = $1;
182: $aname = $dataref->{'username'};
183: } elsif ($dataref->{'role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)$}) {
184: $adom = $1;
185: $aname = $2;
186: }
187: if ($adom ne '' && $aname ne '') {
188: my $ahome = &Apache::lonnet::homeserver($aname,$adom);
189: unless ($ahome eq 'no_host') {
190: if ($ahome && grep(/^\Q$ahome\E$/,@ids)) {
191: $hosthere = 1;
192: }
1.18 raeburn 193: }
194: }
195: }
196: }
1.23 raeburn 197: unless ($hosthere) {
198: my $hostname;
199: if ($rule_in_effect eq 'balancer') {
200: $hostname = &Apache::lonnet::hostname($dataref->{'server'});
201: if ($hostname) {
202: $switchto = $dataref->{'server'};
203: }
204: } else {
205: $hostname = &Apache::lonnet::hostname($rule_in_effect);
206: if ($hostname) {
207: $switchto = $rule_in_effect;
208: }
209: }
1.18 raeburn 210: if ($hostname) {
211: my $protocol = $Apache::lonnet::protocol{$switchto};
212: $protocol = 'http' if ($protocol ne 'https');
213: $url = $protocol.'://'.$hostname;
1.23 raeburn 214: if ($rule_in_effect eq 'balancer') {
215: $message .= '<br />'.
216: &mt('As a result, your LON-CAPA session is being redirected to the server where you originally logged in.');
217: } else {
218: $message .= '<br />'.
219: &mt('As a result, your LON-CAPA session is being redirected.');
220: }
1.18 raeburn 221: }
222: }
1.35 ! raeburn 223: unless ($hosthere) {
! 224: if (($dataref->{'balancer'}) && ($dataref->{'balcookie'})) {
! 225: &Apache::lonnet::delbalcookie($dataref->{'balcookie'},$dataref->{'balancer'});
! 226: }
! 227: }
1.18 raeburn 228: }
229: if ($dataref->{'sso.login'}) {
1.21 raeburn 230: $url .= '/adm/roles';
1.18 raeburn 231: } else {
1.21 raeburn 232: $url .= '/adm/login';
1.24 raeburn 233: if ($udom) {
234: $url .= '?domain='.$udom;
235: }
1.20 raeburn 236: $message .= '<br />'.&mt('You will need to provide your password one more time.');
1.18 raeburn 237: }
238: my %info= (
1.24 raeburn 239: 'domain' => $udom,
1.18 raeburn 240: 'username' => $dataref->{'username'},
241: 'role' => $dataref->{'role'},
242: 'sessionserver' => $lonhost,
243: );
244: if ($dataref->{'origurl'}) {
245: $info{'origurl'} = $dataref->{'origurl'};
246: }
247: if ($dataref->{'symb'}) {
248: $info{'symb'} = $dataref->{'symb'};
249: }
250: my $iptoken = &Apache::lonnet::tmpput(\%info,$switchto);
251: unless ($iptoken eq 'conlost') {
1.24 raeburn 252: $url .= ($url =~ /\?/) ? '&' : '?';
253: $url .= 'iptoken='.$iptoken;
1.18 raeburn 254: }
255: $r->print(&Apache::loncommon::start_page($title,undef,
256: {'redirect' =>
257: [2,$url],}).
258: '<h1>'.&mt('One moment please...').'</h1>'.
259: '<p class="LC_warning">'.$message.'</p>'.
260: &Apache::loncommon::end_page());
261: } else {
262: return &goto_login($r);
1.10 raeburn 263: }
1.18 raeburn 264: return OK;
1.7 albertel 265: }
266:
1.28 raeburn 267: sub logout {
268: my ($r,$handle,$data,$lti_env) = @_;
1.34 raeburn 269: my $lonidsdir=$r->dir_config('lonIDsDir');
270: if (unlink("$lonidsdir/$handle.id")) {
271: if (($env{'user.linkedenv'} =~ /^[a-f0-9]+_linked$/) &&
272: (-l "$lonidsdir/$env{'user.linkedenv'}.id") &&
273: (readlink("$lonidsdir/$env{'user.linkedenv'}.id") eq "$lonidsdir/$handle.id")) {
274: unlink("$lonidsdir/$env{'user.linkedenv'}.id");
1.28 raeburn 275: }
276: }
277: my %temp=('logout' => time);
278: &Apache::lonnet::put('email_status',\%temp);
279: &Apache::lonnet::log($env{'user.domain'},
280: $env{'user.name'},
281: $env{'user.home'},
282: "Logout $ENV{'REMOTE_ADDR'}");
283:
284: &Apache::loncommon::content_type($r,'text/html');
285:
1.34 raeburn 286: #expire the cookies
287: my %cookies=CGI::Cookie->parse($r->header_in('Cookie'));
288: foreach my $name (keys(%cookies)) {
289: next unless ($name =~ /^lon(|S|Link|Pub)ID$/);
290: my $c = new CGI::Cookie(-name => $name,
291: -value => '',
292: -expires => '-10y',);
293: $r->headers_out->add('Set-cookie' => $c);
1.28 raeburn 294: }
295: my (%info,%user_info,%lti_info);
296: if (ref($lti_env) eq 'HASH') {
297: %lti_info = %{$lti_env};
298: }
299: my $lonhost = $r->dir_config('lonHostID');
300: if (ref($data) eq 'HASH') {
301: %user_info=('ip' => $ENV{'REMOTE_ADDR'},
302: 'domain' => $data->{'domain'},
303: 'username' => $data->{'username'},
304: 'role' => $data->{'role'},
305: 'origurl' => $data->{'origurl'},
306: 'symb' => $data->{'symb'},
307: 'server' => $lonhost);
308: }
309: %info = (%user_info,%lti_info);
310: my $token = &Apache::lonnet::tmpput(\%info,$lonhost);
311: my $url = '/adm/migrateuser?token='.$token;
312: $r->send_http_header;
313: $r->print(
314: &Apache::loncommon::start_page('Updating Session ...',undef,
315: {'redirect' => [0.1,$url],
316: 'only_body' => 1,}).
317: &Apache::loncommon::end_page());
318: $r->register_cleanup(\&flush_course_logs);
319: return;
320: }
321:
322: sub flush_course_logs {
323: &Apache::lonnet::flushcourselogs();
324: return OK;
325: }
326:
1.1 albertel 327: sub handler {
328: my ($r) = @_;
329:
330: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['token']);
1.4 albertel 331: my %data = &Apache::lonnet::tmpget($env{'form.token'});
1.13 raeburn 332: if (keys(%data) == 0) {
333: return &goto_login($r);
334: }
1.4 albertel 335: my $delete = &Apache::lonnet::tmpdel($env{'form.token'});
336:
1.6 albertel 337: &Apache::lonlocal::get_language_handle($r);
338:
1.4 albertel 339: if ($delete ne 'ok') {
1.27 raeburn 340: return &goto_login($r,undef,\%data);
1.4 albertel 341: }
1.2 albertel 342:
1.18 raeburn 343: if (!defined($data{'username'}) || !defined($data{'domain'})) {
1.27 raeburn 344: return &goto_login($r,undef,\%data);
1.18 raeburn 345: }
346: if ($data{'ip'} ne $ENV{'REMOTE_ADDR'}) {
1.24 raeburn 347: &Apache::lonnet::logthis('IP change when session migration requested -- was: '.
348: $data{'ip'}.'; now: '.$ENV{'REMOTE_ADDR'}.' for '.$data{'username'}.':'.$data{'domain'});
1.18 raeburn 349: return &ip_changed($r,$data{'domain'},$data{'server'},\%data);
1.2 albertel 350: }
351:
1.17 raeburn 352: &Apache::lonnet::logthis("Allowing access for $data{'username'}:$data{'domain'} to $data{'role'}");
1.2 albertel 353: my $home=&Apache::lonnet::homeserver($data{'username'},$data{'domain'});
1.24 raeburn 354: my $udom;
355: if (&Apache::lonnet::domain($data{'domain'})) {
356: $udom=$data{'domain'};
357: }
1.27 raeburn 358: if ($home =~ /(con_lost|no_such_host)/) { return &goto_login($r,$udom,\%data); }
359:
360: my $sso_env = &sso_check(\%data);
361: my $lti_env = <i_check(\%data);
1.2 albertel 362:
1.27 raeburn 363: my $extra_env;
364: if ((ref($sso_env) eq 'HASH') && (keys(%{$sso_env}))) {
365: $extra_env = $sso_env;
366: } elsif ((ref($lti_env) eq 'HASH') && (keys(%{$lti_env}))) {
367: $extra_env = $lti_env;
368: }
1.8 albertel 369:
1.16 raeburn 370: my %form;
371: if ($data{'symb'} ne '') {
372: $form{'symb'} = $data{'symb'};
373: }
1.21 raeburn 374: if ($data{'iptoken'} ne '') {
375: $form{'iptoken'} = $data{'iptoken'};
376: }
1.25 raeburn 377: if ($data{'noloadbalance'} ne '') {
378: $form{'noloadbalance'} = $data{'noloadbalance'};
379: }
1.16 raeburn 380:
1.3 albertel 381: if (!$data{'role'}) {
1.12 albertel 382: my $handle = &Apache::lonnet::check_for_valid_session($r);
383: if ($handle) {
1.11 albertel 384: &Apache::lonnet::transfer_profile_to_env($r->dir_config('lonIDsDir'),
385: $handle);
1.27 raeburn 386: if ($data{'lti.login'}) {
1.28 raeburn 387: my $needslogout;
388: if ($env{'request.lti.login'}) {
389: if (($env{'user.name'} ne $data{'username'}) ||
390: ($env{'user.domain'} ne $data{'domain'})) {
391: $needslogout = 1;
392: }
393: } else {
394: $needslogout = 1;
395: }
396: # If access is via LTI, and user already has a non-LTI session cookie
397: # (and session) or has an LTI session cookie for a different username,
398: # logout the existing session, and start a new one
399: if ($needslogout) {
400: &logout($r,$handle,\%data,$lti_env);
401: } elsif (($data{'lti.reqcrs'}) && ($data{'lti.reqrole'} eq 'cc')) {
1.27 raeburn 402: $form{'lti.reqcrs'} = $data{'lti.reqcrs'};
403: $form{'lti.reqrole'} = $data{'lti.reqrole'};
404: $form{'lti.sourcecrs'} = $data{'lti.sourcecrs'};
1.29 raeburn 405: $form{'lti.uri'} = $data{'lti.uri'};
1.28 raeburn 406: if ($data{'lti.passbackid'}) {
407: $form{'lti.passbackid'} = $data{'lti.passbackid'};
408: }
409: if ($data{'lti.passbackurl'}) {
410: $form{'lti.passbackurl'} = $data{'lti.passbackurl'};
411: }
412: if ($data{'lti.rosterid'}) {
413: $form{'lti.rosterid'} = $data{'lti.rosterid'};
414: }
415: if ($data{'lti.rosterurl'}) {
416: $form{'lti.rosterurl'} = $data{'lti.rosterurl'};
417: }
1.29 raeburn 418: if ($data{'lti.target'}) {
419: $form{'lti.target'} = $data{'lti.target'};
420: }
1.27 raeburn 421: &Apache::loncommon::content_type($r,'text/html');
422: $r->send_http_header;
423: &Apache::ltiauth::lti_reqcrs($r,$data{'domain'},\%form,$data{'username'},$data{'domain'});
1.28 raeburn 424: } else {
425: if (ref($lti_env) eq 'HASH') {
426: delete($lti_env->{'reqcrs'});
427: delete($lti_env->{'reqrole'});
428: delete($lti_env->{'selfenrollrole'});
429: }
430: if ($data{'lti.selfenrollrole'}) {
1.32 raeburn 431: if (&Apache::ltiauth::lti_enroll($data{'username'},$data{'domain'},
1.28 raeburn 432: $data{'lti.selfenrollrole'}) eq 'ok') {
433: my $url = '/adm/roles?selectrole=1&'.
434: &escape($data{'lti.selfenrollrole'}).'=1';
435: if ($data{'origurl'} =~ m{/default_\d+\.sequence$}) {
436: $url .= '&orgurl='.$data{'origurl'}.'&navmap=1';
437: } elsif ($data{'origurl'} ne '') {
438: $url .= '&orgurl='.$data{'origurl'};
439: }
440: if (ref($lti_env) eq 'HASH') {
441: &Apache::lonnet::appenv($lti_env);
442: }
443: $r->internal_redirect($url);
444: } else {
445: &Apache::ltiauth::invalid_request($r,23);
446: }
447: } elsif ($data{'origurl'} ne '') {
448: my $url = $data{'origurl'};
449: if ($url =~ m{/default_\d+\.sequence$}) {
450: $url .= (($url =~/\?/)?'&':'?').'navmap=1';
451: }
452: if (ref($lti_env) eq 'HASH') {
453: &Apache::lonnet::appenv($lti_env);
1.27 raeburn 454: }
455: $r->internal_redirect($url);
456: } else {
1.28 raeburn 457: if (ref($lti_env) eq 'HASH') {
458: &Apache::lonnet::appenv($lti_env);
459: }
1.27 raeburn 460: }
461: }
462: } elsif ($data{'origurl'} ne '') {
1.14 raeburn 463: $r->internal_redirect($data{'origurl'});
464: } elsif ($env{'request.course.id'}) {
465: $r->internal_redirect('/adm/navmaps');
1.11 albertel 466: } else {
467: $r->internal_redirect('/adm/roles');
468: }
469: } else {
1.14 raeburn 470: my $desturl = '/adm/roles';
471: if ($data{'origurl'} ne '') {
472: $desturl = $data{'origurl'};
1.27 raeburn 473: if ($data{'lti.login'}) {
474: $desturl = $data{'origurl'};
475: if ($desturl =~ m{/default_\d+\.sequence$}) {
476: $desturl .= (($desturl =~/\?/)?'&':'?').'navmap=1';
477: }
478: }
479: }
480: my $skipcritical;
481: if (($data{'lti.login'}) && ($data{'lti.reqcrs'}) &&
482: ($data{'lti.reqrole'} eq 'cc')) {
483: $skipcritical = 1;
1.14 raeburn 484: }
1.11 albertel 485: &Apache::lonauth::success($r,$data{'username'},$data{'domain'},
1.27 raeburn 486: $home,$desturl,$extra_env,\%form,$skipcritical);
1.11 albertel 487: }
1.1 albertel 488: return OK;
489: }
1.6 albertel 490:
1.33 raeburn 491: my $next_url='/adm/roles?selectrole=1&'.&escape($data{'role'}).'=1';
1.15 raeburn 492: if ($data{'origurl'} ne '') {
1.33 raeburn 493: $next_url .= '&orgurl='.&escape($data{'origurl'});
1.30 raeburn 494: if ($data{'lti.login'}) {
1.31 raeburn 495: if (($data{'origurl'} =~ m{/default_\d+\.sequence$}) ||
496: ($data{'origurl'} =~ m{^/res/.+\.sequence$})) {
1.33 raeburn 497: $next_url .= '&navmap=1';
1.30 raeburn 498: }
499: }
1.15 raeburn 500: }
1.6 albertel 501: &Apache::lonauth::success($r,$data{'username'},$data{'domain'},$home,
1.16 raeburn 502: $next_url,$extra_env,\%form);
1.6 albertel 503: return OK;
1.1 albertel 504: }
505:
506: 1;
507: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>