Annotation of loncom/auth/lonwebdavauth.pm, revision 1.1
1.1 ! raeburn 1: # The LearningOnline Network
! 2: # Authentication Handler for webDAV access to Authoring Space.
! 3: #
! 4: # $Id: lonwebdavauth.pm,v 1.1 2012/2/25 19:37:40 raeburn Exp $
! 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: =head1 NAME
! 30:
! 31: Apache::lonwebdavauth - webDAV Authentication Handler
! 32:
! 33: =head1 SYNOPSIS
! 34:
! 35: Invoked for /+webdav/[\w\-]+/[\w\-]+/ by
! 36: /etc/httpd/conf/loncapa_apache.conf:
! 37:
! 38: PerlAuthenHandler Apache::lonwebdavauth
! 39:
! 40: =head1 INTRODUCTION
! 41:
! 42: This module employs Apache Basic Auth authentication and is used
! 43: to provide authentication for webDAV client access to author
! 44: space(s). Note: because Apache Basic Auth is used, webDAV access
! 45: is only available for servers running Apache with SSL.
! 46:
! 47: If the webDAV client supports cookies then whenever the client
! 48: sends the cookie back, a check is made to see if a corresponding
! 49: valid session file exists in the server's webDAV session directory.
! 50: Support for cookies by webDAV clients is optional.
! 51:
! 52: If a valid session file exists, a cookie is returned containing
! 53: the session ID, otherwise a new session file is created and
! 54: returned in the cookie.
! 55:
! 56: The perlvar "lonDAVsessDir" in /etc/httpd/conf/loncapa_apache.conf
! 57: provides the directory location: /home/httpd/webdav/sessionIDs.
! 58:
! 59: If the session is stale, or the cookie is missing or invalid,
! 60: the user is re-challenged for login information. If the perlvar
! 61: lonOtherAuthen has been set, Single Sign On will be used, otherwise
! 62: an Apache Basic Auth request will be sent to the client.
! 63:
! 64: If Apache Basic Auth is used, successful authentication will
! 65: result in creation of a webDAV session file containing a
! 66: minimal set of information about the user which will also be
! 67: loaded into the user's environment. The environment persists
! 68: until the end of the Apache request, when it is cleaned up
! 69: by lonacc::cleanup, as is the case for requests for non-webdav URLs.
! 70:
! 71: If a valid session file exists, a cookie is returned containing
! 72: the session ID, otherwise a new session file is created and
! 73: returned in the cookie.
! 74:
! 75: This is part of the LearningOnline Network with CAPA project
! 76: described at http://www.lon-capa.org.
! 77:
! 78: =head1 HANDLER SUBROUTINE
! 79:
! 80: This routine is called by Apache and mod_perl.
! 81:
! 82: =over 4
! 83:
! 84: =item *
! 85:
! 86: Check for valid webDAV session
! 87:
! 88: =item *
! 89:
! 90: No session? - if SSO enabled: return DECLINED
! 91:
! 92: =item *
! 93:
! 94: No session? - if SSO not enabled: return AUTH_REQUIRED
! 95: which will prompt webDAV client to authenticate user
! 96: (via Apache Basic Auth).
! 97:
! 98: =item *
! 99:
! 100: If authenticated, call &init_webdav_env() to create sessionID
! 101: and populate environment, and send header containing cookie.
! 102:
! 103: =back
! 104:
! 105: =head1 NOTABLE SUBROUTINES
! 106:
! 107: =over
! 108:
! 109: =item * init_webdav_env()
! 110:
! 111: =over
! 112:
! 113: =item *
! 114:
! 115: Checks for valid session files in webDAV session directory.
! 116:
! 117: =item *
! 118:
! 119: Calls Apache::lonnet::transfer_profile_to_env() to create
! 120: %env for user if session is valid.
! 121:
! 122: =item *
! 123:
! 124: Otherwise creates new session file and populates %env.
! 125:
! 126: =item *
! 127:
! 128: Session ID file is a GDBM file containing:
! 129:
! 130: =over
! 131:
! 132: =item * user.name, user.domain, user.home, user.environment
! 133:
! 134: =item * user.role entries for:
! 135:
! 136: active author, co-author, and assistant co-author roles
! 137: in domains hosted on this machine.
! 138:
! 139: =back
! 140:
! 141: =back
! 142:
! 143: =back
! 144:
! 145: =cut
! 146:
! 147: package Apache::lonwebdavauth;
! 148:
! 149: use strict;
! 150: use GDBM_File;
! 151: use Apache::Constants qw(:common :http :methods);
! 152: use Apache::lonnet;
! 153: use LONCAPA qw(:DEFAULT :match);
! 154:
! 155: sub handler {
! 156: my $r = shift;
! 157: my $now = time;
! 158: my $timetolive = 600;
! 159: my $sessiondir=$r->dir_config('lonDAVsessDir');
! 160: my ($uname,$udom,$uhome);
! 161:
! 162: # Check for cookie
! 163: my $handle = &Apache::lonnet::check_for_valid_session($r,'lonDAV');
! 164: if ($handle ne '') {
! 165: my $sesstime;
! 166: ($uname,$udom,$sesstime,$uhome) =
! 167: ($handle =~ /^($match_username)_($match_domain)_(\d+)_\d+_(.+)$/);
! 168: if ($sesstime) {
! 169: if ($now-$sesstime < $timetolive) {
! 170: if (&Apache::lonnet::homeserver($uname,$udom) eq $uhome) {
! 171: &Apache::lonnet::transfer_profile_to_env($sessiondir,$handle);
! 172: return OK;
! 173: }
! 174: }
! 175: }
! 176: }
! 177:
! 178: if ($r->dir_config('lonOtherAuthen') eq 'yes') {
! 179: if (defined($r->dir_config('lonOtherAuthenType'))) {
! 180: $r->auth_type($r->dir_config('lonOtherAuthenType'));
! 181: }
! 182: return DECLINED;
! 183: }
! 184:
! 185: my ($status,$upass) = $r->get_basic_auth_pw;
! 186: return $status unless ($status == 0 || $status == OK);
! 187:
! 188: if ($r->user =~ /,/) {
! 189: ($uname,$udom) = split(/,/,$r->user);
! 190: unless (($uname =~ /^$match_username$/) && ($udom =~ /^$match_domain$/)) {
! 191: $r->note_basic_auth_failure;
! 192: return AUTH_REQUIRED;
! 193: }
! 194: } else {
! 195: $uname = $r->user;
! 196: ($udom) = ($r->uri =~ m{^/webdav/($match_domain)/});
! 197: unless (($udom ne '' ) && ($uname =~ /^$match_username$/)) {
! 198: $r->note_basic_auth_failure;
! 199: return AUTH_REQUIRED;
! 200: }
! 201: }
! 202: if (&Apache::lonnet::domain($udom) ne '') {
! 203: if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') {
! 204: my $uhome = &Apache::lonnet::authenticate($uname,$upass,$udom);
! 205: if (($uhome ne 'no_host') &&
! 206: (&Apache::lonnet::hostname($uhome) ne '')) {
! 207: $handle = &init_webdav_env($sessiondir,$uname,$udom,
! 208: $uhome,$now,$timetolive);
! 209: if ($handle ne '') {
! 210: my $cookie = "lonDAV=$handle; path=/webdav/; secure; HttpOnly;";
! 211: $r->header_out('Set-cookie' => $cookie);
! 212: $r->send_http_header;
! 213: }
! 214: return OK;
! 215: }
! 216: }
! 217: }
! 218: $r->note_basic_auth_failure;
! 219: return AUTH_REQUIRED;
! 220: }
! 221:
! 222: sub init_webdav_env {
! 223: my ($sessiondir,$uname,$udom,$uhome,$now,$timetolive) = @_;
! 224: my $handle;
! 225: my $currnewest = 0;
! 226: if ($sessiondir ne '') {
! 227: if (opendir(DIR,$sessiondir)) {
! 228: while (my $filename=readdir(DIR)) {
! 229: if ($filename=~/^($uname\_$udom\_(\d+)\_\d+\_$uhome)\.id$/) {
! 230: my $oldhandle = $1;
! 231: my $sesstime = $2;
! 232: if ($now-$sesstime < $timetolive) {
! 233: if ($sesstime > $currnewest) {
! 234: $currnewest = $sesstime;
! 235: if ($handle ne '') {
! 236: unlink("$sessiondir/$handle.id");
! 237: }
! 238: $handle = $oldhandle;
! 239: next;
! 240: }
! 241: }
! 242: unlink($sessiondir.'/'.$filename);
! 243: }
! 244: }
! 245: closedir(DIR);
! 246: }
! 247: }
! 248: if ($handle ne '') {
! 249: &Apache::lonnet::transfer_profile_to_env($sessiondir,$handle);
! 250: return $handle;
! 251: } else {
! 252: my $id = $$.int(rand(10000000));
! 253: $handle = "$uname\_$udom\_$now\_$id\_$uhome";
! 254: my $sessionfile = "$sessiondir/$handle.id";
! 255: if (tie(my %disk_env,'GDBM_File',"$sessionfile",
! 256: &GDBM_WRCREAT(),0640)) {
! 257: $disk_env{'user.name'} = $uname;
! 258: $disk_env{'user.domain'} = $udom;
! 259: $disk_env{'user.home'} = $uhome;
! 260: $disk_env{'user.environment'} = $sessionfile;
! 261: my $possroles = ['au','ca','aa'];
! 262: my @possdoms = &Apache::lonnet::current_machine_domains();
! 263: my %cstr_roles =
! 264: &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
! 265: undef,$possroles,\@possdoms);
! 266: foreach my $item (keys(%cstr_roles)) {
! 267: my ($aname,$adom,$role) = split(/:/,$item);
! 268: if ($role eq 'au') {
! 269: $disk_env{"user.role.$role./$adom/"} = $cstr_roles{$item};
! 270: } else {
! 271: $disk_env{"user.role.$role./$adom/$aname"} = $cstr_roles{$item};
! 272: }
! 273: }
! 274: @env{keys(%disk_env)} = @disk_env{keys(%disk_env)};
! 275: untie(%disk_env);
! 276: }
! 277: return $handle;
! 278: }
! 279: return;
! 280: }
! 281:
! 282: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>