6.4.2 Doing your own authentication (Cont.) - Page 8
July 3, 2002
Having stored the form, the application can now print it:
# If no username then just display the form.
unless ($username) {
my $title = $ENV{'HTTPS'} ?
'Secure login form' : 'Insecure login form';
$r->send_http_header('text/html');
print <<ENDHTML;
<!DOCTYPE HTML PUBLIC>
<HTML>
<HEAD><TITLE>$title</TITLE></HEAD>
<BODY>
<H1>Enter your username and password</H1>
$loginForm
To create an account, go <A HREF="/create">here</A>.
</BODY>
</HTML>
ENDHTML
return OK;
}
If the username isn't passed in, the application assumes that the user hasn't yet seen
the login form. It prints it, then returns OK to Apache.
Note that the title of the page depends on whether or not the user is logging in over
a secure connection. Of course, a more security-minded application might want to
redirect users logging in without SSL to another page, or offer a stronger warning. The
title is interpolated into the string via the here-doc syntax again, as is the entire login
form. The application also offers a link to the page for creating an account (which we'll
get to later in the chapter).
If we did get parameters, we check for the user and password in the database:
# Check the username and password.
if (defined($username) && defined($password)) {
my $dbh = DBI->connect('DBI:mysql:Info:localhost',
'web','nouser');
return error($r, "Can't connect to Info") unless $dbh;
my ($try) = $dbh->selectrow_array
('SELECT password FROM Users WHERE username = ?',
undef, $username);
if ($try && $try eq crypt($password,$try)) {
$r->send_http_header('text/html');
print <<ENDHTML;
<!DOCTYPE HTML PUBLIC>
<HTML>
<HEAD><TITLE>Hello $username</TITLE></HEAD>
<BODY>
Login successful. Please proceed.
</BODY>
</HTML>
ENDHTML
return OK;
}
}
After getting the parameters and checking that we got some kind of value for each, the
code connects to the database as it did in the examples from chapter 4. If DBI-> connect
doesn't return a value, the handler calls error to display an error page; the
code is left out for brevity here.
Assuming we're talking to the database, the code next retrieves the given user's
record from the Users table. $try is set to the password retrieved from the table. If
$try is not set, that means there is no such user in the table, and the handler will drop
out to the next section.
The handler then calls crypt on the password and the value stored in the table.
(The need for passing in the already-encrypted value from the database is explained
later in this section.) If the given password encrypts to the same value stored in the
database, the user is valid and the application can go on to whatever it is going to do.
If not, or if any of the other tests given previously failed, the handler goes on to
the next section:
# Invalid user or password.
$r-> send_http_header('text/ html');
print <<ENDHTML;
<!DOCTYPE HTML PUBLIC>
<HTML>
<HEAD><TITLE>Invalid login</TITLE></HEAD>
<BODY>
<H2>The username and/or password you entered is not valid.
Please try again.</H2>
$loginForm
To create an account, go <A HREF="/create">here</A>.
</BODY>
</HTML>
ENDHTML
return OK;
}
This section simply displays a page indicating that the user can't log in with the given
password. It offers the login form again right here, instead of just telling him to go
back. The username will be defaulted into the field already but he will have to type
his password again. This makes use of the default ACTION attribute for the form—
the Submit button invokes the same URL again with the current parameters.
The handler needs to be added to mod_perl's configuration:
PerlModule Examples::Login
<Location /login>
SetHandler perl-script
PerlHandler Examples::Login
</Location>
6.4.2 Doing your own authentication - Page 7
Web Development with Apache and Perl
6.4.2 Doing your own authentication (Cont.) - Page 9
|