version 1.1, 2012/02/27 03:06:33
|
version 1.7, 2020/12/18 15:23:03
|
Line 34 Apache::lonwebdavacc - webDAV Authorizat
|
Line 34 Apache::lonwebdavacc - webDAV Authorizat
|
|
|
=head1 SYNOPSIS |
=head1 SYNOPSIS |
|
|
Invoked for /+webdav/[\w\-]+/[\w\-]+/ by |
Invoked for ^/+webdav/[\w\-.]+/\w[\w.\-\@]+/ by |
/etc/httpd/conf/loncapa_apache.conf: |
/etc/httpd/conf/loncapa_apache.conf: |
|
|
PerlAccessHandler Apache::lonwebdavacc |
PerlAccessHandler Apache::lonwebdavacc |
Line 44 PerlAccessHandler Apache::lonwebda
|
Line 44 PerlAccessHandler Apache::lonwebda
|
This module enables authorization for authoring space |
This module enables authorization for authoring space |
and is used to control access for the following type of URI: |
and is used to control access for the following type of URI: |
|
|
<LocationMatch "^/webdav/[\w\-]+/[\w\-]+> |
<LocationMatch "^/+webdav/[\w\-.]+/\w[\w.\-\@]+/"> |
|
|
This module is only called following successful authentication. |
This module is only called following successful authentication. |
Unless lonOtherAuthen has been set, so Single Sign On can be used, |
Successful authentication will have created a session file and |
successful authentication will have created a session file and |
|
transferred the contents to the user's environment. |
transferred the contents to the user's environment. |
|
|
In the case of SSO, there is no existing user environment, but |
Note: because Apache Basic Auth is used for authentication |
$r->user will have been set to the user's username, following |
|
successful authentication. For SSO, the webDAV session file |
|
and environment are set up by a call to |
|
Apache::lonwebdavauth::init_webdav_env(). |
|
|
|
Note: because Apache Basic Auth is used for authentication (unless SSO) |
|
webDAV access is only available for servers running Apache with SSL. |
webDAV access is only available for servers running Apache with SSL. |
|
|
This is part of the LearningOnline Network with CAPA project |
This is part of the LearningOnline Network with CAPA project |
Line 75 Checks if $env{'user.environment'} is de
|
Line 68 Checks if $env{'user.environment'} is de
|
|
|
=item * |
=item * |
|
|
If no %env, this was SSO authentication so call to &sso_login() to |
If no %env, calls Apache::lonnet::check_for_valid_session() |
create session, and return cookie. |
to retrieve a valid sessionID (webDAV client needs to support |
|
cookies for session retrieval to be successful). If a session is |
|
found Apache::lonnet::transfer_profile_to_env() is called |
|
to populate %env. |
|
|
=item * |
=item * |
|
|
Checks if requested URL (of form /webdav/authordomain/authorname) is valid |
Checks if requested URL (of form /webdav/authordomain/authorname) is valid |
and whether authenticated user has an active author or co-author |
and whether authenticated user has an active author or co-author |
role in the corresonding Author Space. |
role in the corresponding Authoring Space. |
|
|
=back |
=back |
|
|
Line 96 role in the corresonding Author Space.
|
Line 92 role in the corresonding Author Space.
|
|
|
=item * |
=item * |
|
|
Called if no user.environment exists in %env. |
Not currently used. |
|
|
=item * |
=item * |
|
|
Line 124 use strict;
|
Line 120 use strict;
|
use GDBM_File; |
use GDBM_File; |
use Apache::Constants qw(:common :http :methods); |
use Apache::Constants qw(:common :http :methods); |
use Apache::lonnet; |
use Apache::lonnet; |
|
use Apache::londiff(); |
use LONCAPA qw(:DEFAULT :match); |
use LONCAPA qw(:DEFAULT :match); |
|
|
sub handler { |
sub handler { |
Line 132 sub handler {
|
Line 129 sub handler {
|
my $now = time; |
my $now = time; |
my $sessiondir=$r->dir_config('lonDAVsessDir'); |
my $sessiondir=$r->dir_config('lonDAVsessDir'); |
|
|
my ($adom,$aname); |
my ($adom,$aname) = ($r->uri =~ m{^/webdav/($match_domain)/($match_username)/}); |
|
my $author = "$aname:$adom"; |
unless ($env{'user.environment'}) { |
unless ($env{'user.environment'}) { |
my $handle = &Apache::lonnet::check_for_valid_session($r,'lonDAV'); |
my $handle = &Apache::lonnet::check_for_valid_session($r,'lonDAV'); |
if ($handle eq '') { |
if ($handle ne '') { |
$handle = &sso_login($r,$sessiondir,$now,$timetolive); |
|
if ($handle eq '') { |
|
return FORBIDDEN; |
|
} |
|
} else { |
|
&Apache::lonnet::transfer_profile_to_env($sessiondir,$handle); |
&Apache::lonnet::transfer_profile_to_env($sessiondir,$handle); |
|
} else { |
|
return FORBIDDEN; |
} |
} |
} |
} |
my $uhome=&Apache::lonnet::homeserver($env{'user.name'},$env{'user.domain'}); |
my $uhome=&Apache::lonnet::homeserver($env{'user.name'},$env{'user.domain'}); |
Line 149 sub handler {
|
Line 144 sub handler {
|
return FORBIDDEN; |
return FORBIDDEN; |
} |
} |
|
|
($adom,$aname) = ($r->uri =~ m{^/webdav/($match_domain)/($match_username)/}); |
|
my $docroot = $r->dir_config('lonDocRoot'); |
my $docroot = $r->dir_config('lonDocRoot'); |
if ($adom eq '' || $aname eq '') { |
if ($adom eq '' || $aname eq '') { |
return FORBIDDEN; |
return FORBIDDEN; |
} elsif (!-d "$docroot/priv/$adom/$aname") { |
} elsif (!-d "$docroot/priv/$adom/$aname") { |
return FORBIDDEN; |
return FORBIDDEN; |
} |
} |
# FIXME method check for MKCOL MOVE PUT DELETE for *.log, *.bak |
my $allowed; |
# FIXME method check for regexp for "version-style" names: /\.\d+\.\w+$/ |
|
# for MOVE PUT MKCOL |
|
if (($env{'user.name'} eq $aname) && ($env{'user.domain'} eq $adom)) { |
if (($env{'user.name'} eq $aname) && ($env{'user.domain'} eq $adom)) { |
if ($env{"user.role.au./$adom/"}) { |
if ($env{"user.role.au./$adom/"}) { |
return OK; |
$allowed = 1; |
} |
} |
} else { |
} else { |
if (($env{"user.role.ca./$adom/$aname"}) || |
if (($env{"user.role.ca./$adom/$aname"}) || |
(env{"user.role.aa./$adom/$aname"})) { |
($env{"user.role.aa./$adom/$aname"})) { |
return OK; |
$allowed = 1; |
} |
} |
} |
} |
|
if ($allowed) { |
|
my $method = $r->method(); |
|
if (($r->filename =~ /.+\.(log|bak|meta|save)$/) || ($r->filename =~ /\.\d+\.\w+$/) || |
|
($r->filename =~ m{/\.+[^_/]+$})) { |
|
if (($method eq 'MKCOL') || ($method eq 'PUT')) { |
|
return FORBIDDEN; |
|
} elsif ($method eq 'MOVE') { |
|
if (($r->filename =~ /\.\d+\.\w+$/) || ($r->filename =~ m{/\.+[^_/]+$})) { |
|
return FORBIDDEN; |
|
} |
|
} |
|
} |
|
if (($method eq 'DELETE') || ($method eq 'MOVE')) { |
|
unless (($r->filename =~ m{/\._[^/]+$}) || ($r->filename =~ m{/\.DS_Store$})) { |
|
my $dirptr=16384; |
|
my ($cmode,$cmtime)=(stat($r->filename))[2,9]; |
|
if (($cmode&$dirptr)) { |
|
my $numpub = 0; |
|
$numpub = &recurse_dir($r->filename,$r->dir_config('lonDocRoot'),$numpub); |
|
if ($numpub) { |
|
return FORBIDDEN; |
|
} |
|
} else { |
|
if ($r->filename =~ /^(.+)\.(log|bak|save|meta)$/) { |
|
my $conjugate = $1; |
|
my $type = $2; |
|
if (($type eq 'log') || ($type eq 'meta')) { |
|
if (-e $conjugate) { |
|
my $conjstatus = &pubstatus($conjugate,$r->dir_config('lonDocRoot')); |
|
unless (($conjstatus eq 'unpublished') || ($conjstatus eq 'obsolete')) { |
|
return FORBIDDEN; |
|
} |
|
} |
|
} |
|
} else { |
|
my $status = &pubstatus($r->filename,$r->dir_config('lonDocRoot')); |
|
unless (($status eq 'unpublished') || ($status eq 'obsolete')) { |
|
return FORBIDDEN; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return OK; |
|
} |
return FORBIDDEN; |
return FORBIDDEN; |
} |
} |
|
|
sub sso_login { |
sub sso_login { |
my ($r,$sessiondir,$now,$timetolive) = @_; |
my ($r,$sessiondir,$now,$timetolive,$author) = @_; |
my ($uname,$udom); |
my ($uname,$udom); |
my ($uname) = ($r->user =~ m/([a-zA-Z0-9_\-@.]*)/); |
my ($uname) = ($r->user =~ m/([a-zA-Z0-9_\-@.]*)/); |
unless ($uname =~ /^$match_username$/) { |
unless ($uname =~ /^$match_username$/) { |
Line 191 sub sso_login {
|
Line 228 sub sso_login {
|
return; |
return; |
} |
} |
my $handle = |
my $handle = |
&Apache::lonwebdavauth::init_webdav_env($sessiondir,$uname,$udom, |
&Apache::lonwebdavauth::init_webdav_env($r,$sessiondir,$uname,$udom, |
$uhome,$now,$timetolive); |
$uhome,$now,$timetolive,$author); |
if ($handle ne '') { |
if ($handle ne '') { |
my $cookie = "lonDAV=$handle; path=/webdav/; secure; HttpOnly;"; |
if (&Apache::lonnet::usertools_access($uname,$udom,'webdav')) { |
$r->header_out('Set-cookie' => $cookie); |
my ($webdav) = |
$r->send_http_header; |
($r->uri =~ m{^(/webdav/$match_domain/$match_username/)}); |
|
my $ip = &Apache::lonnet::get_requestor_ip(); |
|
&Apache::lonnet::log($udom,$uname,$uhome, |
|
"SSO log-in to $webdav from $ip"); |
|
my $cookie = "lonDAV=$handle; path=/webdav/; secure; HttpOnly;"; |
|
$r->header_out('Set-cookie' => $cookie); |
|
$r->send_http_header; |
|
} |
} |
} |
return ($handle); |
return ($handle); |
} |
} |
|
|
|
sub pubstatus { |
|
my ($fn,$docroot,$cmtime) = @_; |
|
my $privfn = $fn; |
|
my $thisdisfn = $fn; |
|
$thisdisfn=~s/^\Q$docroot\E\/priv//; |
|
my $resfn=$docroot.'/res'.$thisdisfn; |
|
my $targetfn = '/res'.$thisdisfn; |
|
my $status = 'unpublished'; |
|
if (-e $resfn) { |
|
$status = 'published'; |
|
my $same = 0; |
|
if ((stat($resfn))[9] >= $cmtime) { |
|
$same = 1; |
|
} else { |
|
if (&Apache::londiff::are_different_files($resfn,$privfn)) { |
|
$same = 0; |
|
} else { |
|
$same = 1; |
|
} |
|
} |
|
if ($same) { |
|
if (&Apache::lonnet::metadata($targetfn,'obsolete')) { |
|
$status = 'obsolete'; |
|
} |
|
} |
|
} |
|
return $status; |
|
} |
|
|
|
sub recurse_dir { |
|
my ($dirname,$docroot,$numpub) = @_; |
|
$dirname =~ s{/$}{}; |
|
my $dirptr=16384; |
|
if (opendir(my $dirh,$dirname)) { |
|
my @items = readdir($dirh); |
|
closedir($dirh); |
|
foreach my $item (@items) { |
|
next if ($item =~ /.+\.(log|bak|save|meta)$/); |
|
next if ($item =~ /^\.+/); |
|
my ($cmode,$cmtime)=(stat("$dirname/$item"))[2,9]; |
|
if (!($cmode&$dirptr)) { |
|
if (&pubstatus("$dirname/$item",$docroot,$cmtime) eq 'published') { |
|
$numpub ++; |
|
} |
|
} else { |
|
$numpub = &recurse_dir("$dirname/$item",$docroot,$numpub); |
|
} |
|
} |
|
} |
|
return $numpub; |
|
} |
|
|
1; |
1; |