[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 1663 - (download) (as text) (annotate)
Tue Dec 9 01:12:32 2003 UTC (9 years, 5 months ago) by sh002i
File size: 7377 byte(s)
Normalized headers. All files now contain the text below as a header.
This is important since all files now (a) use the full name of the
package, (b) assign copyright to "The WeBWorK Project", (c) give the
full path of the file (relative to CVSROOT) instead of simply the file
name, and (d) include license and warranty information.

Here is the new header:

################################################################################
# WeBWorK Online Homework Delivery System
# Copyright © 2000-2003 The WeBWorK Projcct, http://openwebwork.sf.net/
# $CVSHeader$
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of either: (a) the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version, or (b) the "Artistic License" which comes with this package.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
# Artistic License for more details.
################################################################################

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9