I have cobbled together a working AuthcNDS module that allows me to authenticate users 
against the netware NDS tree within our office. 

My apache server is running on a RH5.2 box with some of the Caldera netware RPMs 
installed.
Server Version: Apache/1.3.9 (Unix) mod_fastcgi/2.2.2 PHP/3.0.12 mod_perl/1.21

The module doesn't communicate directly with the NDS, but instead uses a command line 
tool (nwlogin) to do the password checking. Unfortunately spawning that process is 
rather time consuming so once the user is authenticated, the module sets a cookie 
based on the username, IP, a 'secret' and MD5 hashes it. 

The module, when asked to authenticate a user, first checks for that cookie. If it 
doesn't exist, it then goes to the NDS.

I used one of the Apache auth-cookie modules as a starting point.

I need to fix up the spawning of the nwlogin process as i think the users password 
would be visible in the output from 'ps auxw'. Perhaps i should pipe the password to 
nwlogin instead of passing it as a command line arguement.

Any other suggestions for tidying it up? Have i made any glaring mistakes? (this is my 
first mod_perl effort)

Unfortunately it is not self contained and is reliant upon the nwlogin tool that comes 
with the Caldera RPMs.

=======================================================
package Apache::AuthcNDS;
#
# file: Apache/AuthcNDS.pm
#
# performs authentication against the NDS and makes use of cookies to cache
# authentication info so that we dont have to reauth for every single hit
# which can be quite time consuming as the auth process requires the use of
# an external shell program.
#

use strict;
use MD5;
use CGI::Cookie;
use Apache::Constants qw(:common);

my $r;

sub handler 
        {
        $r = shift;
        my ($cookie , $user, $auth_cookie , $authstring, $md5check, $newcookie , 
$cookie_text);

        my ($res, $sent_pw) = $r->get_basic_auth_pw;
        return $res if $res != OK; 

        $user = $r->connection->user;
        
        #
        # the secret is the only bit of text not derived from the user
        # this stops them from creating a fake cookie ( i hope )
        # 
        
        my $secret = 'elegiac';
        
        #
        # search thru the cookies for ours...
        # if our cookie shows up, they must have already authenticated
        # if so i can avoid the expensive NDS lookup
        #
        
        ($auth_cookie) = ( ($r->header_in("Cookie") || "") =~ /Auth_NDS_ID=([^;]+)/);
                
        if ($auth_cookie) 
                {
                $md5check = join('-', $user , &MakeHash($user , $r->auth_type , 
$r->auth_name , $secret));
                
                if ($md5check eq $auth_cookie)
                        { return OK; }
                }

        # failing that we have to actually check their credentials
        # against the NDS
        
        if (!&auth_nds ( $user , $sent_pw )) 
                {
                        # authentication failed !
                        # log that and clear the cookie on the users machine
                        $r->note_basic_auth_failure;
                        $r->log_reason("Authentication of [$user] against NDS 
failed.", $r->filename);
                        $r->err_headers_out->{'Set-Cookie'}  = "Auth_NDS_ID=";
                        return AUTH_REQUIRED;
                } 
        else
                {
                        # authentication succeeded, so let them know, and set the 
cookie for future reference
                        
                        $cookie_text = join('-', $user , &MakeHash($user , 
$r->auth_type , $r->auth_name , $secret));
                        $newcookie = new CGI::Cookie(-name => 'Auth_NDS_ID',
                                                -value => $cookie_text);
                
                        $r->err_headers_out->{'Set-Cookie'}  = $newcookie;
                        return OK;
                }
        }

#==================================
# make up the hash to be placed in the cookie (hash cookies? ;)
#==================================
sub MakeHash()
        {
        
        my ($u , $at , $an , $d) = @_;
        
        my $authstring = $u . $at . $an . $d;
        
        return MD5->hexhash($authstring)
        }

#==================================
# check the username and password against the NDS
#==================================
sub auth_nds()
        {
        my ($user_abs , $current, $authenticated);
        
        my ($user,$pass) = @_;

        # dont process if username or password is blank 
        if (!$user || !$pass) { return 0;}

                # check to see if someone else is logged in

                $current = `nwwhoami`;
                
                # if someone else is currently logged in then note that and wait 1 
second
                if ($current) { $r->log_reason ("someone already logged in. sleeping 
for 1s." , $r->filename) ; sleep 1; }
                
                # clear all current connections (for the NOBODY user)
                
                system ('nwlogout -a > /dev/null 2> /dev/null');

                #
                # trim the username passed to us so that we have one form that starts 
with a DOT and one that doesnt
                # i.e .sf.tr.bne and sf.tr.bne
                #
                $user_abs = $user;

                unless ($user_abs =~ /^\./) { $user_abs = '.' . $user_abs;} 
                $user =~ s/^\.//;
                
                #
                # now try to login using that username and password
                # and rely on the exit status to determine whether it failed or not
                #
                $authenticated = system("nwlogin -u $user_abs -p $pass > /dev/null 2> 
/dev/null");
                
                # tidy up after ourselves by logging out the NOBODY user
                system("nwlogout --all > /dev/null 2> /dev/null");

        # and return a status
        return !$authenticated;

        }

#==================================


1;
__END__




Reply via email to