Your Daily Source for Apache News and Information  
Breaking News Preferences Contribute Triggers Link Us Search About
Apache Today [Your Apache News Source] To internet.com

Apache HTTPD Links
Apache XML Project
The Jakarta Project
The Java Apache Project
Apache Project
Apache Module Registry
Apache-Perl Integration Project
Apache-Related Projects
ApacheCon
PHP Server Side Scripting
The Apache FAQ
The Apache Software Foundation
The Linux Channel at internet.com
All Linux Devices
Linuxnewbie.org
Enterprise Linux Today
Linux Today
Linux Apps
Linux Programming
BSD Today
Linux Central
BSD Central
Just Linux
Apache Today
Linux Start
Linux Planet
PHPBuilder
SITE DESCRIPTIONS
Apache Guide: Apache Authentication, Part 4
Aug 14, 2000, 03 :40 UTC (18 Talkback[s]) (17953 reads) (Other stories by Rich Bowen)

By

In the last three articles, I've talked about authentication on Apache: asking the user for a username and password to get at your stuff. This week I'll cover some techniques for automating the maintenance of your password lists with Perl. Doing it all by hand can be a real drag.

Warning: This article assumes that you already have a grasp on the basics of Perl.

Perl

In case you don't know what Perl is, here's the simple explanation: it's a programming language. It's a very popular programming language, favored by folks for doing tasks that require text manipulation, sockets communication, orchestrating various applications in some way, and a plethora of other tasks. It is reputed to be very popular as a CGI programming language also, but that's only a smidgen of the whole story, and tends to sell Perl short by people who think, "Oh, that's just a CGI language."

Encrypting a Password

One of the things that is going to come in very handy in managing user and password lists is the ability to encrypt a password. The good news is that Perl has a built-in function to do just this. It's called crypt. In order to use it, you need to understand a few things.

First, as mentioned in an earlier article, Apache stores passwords in what's know as "Unix crypt" format. Perl's crypt function produces this same format. To encrypt a string, you need something called the "salt." The salt is a two (or more) character string that is used to get the encryption started. The salt is usually generated randomly, and so the string will end up being encrypted differently depending on the salt that was picked.

To call the crypt function in Perl, you'd do the following:

        $encrypted = crypt ($password, $salt);

In the above code example, $password is assumed to have been supplied by the user in some fashion, and $salt is assumed to have been generated in some fashion. More on this later.

Crypt is a one-way encryption algorithm. What that means is that once you have encrypted a string, there's no way to decrypt it--to get it back to it's original format. This means that the only way to tell if a particular password is the same as the original is to encrypt that password, and see if you get the same thing. Of course, you have to encrypt it with the same string. Conveniently, crypt leaves the salt in the first two characters of the encrypted string, so you just have to do something like this:

        $guess_encrypted = crypt ($guess, $encrypted);
        if ($guess_encrypted eq $encrypted)     {
                print "You guessed right.\n";
        }
        else {
                print "Wrong password, try again.\n";
        }

When you specify a particular string as the salt, Perl knows to just use the first two characters of that string.

By the way, to generate a salt yourself, you can use something like this:

        @a=(0..9,'a'..'z');
        $pass = join '', map { $a[int rand @a] } (0..1);

That just generates a 2-character string composed of random numbers and letters. And, as always in Perl, there's more than one way to do it.

Adding a Password to a Password File

We've talked about three ways to store your usernames and passwords. First, three weeks ago, we talked about using plain text files. Two weeks ago, we talked about using DBM files. And last week, we talked about using a MySQL database.

There are several ways to handle putting passwords into each type of storage mechanism. In each case, you can do things "by hand", or you can use one of the existing CPAN modules to do a lot of the work for you.

The CPAN module to look for is HTTPD::UserManage. It was written by Lincoln Stein and Doug MacEachern, and allows you to manage multiple types of authentication mechanisms, on multiple server-types (Apache, Netscape, etc) via one interface.

You can get HTTPD::UserManage from your favorite CPAN mirror. It also comes with a CGI application that, when correctly installed, lets you manage your authentication files from the web. Pretty cool stuff.

There are also a couple of other modules - Apache::Htpasswd and Apache::Htgroup, that give a simple, Apache-only interface for managing your authentication files.

Adding a password to a Text Password File

If you want to add a password to a text htpasswd-type password file, without the benefit of modules, here's how you'd do it:

        open PASSWD, '>>/path/to/.htpasswd';
        print PASSWD "$username:$encrypted\n";
        close PASSWD;

Well, you say to yourself, that's pretty darned simple. Why would I want to use a module to do that? Three reasons. One, if you're going to be doing this hundreds or thousands of times, you'll find it much easier to be able to call one function, passing in the username and desired password, than encrypting the password yourself and running the above code. Secondly, the modules provide you with a lot of other functionality, such as verifying a password, and deleting a user. Thirdly, if you're using HTTPD::UserManage, and you decide a year from now to change to using mod_auth_mysql instead of htpasswd files, you don't have to change any code. That third one is a big win, because some day you will want to change your authentication method, and you don't want to be stuck with changing code a dozen places, and potentially missing a few. Trust me. I missed a few.

Passwords in DBM Files

DBM files are the fun ones, because they let me use a pretty cool feature of Perl. Perl has a key work called tie. As the name suggests, it lets you tie one thing to another. In this case, it lets you tie a variable (in particular, a hash) to a DBM file. So, when you modify the hash, the DBM file automatically gets modified for you. Very cool stuff.

This looks like the following:

        use DB_File;
        my %database;
        tie %database, 'DB_File', "passwords.dat"
            or die "Can't initialize database: $!\n";
    $crypt = crypt($password, $salt);
        $database{$username} = $crypt;
        untie %database;

And, voila, you have an entry in the password file associating user $username with their password.

Note that you should, of course, not put your password file inside your web root, where someone can download it and crack it at their leisure. The above code is just an example.

Passwords in MySQL Databases

This is the most obvious one. In fact, most often when you use mod_auth_mysql, it's beacase you already have user information in a database, and want to use if for authentication.

Information can be updated in the database with regular SQL statements, and DBI:

        use DBI;
        my $dbh = DBI->connect('DBI:mysql:database', 'username',
     'password'); # 'password' is the database password.
        my $sth = $dbh->prepare("update passwords
                set passwd = '$crypt' where username = '$username'");
        $sth->execute;
        $sth->finish;
        $dbh->disconnect;

Summary

This was a lightning-fast overview of how one might use Perl to manage your password lists, in any of the three storage mechanisms that we've talked about over the last three weeks.

Future columns

Please let me know if there are other topics that you'd like for me to talk about in future columns. You can send your suggestions to me at And please let me know what you think of my columns, at that same address. Many thanks for reading down this far!

--Rich

  Current Newswire:
WDVL: Perl for Web Site Management: Part 3

Retro web application framework V1.1.0 release

Leveraging open standards such as Java, JSP, XML,J2EE, Expresso and Struts.

Netcraft Web Server Survey for November is available

FoxServ 2.0 Released

Ace's Hardware: Building a Better Webserver in the 21st Century

Web Techniques: Customer Number One

Apache-Frontpage RPM project updated

CNet: Open-source approach fades in tough times

NewsForge: VA spin-off releases first product, aims for profit

 Talkback(s) Name  Date
  Using authentication
I've browsed through the last two articles in this series. There's plenty of detail on various methods for storing usernames and passwords and verifying them, but how do you actually use the auth information? In otherwords, how do I find out what user is logged in within say, a CGI program? My languege of prefernce in this case is perl, if that matters. If this was already discussed in one of these articles and I just missed it, my apolgies in advance :).

Thanks

  
  Aug 16, 2000, 15:04:31
  Apache Authentication part 4
Hi

great article.
I was interested in possibly applying the last method (passwords in mysql databases) to an account based site I'm developing. Wouldn't this be assuming that I would be using perl for password verification for the rest of the database's existance. It is possible I would eventually use another technology. If perl encrypts the string, would it not have encrypt all password entry attempts and compare it to the database entry it made in the first place or could any language (including mysql statements) encrypt login attempts and get the same result.

thanks,
adam

p.s. wouldn't $crypt and $username be interpretted as literal strings with the apostrophes around them?

  
  Aug 17, 2000, 19:43:42
   Re: Apache Authentication part 4
p.s. wouldn't $crypt and $username be interpretted as literal strings with the apostrophes around them?
No, because it is within a double quoted string. Example:
$foo="bar";
print '$foo'; #prints: $foo
print "$foo"; #prints: bar
print '"$foo"'; #prints: "$foo"
print "'$foo'"; #prints: 'bar'

  
  Aug 21, 2000, 13:32:32
   Re: Using authentication
> I've browsed through the last two articles in this series. There's plenty of detail on various methods for storing usernames and passwords and verifying them, but how do you actually use the auth information? In otherwords, how do I find out what user is logged in within say, a CGI program? My languege of prefernce in this case is perl, if that matters. If this was already discussed in one of these articles and I just missed it, my apolgies in advance :).
Thanks


Hmm. Good question. I'll have to come back to that.

The short answer is that, in Perl, you can refer to the variable $ENV{REMOTE_USER} to get the username. The HTTP variable is called REMOTE_USER, so if you're using another language, you use whatever the ENV access mechanism is in that language.

--Rich   
  Aug 22, 2000, 12:22:08
   Re: Apache Authentication part 4
The crypt() method is pretty standard. It's not specific to Perl. So any language you use to encrypt your passwords will be the same format, and Apache will still understand it just fine.

OTOH, you will need to be careful with the MySQL PASSWORD() function, as it is a different format than Apache understands.

  
  Aug 22, 2000, 12:25:59
  MD5
I think you should mention that system using MD5 passwords, the crypt will not work.   
  Aug 24, 2000, 07:07:59
  Authorization failed??
I installed Apache 1.3.12 w/ mod_ssl on my FreeBSD 4.1R.
When I want to access some protected html files, browser ask me to
type id and password, but it doesn't accept my correct password, just give
me 401...Could someone help me ? Thanks in advance.   
  Aug 29, 2000, 13:21:27
  Passing credentials to another Apache server
A bit desperate here. This is probably a stupid question.

I have user logging in using .htaccess on an external Apache web site. I want to be able to allow them to click on a link which will take them to another Apache web server inside the firewall, where an app is running. This app requires a login, (web app), but I'd like to somehow pass the users credentials to the internal web site without having the user have to login a second time.

Do you know how I can do this?

Thanks extremely much. There could be beer involved.

Eric Ryder
  
  Oct 5, 2000, 02:35:00
   Re: Passing credentials to another Apache server
> A bit desperate here. This is probably a stupid question.
I have user logging in using .htaccess on an external Apache web site. I want to be able to allow them to click on a link which will take them to another Apache web server inside the firewall, where an app is running. This app requires a login, (web app), but I'd like to somehow pass the users credentials to the internal web site without having the user have to login a second time.
Do you know how I can do this?
Thanks extremely much. There could be beer involved.
Eric Ryder


Sounds like you have two problems:

1) how to stop double authentication

When they login using .htpasswd you can access their username but not password using the environmental variables. Your best bet is to implement your link as a cgi on the outside server and forward the authentication. You could also consider changing authenticaton to a cookie based scheme and then you could send that directly to the inside server.

2) how to tunnel the access across the firewall

Guess you have a couple of options, you could frame the request and have the external server do it for the client, you could tunnel it across opening a temporary hole say with socks or you could redirect the client using the Location header.

Any old way it sounds complex and possibly insecure - good luck   
  Oct 15, 2000, 19:36:44
   Re: Using authentication
I'm not sure if that's a 100% correct method but you can check the environment variable called REMOTE_USER to check who has logged in. To do so from a Perl CGI you can use $ENV{REMOTE_USER}.

> I've browsed through the last two articles in this series.
> There's plenty of detail on various methods for storing usernames and
> passwords and verifying them, but how do you actually use the auth
> information? In otherwords, how do I find out what user is logged in
> within say, a CGI program?   
  Nov 7, 2000, 18:08:53
  Cancelling Authentication
I'm trying to find out how to cancel the authentication. In other word, I'm trying to put logout option to my web page. Do you know of any way to do this?

  
  Nov 28, 2000, 05:39:26
  User authentication
Hello!

I also use Perl for my CGI scripts. For checking userID I use $ENV{"REMOTE_HOST"} but for checking real user running the CGI I use backquoted whoami UNIX command. I have Auth directives and I ask for username and password. But when I start my CGI scripts it says RemoteUser = miha, UserID = nobody. The same as is set in httpd.conf. How to make that every user with account on our network will use his user name to run CGI scripts???

I don't use /etc/passwd file, I have my own .htpasswd. I just want permissions of the users.

Thanx   
  Dec 17, 2000, 13:26:51
   Re: Re: Passing credentials to another Apache server
Guess you have a couple of options, you could frame the request and have the external server do it for the client, you could tunnel it across opening a temporary hole say with socks or you could redirect the client using the Location header.

By "framing the request" i guess that you set a document.location of a frame to "http://uid:pwd@myhost/welcome.html" thus redirecting that frame towards the internal resource. The problem with this method is that the url is stored in the browser history, thus representing a security hasard.

With tunnelling you would get in to a whole lot of problems creating a http parser using CGI or something to interpret http Send and Get through the tunnel. (I'm not sure what you actually mean here, but the tunnel would have to operate from the server, so you wouldn't authenticate the browser, thus having to continue the session with the intranet using serverside scripts i guess?) (Please enlighten me if I didn't understand your approach)

I've tried redirecting the user with location header using both the cgi-mod and direct header manipulation with print command, and I had problems making the browser authenticate with the given credentials:
The header was generated like this: (perl cgi)
print $q->redirect("http://uid:pwd@myhost/welcome.html") or like this:
print "Location: Moved 302 etc.....
but with no luck. It seems as if the browser won't perform a new authentication based on the redirection.

So, anyone got a recipe for this based on apache/perl ?. I've seen it done easily with Java/JSP on other system like BEA weblogic, and I've even seen a HTTP POST mechanism using Siebel work, and I guess it's just a matter of writing a CGI on the internal server that recieves a HTTP POST with uid and password, that checks the credentials and return a Authentication header or something to the browser, thus solving authentication without showing any prompts to the user...?
  
  Jan 10, 2001, 10:53:13
   Re: Passing credentials to another Apache server
If I was going to pas credentials on, I would have SSL Certs (try Onsite from Verisign), that the first apache server would look for, and then reload onto the apache server *inside the firewall*. Also, If you're really really trying to do this, I'm sure someone or yourself could develop a PKI infastructure, and just have the machine waiting for people with the PKI keys.


Hope this helps..
  
  Feb 7, 2001, 21:24:44
  Are Dynamic HTAccess Files Possible???
Is it possible to dynamically create an htaccess file that can redirect
based on the user??

I have a web site that has 100 directories that need to be secure. In stead of fighting 100 static
access files, index pages, etc., it would be great to have the link point to a perl script and send back
an authentication prompt. Upon passing the user, sending them to their proper directory fully authenticated.

I understand cgi/perl stuff, as my hang up is in the security portion. Any help is greatly appreciated...

Thanks, Jeff.   
  Mar 10, 2001, 08:56:34
  Timeouts with authentication
Is there any module available to timeout a login - so that Apache will automatically force a relogin after a period of idle time?

I've done this with PHP already, but the website I'm working on now cannot use the same approach.

Any help will be appreciated.
Thanks.   
  Mar 12, 2001, 21:16:57
  Where can i found?
Where can i found mod_auth_pgsql?? if it is posible rpm format

I need it!!


  
  Apr 26, 2001, 07:20:50
   Re: Authorization failed??
> I installed Apache 1.3.12 w/ mod_ssl on my FreeBSD 4.1R.
When I want to access some protected html files, browser ask me to
type id and password, but it doesn't accept my correct password, just give
me 401...Could someone help me ? Thanks in advance.

Hello, We have the same problem on openvms. I made a password file using htpasswd.exe-alpha and the cgi-bin program askes for user+password but never approves while I have very carefully entered the passwords. Did you get any soluton from someone ?

Please reply to [email protected] . Thank you !
  
  May 3, 2001, 16:50:09
Enter your comments below.
Your Name: Your Email Address:


Subject: CC: [will also send this talkback to an E-Mail address]
Comments:

See our talkback-policy for or guidelines on talkback content.

About Triggers Media Kit Security Triggers Login


All times are recorded in UTC.
Linux is a trademark of Linus Torvalds.
Powered by Linux 2.4, Apache 1.3, and PHP 4
Copyright INT Media Group, Incorporated All Rights Reserved.
Legal Notices,  Licensing, Reprints, & Permissions,  Privacy Policy.
http://www.internet.com/