[system] / trunk / webwork2 / lib / WeBWorK / Authen.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK/Authen.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1682 - (download) (as text) (annotate)
Tue Dec 23 05:25:09 2003 UTC (9 years, 5 months ago) by sh002i
File size: 7262 byte(s)
small amount of cleanup (to prepare for cookie patch)

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork-modperl/lib/WeBWorK/Authen.pm,v 1.20 2003/12/09 01:12:30 sh002i Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 package WeBWorK::Authen;
   18 
   19 =head1 NAME
   20 
   21 WeBWorK::Authen - Check user identity, manage session keys.
   22 
   23 =cut
   24 
   25 use strict;
   26 use warnings;
   27 
   28 sub new($$$) {
   29   my $invocant = shift;
   30   my $class = ref($invocant) || $invocant;
   31   my $self = {};
   32   ($self->{r}, $self->{ce}, $self->{db}) = @_;
   33   bless $self, $class;
   34   return $self;
   35 }
   36 
   37 sub checkPassword($$$) {
   38   my ($self, $userID, $possibleClearPassword) = @_;
   39   my $Password = $self->{db}->getPassword($userID); # checked
   40   return 0 unless defined $Password;
   41   my $possibleCryptPassword = crypt($possibleClearPassword, $Password->password());
   42   return $possibleCryptPassword eq $Password->password();
   43 }
   44 
   45 sub generateKey($$) {
   46   my ($self, $userID) = @_;
   47   my @chars = @{ $self->{ce}->{sessionKeyChars} };
   48   my $length = $self->{ce}->{sessionKeyLength};
   49   srand;
   50   my $key = join ("", @chars[map rand(@chars), 1 .. $length]);
   51   return WeBWorK::DB::Record::Key->new(user_id=>$userID, key=>$key, timestamp=>time);
   52 }
   53 
   54 sub checkKey($$$) {
   55   my ($self, $userID, $possibleKey) = @_;
   56   my $Key = $self->{db}->getKey($userID); # checked
   57   return 0 unless defined $Key;
   58   if (time <= $Key->timestamp()+$self->{ce}->{sessionKeyTimeout}) {
   59     if ($possibleKey eq $Key->key()) {
   60       # unexpired and matches -- update timestamp
   61       $Key->timestamp(time);
   62       $self->{db}->putKey($Key);
   63       return 1;
   64     } else {
   65       # unexpired but doesn't match -- leave timestamp alone
   66       # we do this to keep an attacker from keeping someone's session
   67       # alive. (yeah, we don't match IPs.)
   68       return 0;
   69     }
   70   } else {
   71     # expired -- delete key
   72     $self->{db}->deleteKey($userID);
   73     return 0;
   74   }
   75 }
   76 
   77 sub unexpiredKeyExists($$) {
   78   my ($self, $userID) = @_;
   79   my $Key = $self->{db}->getKey($userID); # checked
   80   return 0 unless defined $Key;
   81   if (time <= $Key->timestamp()+$self->{ce}->{sessionKeyTimeout}) {
   82     # unexpired, but leave timestamp alone
   83     return 1;
   84   } else {
   85     # expired -- delete key
   86     $self->{db}->deleteKey($userID);
   87     return 0;
   88   }
   89 }
   90 
   91 # verify will return 1 if the person is who they say the are. If the
   92 # verification failed because of of invalid authentication data, a note will be
   93 # written in the request explaining why it failed. If the request failed because
   94 # no authentication data was provided, however, no note will be written, as this
   95 # is expected to happen whenever someone types in a URL manually, and is not
   96 # considered an error condition.
   97 sub verify($) {
   98   my $self = shift;
   99   my $r = $self->{r};
  100   my $ce = $self->{ce};
  101   my $db = $self->{db};
  102 
  103   my $practiceUserPrefix = $ce->{practiceUserPrefix};
  104   my $debugPracticeUser = $ce->{debugPracticeUser};
  105 
  106   my $user = $r->param('user');
  107   my $passwd = $r->param('passwd');
  108   my $key = $r->param('key');
  109   my $force_passwd_authen = $r->param('force_passwd_authen');
  110 
  111   my $error;
  112   my $failWithoutError = 0;
  113 
  114   VERIFY: {
  115     # This block is here so we can "last" out of it when we've
  116     # decided whether we're going to succeed or fail.
  117 
  118     # no authentication data was given. this is OK.
  119     unless (defined $user or defined $passwd or defined $key) {
  120       $failWithoutError = 1;
  121       last VERIFY;
  122     }
  123 
  124     if (defined $user and $force_passwd_authen) {
  125       $failWithoutError = 1;
  126       last VERIFY;
  127     }
  128 
  129     # no user was supplied.  somebody's building their own GET
  130     unless ($user) {
  131       $error = "You must specify a username.";
  132       last VERIFY;
  133     }
  134 
  135     # it's a practice user.
  136     if ($practiceUserPrefix and $user =~ /^$practiceUserPrefix/) {
  137       # we're not interested in a practice user's password
  138       $r->param("passwd", "");
  139 
  140       # it's a practice user that doesn't exist.
  141       unless (defined $db->getUser($user)) { # checked
  142         $error = "That practice account does not exist.";
  143         last VERIFY;
  144       }
  145 
  146       # we've got a key.
  147       if ($key) {
  148         if ($self->checkKey($user, $key)) {
  149           # they key was valid.
  150           last VERIFY;
  151         } else {
  152           # the key was invalid.
  153           $error = "Your session has timed out due to inactivity. You must login again.";
  154           last VERIFY;
  155         }
  156       }
  157 
  158       # -- here we know that a key was not supplied. --
  159 
  160       # it's the debug user.
  161       if ($debugPracticeUser and $user eq $debugPracticeUser) {
  162         # clobber any existing session, valid or not.
  163         my $Key = $self->generateKey($user);
  164         eval { $db->deleteKey($user) };
  165         $db->addKey($Key);
  166         $r->param("key", $Key->key());
  167         last VERIFY;
  168       }
  169 
  170       # an unexpired key exists -- the account is in use.
  171       if ($self->unexpiredKeyExists($user)) {
  172         $error = "That practice account is in use.";
  173         last VERIFY;
  174       }
  175 
  176       # here we know the account is not in use, so we
  177       # generate a new  session key (unexpiredKeyExists
  178       # deleted any expired key) and succeed!
  179       my $Key = $self->generateKey($user);
  180       $db->addKey($Key);
  181       $r->param("key", $Key->key());
  182       last VERIFY;
  183     }
  184 
  185     # -- here we know it's a regular user. --
  186 
  187     # a key was supplied.
  188     if ($key) {
  189       # we're not interested in a user's password if they're
  190       # supplying a key
  191       $r->param("passwd", "");
  192 
  193       if ($self->checkKey($user, $key)) {
  194         # valid key, so succeed.
  195         last VERIFY;
  196       } else {
  197         # invalid key. the login page doesn't propogate the key,
  198         # so we know this is an expired session.
  199         $error = "Your session has timed out due to inactivity. You must login again.";
  200         last VERIFY;
  201       }
  202     }
  203 
  204     # a password was supplied.
  205     if ($passwd) {
  206       if ($self->checkPassword($user, $passwd)) {
  207         # valid password, so create a new session. (we don't want
  208         # to reuse an old one, duh.)
  209         my $Key = $self->generateKey($user);
  210         eval { $db->deleteKey($user) };
  211         $db->addKey($Key);
  212         $r->param("key", $Key->key());
  213         # also delete the password
  214         $r->param("passwd", "");
  215         last VERIFY;
  216       } else {
  217         # incorrect password. fail.
  218         $error = "Incorrect username or password.";
  219         last VERIFY;
  220       }
  221     }
  222 
  223     # neither a key or a password were supplied.
  224     $error = "You must enter a password."
  225   }
  226 
  227   if (defined $error) {
  228     # authentication failed, in a bad way
  229     $r->notes("authen_error",$error);
  230     return 0;
  231   } elsif ($failWithoutError) {
  232     # authentication failed, but not in a bad way
  233     return 0;
  234   } else {
  235     # autentication succeeded!
  236     return 1;
  237   }
  238 
  239   # Whatever you do, don't delete this!
  240   critical($r);
  241 }
  242 
  243 1;
  244 
  245 __END__
  246 
  247 =head1 AUTHOR
  248 
  249 Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu, and Sam
  250 Hathaway, sh002i (at) math.rochester.edu.
  251 
  252 =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9