Parent Directory
|
Revision Log
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 |