[system] / trunk / webwork2 / lib / WeBWorK / Authen.pm Repository:
ViewVC logotype

Annotation of /trunk/webwork2/lib/WeBWorK/Authen.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1682 - (view) (download) (as text)

1 : sh002i 455 ################################################################################
2 : sh002i 1663 # WeBWorK Online Homework Delivery System
3 :     # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4 : sh002i 1682 # $CVSHeader: webwork-modperl/lib/WeBWorK/Authen.pm,v 1.20 2003/12/09 01:12:30 sh002i Exp $
5 : sh002i 1663 #
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 : sh002i 455 ################################################################################
16 :    
17 : malsyned 305 package WeBWorK::Authen;
18 :    
19 : sh002i 455 =head1 NAME
20 :    
21 :     WeBWorK::Authen - Check user identity, manage session keys.
22 :    
23 :     =cut
24 :    
25 : malsyned 441 use strict;
26 :     use warnings;
27 : malsyned 335
28 : malsyned 305 sub new($$$) {
29 : malsyned 323 my $invocant = shift;
30 :     my $class = ref($invocant) || $invocant;
31 : malsyned 305 my $self = {};
32 : sh002i 817 ($self->{r}, $self->{ce}, $self->{db}) = @_;
33 : malsyned 305 bless $self, $class;
34 :     return $self;
35 :     }
36 :    
37 : sh002i 817 sub checkPassword($$$) {
38 :     my ($self, $userID, $possibleClearPassword) = @_;
39 : sh002i 1636 my $Password = $self->{db}->getPassword($userID); # checked
40 :     return 0 unless defined $Password;
41 : sh002i 817 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 : malsyned 323 srand;
50 : sh002i 817 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 : sh002i 1636 my $Key = $self->{db}->getKey($userID); # checked
57 :     return 0 unless defined $Key;
58 : sh002i 817 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 : malsyned 323 }
75 :     }
76 :    
77 : sh002i 817 sub unexpiredKeyExists($$) {
78 :     my ($self, $userID) = @_;
79 : sh002i 1636 my $Key = $self->{db}->getKey($userID); # checked
80 :     return 0 unless defined $Key;
81 : sh002i 817 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 : sh002i 1682 # 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 : malsyned 305 sub verify($) {
98 :     my $self = shift;
99 :     my $r = $self->{r};
100 : sh002i 817 my $ce = $self->{ce};
101 :     my $db = $self->{db};
102 : malsyned 305
103 : sh002i 817 my $practiceUserPrefix = $ce->{practiceUserPrefix};
104 :     my $debugPracticeUser = $ce->{debugPracticeUser};
105 :    
106 : malsyned 313 my $user = $r->param('user');
107 :     my $passwd = $r->param('passwd');
108 :     my $key = $r->param('key');
109 : malsyned 825 my $force_passwd_authen = $r->param('force_passwd_authen');
110 : malsyned 313
111 : malsyned 441 my $error;
112 : sh002i 817 my $failWithoutError = 0;
113 : malsyned 313
114 : sh002i 817 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 : malsyned 825 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 : sh002i 817 unless ($user) {
131 :     $error = "You must specify a username.";
132 :     last VERIFY;
133 :     }
134 :    
135 :     # it's a practice user.
136 : malsyned 349 if ($practiceUserPrefix and $user =~ /^$practiceUserPrefix/) {
137 : sh002i 817 # 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 : sh002i 1636 unless (defined $db->getUser($user)) { # checked
142 : sh002i 817 $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 : malsyned 827 $error = "Your session has timed out due to inactivity. You must login again.";
154 : sh002i 817 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 : sh002i 912 eval { $db->deleteKey($user) };
165 : sh002i 817 $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 : malsyned 349 } else {
197 : sh002i 817 # invalid key. the login page doesn't propogate the key,
198 :     # so we know this is an expired session.
199 : malsyned 827 $error = "Your session has timed out due to inactivity. You must login again.";
200 : sh002i 817 last VERIFY;
201 : malsyned 349 }
202 :     }
203 : sh002i 817
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 : sh002i 912 eval { $db->deleteKey($user) };
211 : sh002i 817 $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 : malsyned 313 }
222 : sh002i 817
223 :     # neither a key or a password were supplied.
224 :     $error = "You must enter a password."
225 :     }
226 :    
227 :     if (defined $error) {
228 : sh002i 1682 # authentication failed, in a bad way
229 : sh002i 817 $r->notes("authen_error",$error);
230 :     return 0;
231 : sh002i 1682 } elsif ($failWithoutError) {
232 :     # authentication failed, but not in a bad way
233 :     return 0;
234 : malsyned 313 } else {
235 : sh002i 1682 # autentication succeeded!
236 :     return 1;
237 : malsyned 305 }
238 : malsyned 313
239 :     # Whatever you do, don't delete this!
240 :     critical($r);
241 : malsyned 305 }
242 :    
243 :     1;
244 : malsyned 522
245 :     __END__
246 :    
247 :     =head1 AUTHOR
248 :    
249 : sh002i 1682 Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu, and Sam
250 :     Hathaway, sh002i (at) math.rochester.edu.
251 : malsyned 522
252 :     =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9