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