[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 827 - (view) (download) (as text)

1 : sh002i 455 ################################################################################
2 : sh002i 494 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
3 : sh002i 455 # $Id$
4 :     ################################################################################
5 :    
6 : malsyned 305 package WeBWorK::Authen;
7 :    
8 : sh002i 455 =head1 NAME
9 :    
10 :     WeBWorK::Authen - Check user identity, manage session keys.
11 :    
12 :     =cut
13 :    
14 : malsyned 441 use strict;
15 :     use warnings;
16 : malsyned 335
17 : malsyned 305 sub new($$$) {
18 : malsyned 323 my $invocant = shift;
19 :     my $class = ref($invocant) || $invocant;
20 : malsyned 305 my $self = {};
21 : sh002i 817 ($self->{r}, $self->{ce}, $self->{db}) = @_;
22 : malsyned 305 bless $self, $class;
23 :     return $self;
24 :     }
25 :    
26 : sh002i 817 # 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 : malsyned 343
34 : sh002i 817 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 : malsyned 323 srand;
47 : sh002i 817 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 : malsyned 323 }
72 :     }
73 :    
74 : sh002i 817 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 : malsyned 313 # 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 : malsyned 305 sub verify($) {
95 :     my $self = shift;
96 :     my $r = $self->{r};
97 : sh002i 817 my $ce = $self->{ce};
98 :     my $db = $self->{db};
99 : malsyned 305
100 : sh002i 817 my $practiceUserPrefix = $ce->{practiceUserPrefix};
101 :     my $debugPracticeUser = $ce->{debugPracticeUser};
102 :    
103 : malsyned 313 my $user = $r->param('user');
104 :     my $passwd = $r->param('passwd');
105 :     my $key = $r->param('key');
106 : malsyned 825 my $force_passwd_authen = $r->param('force_passwd_authen');
107 : malsyned 313
108 : malsyned 441 my $error;
109 : sh002i 817 my $failWithoutError = 0;
110 : malsyned 313
111 : sh002i 817 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 : malsyned 825 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 : sh002i 817 unless ($user) {
128 :     $error = "You must specify a username.";
129 :     last VERIFY;
130 :     }
131 :    
132 :     # it's a practice user.
133 : malsyned 349 if ($practiceUserPrefix and $user =~ /^$practiceUserPrefix/) {
134 : sh002i 817 # 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 : malsyned 827 $error = "Your session has timed out due to inactivity. You must login again.";
151 : sh002i 817 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 : malsyned 349 } else {
194 : sh002i 817 # invalid key. the login page doesn't propogate the key,
195 :     # so we know this is an expired session.
196 : malsyned 827 $error = "Your session has timed out due to inactivity. You must login again.";
197 : sh002i 817 last VERIFY;
198 : malsyned 349 }
199 :     }
200 : sh002i 817
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 : malsyned 313 }
219 : sh002i 817
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 : malsyned 313 } else {
228 : sh002i 817 return not $failWithoutError;
229 : malsyned 305 }
230 : malsyned 313
231 :     # Whatever you do, don't delete this!
232 :     critical($r);
233 : malsyned 305 }
234 :    
235 :     1;
236 : malsyned 522
237 :     __END__
238 :    
239 :     =head1 AUTHOR
240 :    
241 : sh002i 817 Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu, and Sam Hathaway, sh002i (at) math.rochester.edu.
242 : malsyned 522
243 :     =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9