http://www.perlmonks.org?node_id=234258

enoch has asked for the wisdom of the Perl Monks concerning the following question:

I am running Perl as a CGI (and, yes, I have begged and begged Sys. Admin's to get mod_perl on there, but to no avail) on Apache. I have a page where user's can go to and modify some of their own LDAP attributes. Before they reach the page, Apache challenges them for authentication (via mod_auth_kerb). Once they are authenticated, I can look in $ENV{'REMOTE_USER'} to get their username and run a query against LDAP via this trimmed down code:
my $ldapObj = Net::LDAP->new($server); $ldapObj->bind; # bind anonymously my $ldapSearchUser = $ldapObj->search(base => 'o=isp', filter => '(uid=' . $ENV{'REMOTE +_USER'}. ').);
After they make some modificatication(s) to their information, I need to bind back to the LDAP server as the user who logged on to the web page. Something like:
$ldapObj->bind($dn, $ENV{'PASSWORD'})
The problem being, there is no $ENV{'PASSWORD'}. Is there any way I can get Perl (as CGI) to access the password the user logged in with?

Thanks,
enoch

Replies are listed 'Best First'.
•Re: Accessing Authenticated User's Password From CGI
by merlyn (Sage) on Feb 10, 2003 at 22:56 UTC
    By design, the authenticated user is passed in the CGI environment, as you have found, but not the password.

    If you need the password as well, you'll need to ask for it as part of the form.

    BasicAuth is a hack anyway. You can't force a logout. You can't force a timed-out logout. You should be using a cookie-based login scheme, as I illustrated in one of my more famous columns.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      I just went and read that famous column.

      The section

      The wrong way to use cookies, therefore, is to have a login form, and on successful login, send out a cookie that lasts until year 2003 to that browser. That's bad.

      Has a little less impact now that it is 2003.
      --

      “Every bit of code is either naturally related to the problem at hand, or else it's an accidental side effect of the fact that you happened to solve the problem using a digital computer.”
      M-J D
      Hmm... I suspected as much. Thanks for the reply; I am off to read up on Kerberos modules.

      enoch

        i did this (authenticate via Kerberos using CGI) not too long ago. i couldn't find a Module that easily did exactly what i wanted. the closest was Authen::Krb5::Easy, but it used the /etc/krb5.keytab file instead of passwords to get a principal. so i hacked it to do what i wanted... just a change from calling krb5_get_init_creds_keytab to krb5_get_init_creds_password in the Easy.xs file and tweaking the arglist and documentation.

        WARNING: since i only used this module in one application (with it's own private /lib/perl) i didn't get around to renaming it to something like Authen::Krb5::Easy::Password or the like. should you use it, be warned... i wouldn't put it where another Perl user could use it thinking it was the real Authen::Krb5::Easy module...

        # simple useage use Authen::Krb5::Easy; my ($user, $password) = @ARGV; if ( Authen::Krb5::Easy::kinit( $user, $password ) ) { print "Authentication success!$/"; } else { print "Authentication failure!$/"; }

        you can try it if you like ... Authen-Krb5-Easy-0.90-hacked.tgz

Re: Accessing Authenticated User's Password From CGI
by Mr_Person (Hermit) on Feb 10, 2003 at 22:53 UTC
    I don't think there is a way to get the user's password through CGI. The only authentication related variables I see are AUTH_TYPE, REMOTE_USER, and REMOTE_IDENT. In some cases, such as when using Digest authentication, I don't know that the webserver would even have access to the user's password. Perhaps it would be better to use an SSL secured web form for login, have the Perl program authenticate the user, and then make the LDAP changes.
Re: Accessing Authenticated User's Password From CGI
by valdez (Monsignor) on Feb 10, 2003 at 23:15 UTC

    Username and password are asked during Apache's authentication phase, while your script is executed later during content generation phase. These two phases don't share user's password, because it is not needed and dangerous. So there is no way to obtain a password from a plain Apache.

    You need a special handler and mod_perl would be a nice solution, but you can't use it :( so what suggested Mr Person (++) seems to be the only viable solution. It has also an advantage over basic authentication: you can logout users without forcing them to close their browsers.

    Ciao, Valerio

Re: Accessing Authenticated User's Password From CGI
by simon.proctor (Vicar) on Feb 10, 2003 at 22:58 UTC
    > The problem being, there is no $ENV{'PASSWORD'}

    Think about that for a minute. If there were, how secure would your network be? Not very.

      Unbelievable as it may seem, IIS3.0 on Windows NT4.0 actually does provide the password in $ENV{REMOTE_PASSWORD}. I assume this design decision was in some way related to the fact that in IIS, the username/password supplied via basic authentication must be a valid OS signon and getting an NT security token generally requires a plaintext password. I'm not sure if this 'feature' has been removed in more recent versions of IIS.

      I was thinking something more like a variable accessible just from Perl. Something no different than using a PerlAccessHandler with mod_perl a la:
      sub authen_handler { my $r = shift; # get user's authentication credentials my ($res, $password) = $r->get_basic_auth_pw; return $res if $res != OK; my $user = $r->connection->user; # authenticate through DBI my $reason = authen_dbi($r, $user, $sent_pw); if ($reason) { $r->note_basic_auth_failure; $r->log_reason($reason, $r->uri); return AUTH_REQUIRED; } return OK; }
      I am not sure I understand how setting an environment variable would make a network insecure even if the variable is a user's password. If the password is sent over SSL and only accessible from the Perl CGI that accessed it, what insecurities would result?

      enoch
        If I have made any mistakes or erroneous assumptions here please tell me! :)

        To be fair the context of your intitial request hinted more at your wanting to look at the network credentials of the authenticated user. At least thats how I saw that.

        However, regardless of first impression, you should look at this from a different angle. Consider yourself as the user of your application/network.

        You want the confidence that once authenticated, your password is not used or transmitted again unless specifically actioned by yourself. Your password is direct access to your identity so you want the finest control over it you can have.

        The environment you refer to comes from the server. The server doesn't magic this up but receives these variables from the context of where and how it is running. For it to create the password environement variable for your program it must have first received that information in some form.

        Now this would have to come with every single request from the client regardless of whether you are using mod perl or not. That would mean that the clients password would be transmitted over the network each time it did something.

        Now you should clearly see why that is dangerous.

        If you are wanting to stick with network security as your methodology (which is what you originally implied) then you have to trust to the security of that network.

        However, you have a separate context of the user implicity providing their authentication details. In that instance then you have already been given the advice you need on how to implement this. You must bear in mind, though, that this will ultimately be a different set of data to that of the network authentication data (though some users will be naughty and use the same usernames/passwords).

        HTH

        SP