[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 825 - (download) (as text) (annotate)
Mon May 12 23:49:50 2003 UTC (10 years ago) by malsyned
File size: 6590 byte(s)
Fixed BUG #16:
"Logging out from a practice user and logging back in doesn't work
right"
http://webwork3/bugzilla/show_bug.cgi?id=16
--Dennis

    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   my $force_passwd_authen = $r->param('force_passwd_authen');
  107 
  108   my $error;
  109   my $failWithoutError = 0;
  110 
  111   VERIFY: {
  112     # This block is here so we can "last" out of it when we've
  113     # decided whether we're going to succeed or fail.
  114 
  115     # no authentication data was given. this is OK.
  116     unless (defined $user or defined $passwd or defined $key) {
  117       $failWithoutError = 1;
  118       last VERIFY;
  119     }
  120 
  121     if (defined $user and $force_passwd_authen) {
  122       $failWithoutError = 1;
  123       last VERIFY;
  124     }
  125 
  126     # no user was supplied.  somebody's building their own GET
  127     unless ($user) {
  128       $error = "You must specify a username.";
  129       last VERIFY;
  130     }
  131 
  132     # it's a practice user.
  133     if ($practiceUserPrefix and $user =~ /^$practiceUserPrefix/) {
  134       # we're not interested in a practice user's password
  135       $r->param("passwd", "");
  136 
  137       # it's a practice user that doesn't exist.
  138       unless ($db->getUser($user)) {
  139         $error = "That practice account does not exist.";
  140         last VERIFY;
  141       }
  142 
  143       # we've got a key.
  144       if ($key) {
  145         if ($self->checkKey($user, $key)) {
  146           # they key was valid.
  147           last VERIFY;
  148         } else {
  149           # the key was invalid.
  150           $error = "Your session has expired. You must login again.";
  151           last VERIFY;
  152         }
  153       }
  154 
  155       # -- here we know that a key was not supplied. --
  156 
  157       # it's the debug user.
  158       if ($debugPracticeUser and $user eq $debugPracticeUser) {
  159         # clobber any existing session, valid or not.
  160         my $Key = $self->generateKey($user);
  161         $db->deleteKey($user);
  162         $db->addKey($Key);
  163         $r->param("key", $Key->key());
  164         last VERIFY;
  165       }
  166 
  167       # an unexpired key exists -- the account is in use.
  168       if ($self->unexpiredKeyExists($user)) {
  169         $error = "That practice account is in use.";
  170         last VERIFY;
  171       }
  172 
  173       # here we know the account is not in use, so we
  174       # generate a new  session key (unexpiredKeyExists
  175       # deleted any expired key) and succeed!
  176       my $Key = $self->generateKey($user);
  177       $db->addKey($Key);
  178       $r->param("key", $Key->key());
  179       last VERIFY;
  180     }
  181 
  182     # -- here we know it's a regular user. --
  183 
  184     # a key was supplied.
  185     if ($key) {
  186       # we're not interested in a user's password if they're
  187       # supplying a key
  188       $r->param("passwd", "");
  189 
  190       if ($self->checkKey($user, $key)) {
  191         # valid key, so succeed.
  192         last VERIFY;
  193       } else {
  194         # invalid key. the login page doesn't propogate the key,
  195         # so we know this is an expired session.
  196         $error = "Your session has expired. You must login again.";
  197         last VERIFY;
  198       }
  199     }
  200 
  201     # a password was supplied.
  202     if ($passwd) {
  203       if ($self->checkPassword($user, $passwd)) {
  204         # valid password, so create a new session. (we don't want
  205         # to reuse an old one, duh.)
  206         my $Key = $self->generateKey($user);
  207         $db->deleteKey($user);
  208         $db->addKey($Key);
  209         $r->param("key", $Key->key());
  210         # also delete the password
  211         $r->param("passwd", "");
  212         last VERIFY;
  213       } else {
  214         # incorrect password. fail.
  215         $error = "Incorrect username or password.";
  216         last VERIFY;
  217       }
  218     }
  219 
  220     # neither a key or a password were supplied.
  221     $error = "You must enter a password."
  222   }
  223 
  224   if (defined $error) {
  225     $r->notes("authen_error",$error);
  226     return 0;
  227   } else {
  228     return not $failWithoutError;
  229   }
  230 
  231   # Whatever you do, don't delete this!
  232   critical($r);
  233 }
  234 
  235 1;
  236 
  237 __END__
  238 
  239 =head1 AUTHOR
  240 
  241 Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu, and Sam Hathaway, sh002i (at) math.rochester.edu.
  242 
  243 =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9