Hello All,

I have been given the task of customizing a script from III (included below) to 
make it hit multiple LDAP servers.  The issue is that I want to insert some 
logic so that it only hits the right server.  The input is going to come from 
an html page with a dropdown menu that will pass usern...@domain.edu.  We have 
4 possible domains (ccsu.edu, scsu.edu etc...)  What I think I need is 
something that will read the incoming string and say if ccsu.edu go to 
ldap.ccsu.edu.  I am just not sure where to insert this and what effect it will 
have on the rest of the script.  

Has anyone got such a script stowed away somewhere they would be willing to 
share?

Thanks,
~~~~~~~~~~~~~
Edward Iglesias
Systems Librarian
Central Connecticut State University



#!/iiidb/software/tpp/perl/bin/perl -w

use Net::LDAP;
use Net::LDAPS;
use strict;
use CGI qw(unescape);

#
#-----------------------------------------------------------------------
# This perl script is provided as an example for libraries that want to
# employ Innovative's "plugin" model for External Patron Verification.
#
# The example script queries multiple LDAP servers depending on the type 
# of user, e.g. staff/faculty vs. student; campus1 vs. campus2; etc.
#
# This script is not intended to be "standalone" but is instead called by 
# the Innovative checkLDAP script.
#
# Innovative provides this example script as a courtesy to libraries that
# have multiple LDAP servers.  The library is responsible for customizing 
# this script with local values, enhanced functionality, etc. 
#-----------------------------------------------------------------------
#

my $debug = "yes";

open (DEBUG, ">>/tmp/checkLDAP_dlevy.log") if ($debug eq "yes");

#
# LDAP connection information is stored in arrays of size 2.
# The script assumes that the first location (0) in the array 
# contains the connection information for the student LDAP server, 
# i.e. the input extpatserver = student, if  extpatserver = staff the
# script uses the connection information from the second location (1)
# in the following arrays.
# If there is no value in extpatserver, the script queryies the student
# LDAP server.
# These arrays should be initialized here with the real values.
# To customize this script for you system, configure the following 
# arrays:
#
# m_sLDAPServer : contains the host domain name of the LDAP servers.
#
# m_nPort :  specifies the port used to connect to the LDAP server.
#
# m_bUseLDAPS : set to 1 if you use a secure connection i.e. port 636, 
#               set to 0 if you use a non-secure connection.
# m_sBindBase : contains a string that defines which database to use 
#               on the LDAP server on the first bind command; 
#               if empty use anonymous bind.
#
# m_sBindPassword : contains the password of the administrator account 
#                  you use to bind. Set the password unencrypted, 
#                  i.e. use the string you received from the LDAP 
#                  adminstartor as it is.  
# m_sBindUser : set the login of the administartor account, or an empty string
#
# m_bUseOneBind: set to 1 if you use user's credentials to bind.
#
# m_sSearchAttribute : contains the primary search attribute to be used 
#                  (university ID, for example) when searching for 
#                  a given patron on the LDAP server.
#
# m_sSearchBase : contains the search DN used to retrieve user records.
#
# m_sIDAttribute : contains the attribute in the data returned by the LDAP
#                  server which is used as the patron search key on the
#                  Millennium server.   
#

my @m_sLDAPServer = ("ldap.ccsu.edu","");
my @m_nPort = ("636","");
my @m_bUseLDAPS = (1,0);
my @m_sBindBase = ("BIND_BASE= dn=ccsu,dc=edu","");
my @m_sBindPassword = ("","");
my @m_sBindUser = ("","");
my @m_bUseOneBind = (1,0);
my @m_sSearchAttribute = ("USERPrincipalName","");
#This is proboably going to need some work
my @m_sSearchBase = ("search_base =, DC=ccsu,DC=edu","");
my @m_sIDAttribute = ("","");


my $m_bUseLDAPPassword = 1;
my $m_bTryMillenniumAfterBadVerify = 0;

my @m_nTimeOut = (3,3);
my $m_sLDAPVersion = 3;

#
# Input variables are stored in teh following variables
#
my $m_sUserName = "";
my $m_sUserId = "";
my $m_sPassword = "";
my $m_sServer= "";

my $m_hLDAP;
my $m_whichServer = 0; #Identifies which server to query by index, either 0 or 1
my $m_hSearchMessage;
my $m_bVerbose = 0;
#my $m_bVerbose = 1;
my $m_nTimeOut = 3;


my $m_sOriginalUserId;
my $m_sResult = "Failed";
my $m_sLogMessage = "";
my $m_sIIIDB = "";

#------------------------------------------------------------
# log a message for each verification to $IIIDB/errlog/ldap.log
# append if is used to wrap log so it doesn't grow to big
#------------------------------------------------------------
sub logger
{
my $sMessage = shift;

my $sOutName = $m_sIIIDB . "/errlog/ldap.log";

if( ( -e "$sOutName" ) && ( -s "$sOutName" ) > 100000 )
    {
    rename( "$sOutName", "$sOutName.old" );
    system( "touch $sOutName" );
    }

open( OUT, ">>$sOutName" ) ||
    die( "Cannot appendf $sOutName\n" );

my ($nSec,$nMin,$nHr,$nDay,$nMonth,$nYear,$sRest) = localtime();

my $sDenseTime = sprintf "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d",
                $nYear + 1900, $nMonth + 1, $nDay, $nHr, $nMin, $nSec;
print OUT "$sDenseTime:$m_sOriginalUserId:$m_sUserId" .
          ":$m_sLogMessage:$sMessage\n";
if( $m_bVerbose )
    {
    print "$sDenseTime:$m_sOriginalUserId:$m_sUserId" .
              ":$m_sLogMessage:$sMessage\n";
    }
close( OUT );
}
#----------------------------------------------------------------
#
# Innovative checkLDAP script
# The Innovative Perl script sends the following name/value pairs
# via STDIN to this plugin script:
#
#    extpatid= is the patron ID number.
#
#    extpatpw= is the patron password.
#
#    extpatserver= indicates the patron's choice of 
#    "student" or "staff"
#
#----------------------------------------------------------------
sub parseInput
{
while( <> )
        {
        chomp;

        for( split /\&/ )
                {
                if( /^extpatname=(.*)/ )
                        {
                        $m_sUserName = unescape($1);
                        }
                elsif( /^extpatid=(.*)/ )
                        {
                        $m_sUserId = unescape($1);
                        }
                elsif( /^extpatpw=(.*)/ )
                        {
                        $m_sPassword = unescape($1);
                        }
                elsif( /^extpatserver=(.*)/ )
                        {
                        $m_sServer= unescape($1);
                        }
                }
        }
}
#---------------------------------------------------------------
#
# Open a connection to the LDAP server.
#
#---------------------------------------------------------------
sub doConnect
{
my      @aLDAPArgs;

push( @aLDAPArgs, $m_sLDAPServer[$m_whichServer] );
push( @aLDAPArgs, port => $m_nPort[$m_whichServer] );


if( $m_bUseLDAPS[$m_whichServer] )
    {
      $m_hLDAP = new Net::LDAPS( @aLDAPArgs ) ||
                 systemError( "Cannot create session, ar...@aldapargs" );
     }

else
    {

    $m_hLDAP = Net::LDAP->new( @aLDAPArgs ) ||
               systemError( "Cannot create session, ar...@aldapargs" );
     }

if( ! defined( $m_hLDAP ) )
     {
       systemError( "Bad return from LDAP->new with ar...@aldapargs" );
      }

if( $m_bVerbose )
        {
        print "LDAP connection established ar...@aldapargs\n";
        }

return 1;
}
#------------------------------------------------------------
sub doBind
{
#expects the following parameters
my $sBindBase = shift;
my $sBindUser = shift;
my $sBindPassword = shift;
my $sMessage = shift;
my $bReturnOnVerifyError = shift;

my @aBindArgs;
my $mesg;

if( $sBindBase ne "" )
    {
    push( @aBindArgs, dn => $sBindBase ) ;
    }
if( $sBindPassword ne "" )
    {
    push( @aBindArgs, password => $sBindPassword );
    }
if( $m_sLDAPVersion ne "" )
    {
    push( @aBindArgs, version => $m_sLDAPVersion );
    }

$mesg = $m_hLDAP->bind( @aBindArgs ) ||
     systemError("Failed to bind args=dn $sBindBase version $m_sLDAPVersion");

if( $m_bVerbose )
    {
    print "Bindargs = @aBindArgs\n";
    }

if( $mesg->code() )
    {
    if( $bReturnOnVerifyError )
        {
        return( 0 );
        }
    else
        {
        verifyError( "$sMessage:bind failed:mesg=" .
          "(". $mesg->code() . "),args=dn $sBindBase version $m_sLDAPVersion" );
        exit( 0 );
        }
    }
if( $m_bVerbose )
    {
    print "Bind succeeded\n";
    }
return( 1 );
}

#------------------------------------------------------------
# performs a search, if the count is not 1 and there exists
# a fallback search method try that.
#------------------------------------------------------------

sub doSearch
{
my @aSearchArgs;

push( @aSearchArgs, base => $m_sSearchBase[$m_whichServer] );
my $sFilter = "$m_sSearchAttribute[$m_whichServer]=$m_sUserId";
push( @aSearchArgs, filter => "$sFilter" );

alarm $m_nTimeOut;

$m_hSearchMessage = $m_hLDAP->search( @aSearchArgs ) ||
                     systemError ("Failed on search ar...@asearchargs");


alarm 0;

if( $m_hSearchMessage->code() )
    {
    verifyError( "search failed mesg=" .
                 "(". $m_hSearchMessage->code() . "),ar...@asearchargs" );
    return 0;
    }

if( $m_bVerbose )
    {
    printf( "Search done: ar...@asearchargs\n" );
    }

my @aList = $m_hSearchMessage->all_entries;

my $nCount = $#aList + 1;

if( $m_bVerbose ) { print "Search found $nCount matching patrons\n"; }

return $nCount;
}

#------------------------------------------------------------
sub checkPassword
{
my $hEntry = shift;

if( $m_bUseLDAPPassword == 0 ) { return 1; }

my $sVerifyUserName = $m_sUserId;

if( ! doBind( $hEntry->dn(),
        $sVerifyUserName,
        $m_sPassword,
        "Bad password",
         $m_bTryMillenniumAfterBadVerify ) )
    {
    return( 0 );
    }

$m_sLogMessage .= "good password ";

if( $m_bVerbose )
    {
    print "Password check succeeded\n";
    }
return( 1 );
}

#------------------------------------------------------------
# verification has failed log and exit with string Error
#------------------------------------------------------------
sub verifyError
{
my $sMessage = shift;

$m_sUserId = "Error"; # this is the string we will return to the webpac
if( defined $m_hLDAP )
    {
    $m_hLDAP->unbind;
    }
logger( $sMessage );

print "extvererr=$sMessage\n";
}

#------------------------------------------------------------
# log an error message to the syserr file
#------------------------------------------------------------
sub logError
{
my $sMessage = shift;
my $sSyserr = $m_sIIIDB . "/errlog/syserr";
if( open( SYSERR, ">>$sSyserr" ) )
    {
    print SYSERR "$sMessage\n";
    close( SYSERR );
    }
}

#------------------------------------------------------------
# log an error message to the syserr file and exit with Error
#------------------------------------------------------------
sub systemError
{
my $sMessage = shift;

$m_sUserId = "Error"; # this is the string we will return to the webpac
if( defined $m_hLDAP )
    {
    $m_hLDAP->unbind;
    }
logger( "$sMessage ($!)" );
logError( "$sMessage ($!)" );

print "extsyserr=$sMessage\n";
exit 1;
}


#---------------------------------------------------------------
sub cleanUpAndExit
{
$m_hLDAP->unbind; # take down session
exit 0;
}
#---------------------------------------------------------------

sub notFound
{
my $sMessage = shift;

if( ! defined( $sMessage ) ) { $sMessage = "no message"; }
print "extvererr=$sMessage\n";
cleanUpAndExit();
}

#------------------------------------------------------------
# catches alarm, we set alarm so we don't wait forever for the ldap server
#------------------------------------------------------------
sub catchAlarm
{
logError( "Timeout occurred" );
}

#------------------------------------------------------------
#
#   main() starts here
#
# it is CRITICAL that nothing read stdin that will be done by
# parseInput after the globals are loaded and a user script
# has been ruled out
#
#------------------------------------------------------------
$SIG{ALRM} = \&catchAlarm;

parseInput();

 print DEBUG "The userID entered is: $m_sUserId\n" if ($debug eq "yes");


$m_sOriginalUserId = $m_sUserId;
if( $m_sPassword eq "" )
        {
        verifyError( "password not specified" );
        exit( 0 );
        }

if( $m_sUserId eq "" )
        {
        verifyError( "got empty lookup field" );
        exit( 0 );
        }

if( $m_sServer eq "staff" )
    {
        $m_whichServer = 1;
    }
else
        {
        $m_whichServer = 0;
        }

if( ! doConnect() )
    {
    exit 0;
    }

if( $m_bUseOneBind[$m_whichServer] )
    {
    my $sTempUserName = $m_sUserId;
        }


if( ! doBind($m_sBindBase[$m_whichServer], $m_sBindUser[$m_whichServer], 
     $m_sBindPassword[$m_whichServer] ,"",$m_bUseOneBind[$m_whichServer] ))
    {
    notFound( "no bind" );
    }

my $nMatchCount = doSearch();

if( $nMatchCount == 0 )
    {
    $m_sLogMessage .= "not on LDAP, ";
    notFound( "not found" );
    }
elsif( $nMatchCount == 1 )
    {
    $m_sLogMessage .= "on LDAP ";

    my @aList = $m_hSearchMessage->all_entries;
    my $hEntry = pop @aList;

    if( $m_bVerbose )
        {
        print "Entry dn= " . $hEntry->dn() . "\n";
        $hEntry->dump;
        }

    if( ! $m_bUseOneBind[$m_whichServer] && ! checkPassword( $hEntry ) )
        {
        $m_sLogMessage .= "failed password on LDAP, ";
        notFound( "failed password" );
        }
    else
        {
        my @sID = $hEntry->get_value( $m_sIDAttribute[$m_whichServer] );
        my $sID;

        if( ! @sID )
        {
        verifyError("Could not find attribute $m_sIDAttribute[$m_whichServer]");
            notFound( "no attribute" );
        }

        $sID = $sID[0];
        if( ! defined( $sID ) || $sID eq "" )
        {
        verifyError("Could not get attribute $m_sIDAttribute[$m_whichServer]");
            notFound( "no attribute" );
        }

        $m_sUserId = $sID;
        }
    }
else
    {
    $m_sLogMessage .= "many on LDAP ";

    verifyError( "$m_sUserId had $nMatchCount matches on LDAP server" );
    }

logger( "OK" );

print "extid=$m_sUserId\n";

cleanUpAndExit();

1;



Reply via email to