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