Parent Directory
|
Revision Log
Revision 51 - (view) (download) (as text)
| 1 : | sam | 10 | #!/usr/local/bin/perl |
| 2 : | sam | 2 | |
| 3 : | sam | 51 | ################################################################################ |
| 4 : | # WeBWorK | ||
| 5 : | # | ||
| 6 : | # Copyright (c) 1995-2001 University of Rochester | ||
| 7 : | # All rights reserved | ||
| 8 : | # | ||
| 9 : | # $Id$ | ||
| 10 : | ################################################################################ | ||
| 11 : | |||
| 12 : | sam | 2 | package Auth; |
| 13 : | |||
| 14 : | require 5.000; | ||
| 15 : | require Exporter; | ||
| 16 : | @ISA = qw(Exporter); | ||
| 17 : | @EXPORT = qw( | ||
| 18 : | verify_password | ||
| 19 : | new_password | ||
| 20 : | change_user_in_password_file | ||
| 21 : | get_password | ||
| 22 : | delete_password | ||
| 23 : | verify_key | ||
| 24 : | new_key | ||
| 25 : | delete_key | ||
| 26 : | get_permissions | ||
| 27 : | put_permissions | ||
| 28 : | change_user_in_permissions_file | ||
| 29 : | delete_permissions | ||
| 30 : | create_db | ||
| 31 : | get_keys_from_db | ||
| 32 : | get_hash_from_db | ||
| 33 : | get_active_users_from_keysDB | ||
| 34 : | get_current_users_from_passwordDB | ||
| 35 : | ); | ||
| 36 : | |||
| 37 : | use Global; | ||
| 38 : | |||
| 39 : | my $Timeout = 3600; # key expires after 3600 seconds (60min) | ||
| 40 : | my $Key_length = 40; # number of chars in each key | ||
| 41 : | |||
| 42 : | my @Key_chars = ('A'..'Z', 'a'..'z', '0'..'9', '.', '^', '/', '!', '*'); | ||
| 43 : | my @Salt_chars = ('.', '/', 'A'..'Z', 'a'..'z', '0'..'9'); | ||
| 44 : | |||
| 45 : | my $cgiURL = &Global::getWebworkCgiURL(); | ||
| 46 : | |||
| 47 : | ####### public routines (exported into Global's namespace) ###### | ||
| 48 : | |||
| 49 : | sub get_password { | ||
| 50 : | my ($user, $pw_file) = @_; | ||
| 51 : | my %pwhash; | ||
| 52 : | my $pw_obj; | ||
| 53 : | |||
| 54 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file,'R',$Global::standard_tie_permission); | ||
| 55 : | $return_pw = $pwhash{$user}; | ||
| 56 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file); | ||
| 57 : | return($return_pw); | ||
| 58 : | } | ||
| 59 : | |||
| 60 : | sub verify_password { | ||
| 61 : | my($user, $pw_to_check, $pw_file) = @_; | ||
| 62 : | my %pwhash; | ||
| 63 : | my $pw_obj; | ||
| 64 : | |||
| 65 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file,'R',$Global::standard_tie_permission); | ||
| 66 : | my $pw = $pwhash{$user}; | ||
| 67 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file); | ||
| 68 : | |||
| 69 : | ## practice user needs no password, but must have password entry at least | ||
| 70 : | return 1 if ($pw && $user =~ /^$Global::practiceUser/); | ||
| 71 : | |||
| 72 : | my $salt = substr($pw, 0, 2); | ||
| 73 : | |||
| 74 : | ## There's a problem if password entry doesn't exist for user | ||
| 75 : | ## or passwords don't match | ||
| 76 : | |||
| 77 : | return 0 if (!$pw) || (crypt($pw_to_check, $salt) ne $pw); | ||
| 78 : | |||
| 79 : | ## otherwise the password's good | ||
| 80 : | return 1; | ||
| 81 : | } | ||
| 82 : | |||
| 83 : | sub new_password { | ||
| 84 : | my($user, $new_pw, $pw_file) = @_; | ||
| 85 : | my %pwhash; | ||
| 86 : | my $pw_obj; | ||
| 87 : | |||
| 88 : | $encrypted_pw = crypt($new_pw, &new_salt); | ||
| 89 : | |||
| 90 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file,'W',$Global::standard_tie_permission); | ||
| 91 : | $pwhash{$user} = $encrypted_pw; | ||
| 92 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file); | ||
| 93 : | return 1; | ||
| 94 : | } | ||
| 95 : | |||
| 96 : | |||
| 97 : | sub change_user_in_password_file{ | ||
| 98 : | my($new_user, $old_user, $pw_file) = @_; | ||
| 99 : | my %pwhash; | ||
| 100 : | my $pw_obj; | ||
| 101 : | |||
| 102 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file,'W',$Global::standard_tie_permission); | ||
| 103 : | if (defined $pwhash{$old_user}) { | ||
| 104 : | $pwhash{$new_user} = $pwhash{$old_user}; | ||
| 105 : | delete $pwhash{$old_user}; | ||
| 106 : | } | ||
| 107 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file); | ||
| 108 : | return 1; | ||
| 109 : | } | ||
| 110 : | |||
| 111 : | |||
| 112 : | |||
| 113 : | sub delete_password { | ||
| 114 : | my($user, $pw_file) = @_; | ||
| 115 : | my %pwhash; | ||
| 116 : | my $pw_obj; | ||
| 117 : | |||
| 118 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file,'W',$Global::standard_tie_permission); | ||
| 119 : | delete $pwhash{$user}; | ||
| 120 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file); | ||
| 121 : | return 1; | ||
| 122 : | } | ||
| 123 : | |||
| 124 : | |||
| 125 : | sub verify_key { | ||
| 126 : | my($user, $key_to_check, $key_file, $course, $rh_inputs) = @_; | ||
| 127 : | ## Don't check the session key for a "practice" user | ||
| 128 : | ## return 1 if ($user =~ /^$Global::practiceUser/); | ||
| 129 : | |||
| 130 : | ## check to see if $key_to_check matches $key in $key_file. | ||
| 131 : | |||
| 132 : | my($key, $timestamp, $elapsed_time, $tries); | ||
| 133 : | my %keyhash; | ||
| 134 : | my $key_obj; | ||
| 135 : | |||
| 136 : | &Global::tie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file,'W',$Global::restricted_tie_permission); | ||
| 137 : | ($key, $timestamp) = split(/\s+/, $keyhash{$user}); | ||
| 138 : | $elapsed_time = time - $timestamp; | ||
| 139 : | |||
| 140 : | if ((!$key) ## no key in database for user? | ||
| 141 : | || ($key_to_check ne $key) ## key_to_check doesn't match real key? | ||
| 142 : | || ($elapsed_time > $Timeout)) ## key is too old? | ||
| 143 : | { | ||
| 144 : | &Global::untie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file); | ||
| 145 : | # send user back to login script | ||
| 146 : | &login_again_form($course,$rh_inputs); | ||
| 147 : | exit 0; | ||
| 148 : | } | ||
| 149 : | |||
| 150 : | ## key is valid: update timestamp | ||
| 151 : | |||
| 152 : | $timestamp = time; | ||
| 153 : | $keyhash{$user} = "$key $timestamp"; | ||
| 154 : | |||
| 155 : | &Global::untie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file); | ||
| 156 : | return 1; | ||
| 157 : | } | ||
| 158 : | |||
| 159 : | sub new_key { | ||
| 160 : | local($user, $key_file) = @_; | ||
| 161 : | ## Don't generate a key for a "practice" user | ||
| 162 : | ##return $Global::practiceKey if $user eq $Global::practiceUser; | ||
| 163 : | |||
| 164 : | ## create a new key for $user in $key_file | ||
| 165 : | |||
| 166 : | my($i, $key, $timestamp); | ||
| 167 : | my %keyhash; | ||
| 168 : | my $key_obj; | ||
| 169 : | |||
| 170 : | &Global::tie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file,'W',$Global::restricted_tie_permission); | ||
| 171 : | |||
| 172 : | ## generate key | ||
| 173 : | $key = &generate_key; | ||
| 174 : | |||
| 175 : | $timestamp = time; | ||
| 176 : | $keyhash{$user} = "$key $timestamp"; | ||
| 177 : | &Global::untie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file); | ||
| 178 : | return($key); | ||
| 179 : | } | ||
| 180 : | |||
| 181 : | sub delete_key { | ||
| 182 : | my($user, $key_file) = @_; | ||
| 183 : | my %keyhash; | ||
| 184 : | my $key_obj; | ||
| 185 : | |||
| 186 : | &Global::tie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file,'W',$Global::restricted_tie_permission); | ||
| 187 : | delete $keyhash{$user}; | ||
| 188 : | &Global::untie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file); | ||
| 189 : | return 1; | ||
| 190 : | } | ||
| 191 : | |||
| 192 : | |||
| 193 : | sub get_permissions { | ||
| 194 : | my ($user, $perm_file) = @_; | ||
| 195 : | my %permhash; | ||
| 196 : | my $perm_obj; | ||
| 197 : | |||
| 198 : | &Global::tie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file,'R',$Global::standard_tie_permission); | ||
| 199 : | $return_perm = $perm_hash{$user}; | ||
| 200 : | &Global::untie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file); | ||
| 201 : | return($return_perm); | ||
| 202 : | } | ||
| 203 : | |||
| 204 : | sub put_permissions { | ||
| 205 : | my( $new_perm, $user, $perm_file) = @_; | ||
| 206 : | my %perm_hash; | ||
| 207 : | my $perm_obj; | ||
| 208 : | |||
| 209 : | |||
| 210 : | &Global::tie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file,'W',$Global::standard_tie_permission); | ||
| 211 : | $perm_hash{$user} = $new_perm; | ||
| 212 : | &Global::untie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file); | ||
| 213 : | return 1; | ||
| 214 : | } | ||
| 215 : | |||
| 216 : | sub change_user_in_permissions_file{ | ||
| 217 : | my($new_user, $old_user, $perm_file) = @_; | ||
| 218 : | my %perm_hash; | ||
| 219 : | my $perm_obj; | ||
| 220 : | |||
| 221 : | &Global::tie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file,'W',$Global::standard_tie_permission); | ||
| 222 : | if (defined $perm_hash{$old_user}) { | ||
| 223 : | $perm_hash{$new_user} = $perm_hash{$old_user}; | ||
| 224 : | delete $perm_hash{$old_user}; | ||
| 225 : | } | ||
| 226 : | &Global::untie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file); | ||
| 227 : | return 1; | ||
| 228 : | } | ||
| 229 : | |||
| 230 : | |||
| 231 : | |||
| 232 : | sub delete_permissions { | ||
| 233 : | my($user, $perm_file) = @_; | ||
| 234 : | my %perm_hash; | ||
| 235 : | my $perm_obj; | ||
| 236 : | |||
| 237 : | &Global::tie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file,'W',$Global::standard_tie_permission); | ||
| 238 : | delete $perm_hash{$user}; | ||
| 239 : | &Global::untie_hash('PERM_FILE',\$perm_obj,\%perm_hash, $perm_file); | ||
| 240 : | return 1; | ||
| 241 : | } | ||
| 242 : | |||
| 243 : | sub create_db { | ||
| 244 : | my ($fileName, $permissions) =@_; | ||
| 245 : | my %pwhash; | ||
| 246 : | my $pw_obj; | ||
| 247 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $fileName,'W',$permissions); | ||
| 248 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $fileName); | ||
| 249 : | |||
| 250 : | chmod($permissions, $fileName) or | ||
| 251 : | wwerror($0, "Can't do chmod($permissions, $fileName)"); | ||
| 252 : | chown(-1,$Global::numericalGroupID,$fileName) or | ||
| 253 : | wwerror($0, "Can't do chown(-1,$Global::numericalGroupID,$fileName)"); | ||
| 254 : | |||
| 255 : | } | ||
| 256 : | |||
| 257 : | sub get_keys_from_db { | ||
| 258 : | my ($fileName) =@_; | ||
| 259 : | my %pwhash; | ||
| 260 : | my $pw_obj; | ||
| 261 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $fileName,'R',$Global::standard_tie_permission); | ||
| 262 : | my @keysArray = keys(%pwhash); | ||
| 263 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $fileName); | ||
| 264 : | @keysArray; | ||
| 265 : | } | ||
| 266 : | |||
| 267 : | sub get_hash_from_db { | ||
| 268 : | my ($fileName) =@_; | ||
| 269 : | my %dbhash; | ||
| 270 : | my $db_obj; | ||
| 271 : | &Global::tie_hash('PW_FH',\$db_obj,\%dbhash, $fileName,'R',$Global::standard_tie_permission); | ||
| 272 : | my %outhash = %dbhash; | ||
| 273 : | &Global::untie_hash('PW_FH',\$db_obj,\%dbhash, $fileName); | ||
| 274 : | %outhash; | ||
| 275 : | } | ||
| 276 : | |||
| 277 : | |||
| 278 : | sub get_active_users_from_keysDB { | ||
| 279 : | my($key_file) = @_; | ||
| 280 : | |||
| 281 : | ## check to see if $key_to_check matches $key in $key_file. | ||
| 282 : | |||
| 283 : | my($user, $key, $timestamp, $elapsed_time, $tries); | ||
| 284 : | my %keyhash; | ||
| 285 : | my $key_obj; | ||
| 286 : | my @activelist =(); | ||
| 287 : | |||
| 288 : | &Global::tie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file,'R',$Global::restricted_tie_permission); | ||
| 289 : | |||
| 290 : | foreach $user (keys %keyhash) { | ||
| 291 : | ($key, $timestamp) = split(/\s+/, $keyhash{$user}); | ||
| 292 : | $elapsed_time = time - $timestamp; | ||
| 293 : | if ( $elapsed_time < $Timeout) { push @activelist, $user;} | ||
| 294 : | } | ||
| 295 : | &Global::untie_hash('KEY_FH',\$key_obj,\%keyhash, $key_file); | ||
| 296 : | @activelist; | ||
| 297 : | } | ||
| 298 : | |||
| 299 : | sub get_current_users_from_passwordDB { | ||
| 300 : | my ($pw_file) = @_; | ||
| 301 : | my %pwhash; | ||
| 302 : | my $pw_obj; | ||
| 303 : | my $user; | ||
| 304 : | my @currentlist =(); | ||
| 305 : | |||
| 306 : | &Global::tie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file,'R',$Global::standard_tie_permission); | ||
| 307 : | foreach $user (keys %pwhash) {push @currentlist, $user;} | ||
| 308 : | &Global::untie_hash('PW_FH',\$pw_obj,\%pwhash, $pw_file); | ||
| 309 : | @currentlist; | ||
| 310 : | } | ||
| 311 : | |||
| 312 : | |||
| 313 : | |||
| 314 : | |||
| 315 : | |||
| 316 : | ####### private routines ####### | ||
| 317 : | |||
| 318 : | sub new_salt {srand; $Salt_chars[rand(@Salt_chars)] . $Salt_chars[rand(@Salt_chars)]}; | ||
| 319 : | |||
| 320 : | sub generate_key { | ||
| 321 : | my $i = $Key_length; | ||
| 322 : | my $key = ''; | ||
| 323 : | srand; | ||
| 324 : | while($i) { | ||
| 325 : | $key .= $Key_chars[rand(@Key_chars)]; | ||
| 326 : | $i--; | ||
| 327 : | } | ||
| 328 : | return $key; | ||
| 329 : | } | ||
| 330 : | |||
| 331 : | |||
| 332 : | |||
| 333 : | |||
| 334 : | |||
| 335 : | sub login_again_form { | ||
| 336 : | my $course = shift; | ||
| 337 : | my $rh_inputs =shift; | ||
| 338 : | my %inputs; # try to find information for fast relogin | ||
| 339 : | if ( defined($rh_inputs) ) { | ||
| 340 : | %inputs = %{$rh_inputs}; | ||
| 341 : | } elsif (defined(%main::in)) { | ||
| 342 : | %inputs = %main::in; | ||
| 343 : | } else { | ||
| 344 : | %inputs = (); | ||
| 345 : | } | ||
| 346 : | print <<End_Of_Form; | ||
| 347 : | content-type: text/html | ||
| 348 : | |||
| 349 : | <HEAD><TITLE></TITLE></HEAD> | ||
| 350 : | <BODY BACKGROUND="$Global::background_warn_url"> | ||
| 351 : | <H1>Not Logged In</H1> | ||
| 352 : | Sorry, you have been logged out, probably due to excessive idle time.<br> | ||
| 353 : | To continue you will have to log in again. | ||
| 354 : | <FORM ACTION="$Global::loginURL"> | ||
| 355 : | <INPUT TYPE="HIDDEN" NAME="course" VALUE="$course"> | ||
| 356 : | <INPUT TYPE="SUBMIT" VALUE="Login"> | ||
| 357 : | </FORM> | ||
| 358 : | |||
| 359 : | |||
| 360 : | End_Of_Form | ||
| 361 : | |||
| 362 : | print <<End_Of_Text; | ||
| 363 : | <HR><H2> Fast relogin for $inputs{'user'}</H2> | ||
| 364 : | Type your password and click "Go". You will be returned to where you were in your problem set. | ||
| 365 : | <FORM ACTION="${cgiURL}login.pl" METHOD="POST"> | ||
| 366 : | End_Of_Text | ||
| 367 : | # print a fast login form. Copy all of the hidden variable except for the one named 'key' | ||
| 368 : | my $tmp_key; | ||
| 369 : | foreach $tmp_key (keys %inputs) { | ||
| 370 : | next if $tmp_key eq 'key'; | ||
| 371 : | print qq!<INPUT TYPE="HIDDEN" NAME="$tmp_key" VALUE ="$inputs{$tmp_key}">\n!; | ||
| 372 : | } | ||
| 373 : | print qq!<INPUT TYPE="HIDDEN" NAME="SCRIPTING_FILE" VALUE="$ENV{'SCRIPT_NAME'}">\n!; | ||
| 374 : | print qq!Password:<INPUT TYPE=PASSWORD NAME="passwd" VALUE = "">\n!; | ||
| 375 : | print "<INPUT TYPE=SUBMIT NAME=\"GO\" VALUE=\"GO\">\n</FORM>"; | ||
| 376 : | print "\n</BODY>"; | ||
| 377 : | } | ||
| 378 : | |||
| 379 : |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |