[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 817 - (download) (as text) (annotate)
Wed Apr 23 06:39:03 2003 UTC (10 years, 2 months ago) by sh002i
File size: 6397 byte(s)
rewrote these modules to use the WWDBv2 library. rewrote the Authen.pm
verify function to (hopefully) be more readable.
-sam

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9