--- loncom/auth/lonacc.pm 2005/07/07 05:53:35 1.67 +++ loncom/auth/lonacc.pm 2006/06/22 13:20:46 1.81 @@ -1,7 +1,7 @@ # The LearningOnline Network # Cookie Based Access Handler # -# $Id: lonacc.pm,v 1.67 2005/07/07 05:53:35 albertel Exp $ +# $Id: lonacc.pm,v 1.81 2006/06/22 13:20:46 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -38,16 +38,308 @@ use Apache::lonlocal; use CGI::Cookie(); use Fcntl qw(:flock); +sub cleanup { + my ($r)=@_; + if (! $r->is_initial_req()) { return DECLINED; } + &Apache::lonnet::save_cache(); + return OK; +} + +sub goodbye { + my ($r)=@_; + &Apache::lonnet::goodbye(); + return DONE; +} + +############################################### + +sub get_posted_cgi { + my ($r) = @_; + + my $buffer; + if ($r->header_in('Content-length')) { + $r->read($buffer,$r->header_in('Content-length'),0); + } + unless ($buffer=~/^(\-+\w+)\s+Content\-Disposition\:\s*form\-data/si) { + my @pairs=split(/&/,$buffer); + my $pair; + foreach $pair (@pairs) { + my ($name,$value) = split(/=/,$pair); + $value =~ tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; + $name =~ tr/+/ /; + $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; + &Apache::loncommon::add_to_env("form.$name",$value); + } + } else { + my $contentsep=$1; + my @lines = split (/\n/,$buffer); + my $name=''; + my $value=''; + my $fname=''; + my $fmime=''; + my $i; + for ($i=0;$i<=$#lines;$i++) { + if ($lines[$i]=~/^$contentsep/) { + if ($name) { + chomp($value); + if ($fname) { + $env{"form.$name.filename"}=$fname; + $env{"form.$name.mimetype"}=$fmime; + } else { + $value=~s/\s+$//s; + } + &Apache::loncommon::add_to_env("form.$name",$value); + } + if ($i<$#lines) { + $i++; + $lines[$i]=~ + /Content\-Disposition\:\s*form\-data\;\s*name\=\"([^\"]+)\"/i; + $name=$1; + $value=''; + if ($lines[$i]=~/filename\=\"([^\"]+)\"/i) { + $fname=$1; + if + ($lines[$i+1]=~/Content\-Type\:\s*([\w\-\/]+)/i) { + $fmime=$1; + $i++; + } else { + $fmime=''; + } + } else { + $fname=''; + $fmime=''; + } + $i++; + } + } else { + $value.=$lines[$i]."\n"; + } + } + } +# +# Digested POSTed values +# +# Remember the way this was originally done (GET or POST) +# + $env{'request.method'}=$ENV{'REQUEST_METHOD'}; +# +# There may also be stuff in the query string +# Tell subsequent handlers that this was GET, not POST, so they can access query string. +# Also, unset POSTed content length to cover all tracks. +# + + $r->method_number(M_GET); + + $r->method('GET'); + $r->headers_in->unset('Content-length'); +} + +sub portfolio_access { + my ($udom,$unum,$file_name,$group) = @_; + my $current_perms = &Apache::lonnet::get_portfile_permissions($udom,$unum); + my %access_controls = &Apache::lonnet::get_access_controls( + $current_perms,$group,$file_name); + my ($public,$guest,@domains,@users,@courses,@groups); + my $now = time; + my $access_hash = $access_controls{$file_name}; + if (ref($access_hash) eq 'HASH') { + foreach my $key (keys(%{$access_hash})) { + my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/); + if ($start > $now) { + next; + } + if ($end && $end<$now) { + next; + } + if ($scope eq 'public') { + $public = $key; + last; + } elsif ($scope eq 'guest') { + $guest = $key; + } elsif ($scope eq 'domains') { + push(@domains,$key); + } elsif ($scope eq 'users') { + push(@users,$key); + } elsif ($scope eq 'course') { + push(@courses,$key); + } elsif ($scope eq 'group') { + push(@groups,$key); + } + } + if ($public) { + return 'ok'; + } + if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { + if ($guest) { + return 'guest:'.$guest; + } + } else { + if (@domains > 0) { + foreach my $domkey (@domains) { + my %content = &Apache::lonnet::parse_access_controls($$access_hash{$domkey}); + if (ref($content{'dom'}) eq 'ARRAY') { + if (grep(/^\Q$env{'user.domain'}\E$/,@{$content{'dom'}})) { + return 'ok'; + } + } + } + } + if (@users > 0) { + foreach my $userkey (@users) { + my %content = &Apache::lonnet::parse_access_controls($$access_hash{$userkey}); + if (exists($content{'users'}{$env{'user.name'}.':'.$env{'user.domain'}})) { + return 'ok'; + } + } + } + my %roleshash; + my @courses_and_groups = @courses; + push(@courses_and_groups,@groups); + if (@courses_and_groups > 0) { + my (%allgroups,%allroles); + my ($start,$end,$role,$sec,$group); + foreach my $envkey (%env) { + if ($envkey =~ m-^user\.role\.(gr|cc|in|ta|ep|st)\./([^/]+)/([^/]+)/?([^/]*)$-) { + my $cid = $2.'_'.$3; + if ($1 eq 'gr') { + $group = $4; + $allgroups{$cid}{$group} = $env{$envkey}; + } else { + if ($4 eq '') { + $sec = 'none'; + } else { + $sec = $4; + } + $allroles{$cid}{$1}{$sec} = $env{$envkey}; + } + } elsif ($envkey =~ m-^user\.role\./cr/(\w+/\w+/\w*)./([^/]+)/([^/]+)/?([^/]*)$-) { + my $cid = $2.'_'.$3; + if ($4 eq '') { + $sec = 'none'; + } else { + $sec = $4; + } + $allroles{$cid}{$1}{$sec} = $env{$envkey}; + } + } + if (keys(%allroles) == 0) { + return; + } + foreach my $key (@courses_and_groups) { + my %content = &Apache::lonnet::parse_access_controls($$access_hash{$key}); + my $cnum = $content{'number'}; + my $cdom = $content{'domain'}; + my $cid = $cdom.'_'.$cnum; + if (!exists($allroles{$cid})) { + next; + } + foreach my $role_id (keys(%{$content{'roles'}})) { + my @sections = @{$content{'roles'}{$role_id}{'section'}}; + my @groups = @{$content{'roles'}{$role_id}{'group'}}; + my @status = @{$content{'roles'}{$role_id}{'access'}}; + my @roles = @{$content{'roles'}{$role_id}{'role'}}; + foreach my $role (keys(%{$allroles{$cid}})) { + if ((grep/^all$/,@roles) || (grep/^\Q$role\E$/,@roles)) { + foreach my $sec (keys(%{$allroles{$cid}{$role}})) { + if (&course_group_datechecker($allroles{$cid}{$role}{$sec},$now,\@status) eq 'ok') { + if (grep/^all$/,@sections) { + return 'ok'; + } else { + if (grep/^$sec$/,@sections) { + return 'ok' + } + } + } + } + if (keys(%{$allgroups{$cid}}) == 0) { + if (grep/^none$/,@groups) { + return 'ok'; + } + } else { + if (grep/^all$/,@groups) { + return 'ok'; + } + foreach my $group (keys(%{$allgroups{$cid}})) { + if (grep/^$group$/,@groups) { + return 'ok'; + } + } + } + } + } + } + } + } + if ($guest) { + return 'guest:'.$guest; + } + } + } + return; +} + +sub course_group_datechecker { + my ($dates,$now,$status) = @_; + my ($start,$end) = split(/\./,$dates); + if (!$start && !$end) { + return 'ok'; + } + if (grep/^active$/,@{$status}) { + if (((!$start) || ($start && $start <= $now)) && ((!$end) || ($end && $end >= $now))) { + return 'ok'; + } + } + if (grep/^previous$/,@{$status}) { + if ($end > $now ) { + return 'ok'; + } + } + if (grep/^future$/,@{$status}) { + if ($start > $now) { + return 'ok'; + } + } + return; +} + sub handler { my $r = shift; my $requrl=$r->uri; my %cookies=CGI::Cookie->parse($r->header_in('Cookie')); my $lonid=$cookies{'lonID'}; my $cookie; + my $lonidsdir=$r->dir_config('lonIDsDir'); + + my $handle; if ($lonid) { - my $handle=$lonid->value; + $handle=$lonid->value; $handle=~s/\W//g; - my $lonidsdir=$r->dir_config('lonIDsDir'); + } + + my ($sso_login); + if ($r->user + && (!$lonid || !-e "$lonidsdir/$handle.id" || $handle eq '') ) { + $sso_login = 1; + my $domain = $r->dir_config('lonDefDomain'); + my $home=&Apache::lonnet::homeserver($r->user,$domain); + if ($home !~ /(con_lost|no_such_host)/) { + $handle=&Apache::lonauth::success($r,$r->user,$domain, + $home,'noredirect'); + $r->header_out('Set-cookie',"lonID=$handle; path=/"); + } + } + + if ($sso_login) { + &Apache::lonnet::appenv('request.sso.login' => 1); + } + + if ($r->dir_config("lonBalancer") eq 'yes') { + $r->set_handlers('PerlResponseHandler'=> + [\&Apache::switchserver::handler]); + } + + if ($handle ne '') { if ((-e "$lonidsdir/$handle.id") && ($handle ne '')) { # ------------------------------------------------------ Initialize Environment @@ -69,10 +361,27 @@ sub handler { $env{'request.noversionuri'} = &Apache::lonnet::deversion($requrl); # -------------------------------------------------------- Load POST parameters - &Apache::loncommon::get_posted_cgi($r); + &Apache::lonacc::get_posted_cgi($r); # ---------------------------------------------------------------- Check access - + my $now = time; + if ($requrl =~ m|/+uploaded/([^/]+)/([^/]+)/portfolio(/.+)$|) { + my $result = &portfolio_access($1,$2,$3); + if ($result eq 'ok') { + return OK; + } elsif ($result =~ /^guest:(\w+)$/) { + my $guestkey = $1; + #FIXME need to cause generation of an intermediate page + } + } elsif ($requrl =~ m|/+uploaded/([^/]+)/([^/]+)/groups/([^/]+)/portfolio/(.+)$|) { + my $result = &portfolio_access($1,$2,$3.'/'.$4,$3); + if ($result eq 'ok') { + return OK; + } elsif ($result =~ /^guest:(\w+)$/) { + my $guestkey = $1; + #FIXME need to cause generation of an intermediate page +} + } if ($requrl!~/^\/adm|public|prtspool\//) { my $access=&Apache::lonnet::allowed('bre',$requrl); if ($access eq '1') { @@ -95,7 +404,7 @@ sub handler { if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public' && $requrl !~ m{^/+(res|public)/} && - $requrl !~ m{^/+adm/(roles|logout|randomlabel\.png)}) { + $requrl !~ m{^/+adm/(help|logout|randomlabel\.png)}) { $env{'request.querystring'}=$r->args; $env{'request.firsturl'}=$requrl; return FORBIDDEN; @@ -107,6 +416,7 @@ sub handler { if ((&Apache::loncommon::fileembstyle($1) eq 'ssi') || ($requrl=~/^\/adm\/.*\/(aboutme|navmaps|smppg|bulletinboard)(\?|$)/) || ($requrl=~/^\/adm\/wrapper\//) || + ($requrl=~m|^/adm/coursedocs/showdoc/|) || ($requrl=~m|\.problem/smpedit$|) || ($requrl=~/^\/public\/.*\/syllabus$/)) { # ------------------------------------- This is serious stuff, get symb and log @@ -117,7 +427,8 @@ sub handler { } if ($env{'form.symb'}) { $symb=&Apache::lonnet::symbclean($env{'form.symb'}); - if ($requrl =~ m|^/adm/wrapper/|) { + if ($requrl =~ m|^/adm/wrapper/| + || $requrl =~ m|^/adm/coursedocs/showdoc/|) { my ($map,$mid,$murl)=&Apache::lonnet::decode_symb($symb); &Apache::lonnet::symblist($map,$murl => [$murl,$mid], 'last_known' =>[$murl,$mid]); @@ -125,7 +436,7 @@ sub handler { (($requrl=~m|(.*)/smpedit$|) && &Apache::lonnet::symbverify($symb,$1))) { my ($map,$mid,$murl)=&Apache::lonnet::decode_symb($symb); - &Apache::lonnet::symblist($map,$murl => [$murl,$mid], + &Apache::lonnet::symblist($map,$murl => [$murl,$mid], 'last_known' =>[$murl,$mid]); } else { $r->log_reason('Invalid symb for '.$requrl.': '. @@ -159,19 +470,20 @@ sub handler { } return OK; } else { - $r->log_reason("Cookie $handle not valid", $r->filename) - }; + $r->log_reason("Cookie $handle not valid", $r->filename); + } } # -------------------------------------------- See if this is a public resource if ($requrl=~m|^/public/| || (&Apache::lonnet::metadata($requrl,'copyright') eq 'public')) { &Apache::lonnet::logthis('Granting public access: '.$requrl); + &Apache::lonlocal::get_language_handle($r); my $cookie= &Apache::lonauth::success($r,'public','public','public'); my $lonidsdir=$r->dir_config('lonIDsDir'); &Apache::lonnet::transfer_profile_to_env($lonidsdir,$cookie); - &Apache::loncommon::get_posted_cgi($r); + &Apache::lonacc::get_posted_cgi($r); $env{'request.state'} = "published"; $env{'request.publicaccess'} = 1; $env{'request.filename'} = $r->filename; @@ -179,6 +491,27 @@ sub handler { $r->header_out('Set-cookie',"lonID=$cookie; path=/"); return OK; } + if ($requrl=~m|^/+adm/+help/+|) { + return OK; + } +# ------------------------------------- See if this is a viewable portfolio file + if ($requrl =~ m|/+uploaded/([^/]+)/([^/]+)/portfolio(/.+)$|) { + my $result = &portfolio_access($1,$2,$3); + if ($result eq 'ok') { + return OK; + } elsif ($result =~ /^guest:(\w+)$/) { + my $guestkey = $1; + #FIXME need to cause generation of an intermediate page + } + } elsif ($requrl =~ m|/+uploaded/([^/]+)/([^/]+)/groups/([^/]+)/portfolio/(.+)$|) { + my $result = &portfolio_access($1,$2,$4.'/'.$3,$3); + if ($result eq 'ok') { + return OK; + } elsif ($result =~ /^guest:(\w+)$/) { + my $guestkey = $1; + #FIXME need to cause generation of an intermediate page + } + } # -------------------------------------------------------------- Not authorized $requrl=~/\.(\w+)$/; # if ((&Apache::loncommon::fileembstyle($1) eq 'ssi') || 500 Internal Server Error

Internal Server Error

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

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

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