Bongo-teers,

I've had the need for an email solution with an ldap auth subsystem for
some time now. After bothering so_solid_moo and fatpelt about the
possibility a while back, I finally buckled down and wrote a (very basic
and hackish) shell script in PHP which handles the verification that a
user exists and also authenticates the user. The shell script is
minimally configurable and is destined to be called from within Bongo's
MsgAPI Auth Backends. The script works straight from the commandline and
is tested only on a single machine so far (openSUSE 11.2, PHP 5.2.12 w/
ldap module, openLDAP 2.4.12-5.5.1).

There are still several areas of improvement...

    * Handle various linux distros in regards to command line
      interpreter (#!/usr/bin/php in my case)
    * Scalability related to Bongo domains as well as LDAP DIT and schemas
    * Better ldap search builder
    * More flexible LDAP connection configuration
    * Etc.

This script simply may be a stop-gap until something better comes along.
However, I'd like to open it up to feedback and improvement. Please find
it below or attached.



#!/usr/bin/php
<?php

/* Bongo Project licensing applies to this file, see COPYING
 * (C) 2007 Alex Hudson
 * LDAP Extension - Written by Steve Hall
 */

/* LDAPAuth.php
 * User authentication API - LDAP Extension
 *
 * Exit Code 0: True
 * Exit Code 1: False
 * Exit Code 2: Error
 *
 * Usage: <script> "<method>" ["<arguments>"...]
 * Methods: MsgAuthFindUser, MsgAuthVerifyPassword
 *
 * Filter Macros: <USER>,<DOMAIN>,<u...@domain>
 *
 * Requires: #!/usr/bin/php will need to be customized
 * for the target system.
 *
 * Requires: You will need to get and compile LDAP client
 * libraries from either » OpenLDAP or » Bind9.net in order
 * to compile PHP with LDAP support.
 *
 */


    // Configuration
    $config = Array();
    $config["log"] = true;
    $config["hostname"] = "localhost";
    $config["port"] = 389;
    $config["proto"] = 3;
    $config["anon"] = false;
    $config["bdn"] = "cn=admin,o=bongo";
    $config["bpass"] = "password";
    $config["base"] = "o=bongo";
    $config["filter"] =
"(&(objectclass=person)(cn=<USER>)(mail=<u...@domain>))";
   
   
/* MAIN BEGIN */   
   
    // Parse and Call Requested Function or Die
    $exitCode = 0;
    if(isset($argc) && $argc > 1) {
        // Script Called With Method
        echoOut($config, "Script called with method: '" . $argv[1] . "'");
        // Switch on method argument
        switch($argv[1]) {
            case "MsgAuthFindUser":
                // Method Identified
                echoOut($config, "Method identified as:
'MsgAuthFindUser'");           
                if($argc > 2) {
                    // Script Called With Argument
                    echoOut($config, "Script called with argument: '" .
$argv[2] . "'");
                    // Find User
                    mergeFilter($config, $argv[2]);
                    $exitCode = MsgAuthFindUser($config, $argv[2]);
                }
                else {
                    // Script Called Without Required Arguments
                    echoOut($config, "Script called without required
argument(s)");
                    $exitCode = 2;
                }
                break;
            case "MsgAuthVerifyPassword":
                // Method Identified
                echoOut($config, "Method identified as:
'MsgAuthVerifyPassword'");
                if($argc > 3) {
                    // Script Called With Argument
                    echoOut($config, "Script called with argument: '" .
$argv[2] . "'");
                    echoOut($config, "Script called with argument: '" .
$argv[3] . "'");
                    // Verify Password
                    mergeFilter($config, $argv[2]);
                    $exitCode = MsgAuthVerifyPassword($config, $argv[2],
$argv[3]);
                }
                else {
                    // Script Called Without Required Arguments
                    echoOut($config, "Script called without required
argument(s)");
                    $exitCode = 2;
                }
                break;
            default:
                // Script Called Without Matching Method
                echoOut($config, "Script called without matching method");
                $exitCode = 2;
        }
    }
    else {
        // Script Called With Improper Usage
        echoOut($config, "Script called with improper usage... Usage:
<script> <method> <argument> ...");
        $exitCode = 2;
    }
    // Terminate With Exit Code
    echoOut($config, "Script terminating with exit code: '" . $exitCode
. "'");
    exit($exitCode);
   
/* MAIN END */
   
   
/* FUNCTIONS BEGIN */

    // Determine whether or not a user exists in directory
    function MsgAuthFindUser($config = null, $user = null) {
        if($config != null && $user != null) {
            $conn = getConnection($config);
            if($conn !== false) {
                $entry = getEntry($config, $conn, $user);
                if($entry !== false) {
                    // Close Connection and Return
                    echoOut($config, "Closing connection");
                    ldap_close($conn);
                    return 0;
                }
                else {
                    // Close Connection and Return
                    echoOut($config, "Closing connection");
                    ldap_close($conn);
                    return 1;
                }
            }
            else {
                return 2;
            }
        }
        else {
            return 2;
        }
    }
   
   
    // Verify that the password given actually belongs to the user
    function MsgAuthVerifyPassword($config = null, $user = null,
$password = null) {
        if($config != null && $user != null && $password != null) {
            $conn = getConnection($config);
            if($conn !== false) {
                $entry = getEntry($config, $conn, $user);
                if($entry !== false) {
                    // Grab entry attributes
                    //$attributes = ldap_get_attributes($conn, $entry);
                    $dn = ldap_get_dn($conn, $entry);
                    // Close Prior Connection
                    echoOut($config, "Closing prior connection");
                    ldap_close($conn);
                    // Authenticate user via bind
                    $conn = getConnection($config, $dn, $password);
                    if($conn !== false) {
                        // Close Connection and Return
                        echoOut($config, "Closing connection");
                        ldap_close($conn);
                        return 0;
                    }
                    else {
                        if($conn != null) {
                            // Close Connection and Return
                            echoOut($config, "Closing connection");
                            ldap_close($conn);
                        }
                        return 1;
                    }
                }
                else {
                    // Close Connection and Return
                    echoOut($config, "Closing connection");
                    ldap_close($conn);
                    return 1;
                }
            }
            else {
                return 2;
            }
        }
        else {
            return 2;
        }
    }
   
   
    // Get and return LDAP bound connection resource
    function getConnection($config = null, $bdn = null, $bpass = null) {
        if($config != null) {
            // Attempting LDAP Connection
            echoOut($config, "Attempting LDAP connection");
            // Get connection
            echoOut($config, "Connection hostname: '" .
$config["hostname"] . "'");
            echoOut($config, "Connection port: '" . $config["port"] . "'");
            $conn = ldap_connect($config["hostname"], $config["port"]);
            if($conn !== false) {
                // Connection Successful
                echoOut($config, "Connection successful; setting options");
                ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION,
$config["proto"]);
                // Attempting LDAP Bind
                echoOut($config, "Attempting LDAP bind");
                if($config["anon"] === false) {
                    // Authenticated Bind
                    if($bdn != null && $bpass != null) {
                        echoOut($config, "Bind DN: '" . $bdn . "'");
                        echoOut($config, "Bind Pass: '" . $bpass . "'");
                        $connBind = @ldap_bind($conn, $bdn, $bpass);
                    }
                    else {
                        echoOut($config, "Bind DN: '" . $config["bdn"] .
"'");
                        echoOut($config, "Bind Pass: '"
.$config["bpass"] . "'");
                        $connBind = @ldap_bind($conn, $config["bdn"],
$config["bpass"]);
                    }
                }
                else {
                    // Anonymous Bind
                    $connBind = ldap_bind($conn);
                }
                if($connBind != null && $connBind !== false) {
                    // Bind Successful
                    echoOut($config, "Bind successful");
                    return $conn;
                }
                else {
                    // Bind Failed
                    echoOut($config, "Bind failed");
                    echoOut($config, "Closing connection");
                    ldap_close($conn);
                    return false;
                }
            }
            else {
                // Connection Failed
                echoOut($config, "Connection failed");
                return false;
            }
        }
        else {
            return false;
        }
    }
   
   
    // Get and return LDAP entry resource
    function getEntry($config, $conn, $user) {
        // Searching Entries
        echoOut($config, "Searching entries");
        if($config != null) {
            $entries = ldap_search($conn, $config["base"],
$config["filter"]);
            if($entries !== false && ldap_count_entries($conn, $entries)
!= 0) {
                // Entry(s) found
                echoOut($config, "Entry(s) found: " .
ldap_count_entries($conn, $entries));
                return ldap_first_entry($conn, $entries);
            }
            else {
                // No entries found
                echoOut($config, "No entries found");
                return false;
            }
        }
        else {
            return false;
        }
    }
   
   
    // Merge the filter and macros
    function mergeFilter(&$config, $user) {
        $userParts = explode("@", $user);
        if(count($userParts) == 1) {
            $config["filter"] = str_replace("<USER>", $userParts[0],
$config["filter"]);
        }
        if(count($userParts) == 2) {
            $config["filter"] = str_replace("<USER>", $userParts[0],
$config["filter"]);
            $config["filter"] = str_replace("<DOMAIN>", $userParts[1],
$config["filter"]);
            $config["filter"] = str_replace("<u...@domain>",
$userParts[0] . "@" . $userParts[1], $config["filter"]);
        }
        // Merged Filter
        echoOut($config, "Merged filter: '" . $config["filter"] . "'");
    }
   
   
    // Log to StdOut
    function echoOut($config, $msg) {
        // Echo Out if Config Allows
        if($config["log"] === true) {
            echo($msg . "!\n");
        }
    }
   
/* FUNCTIONS END */

?>


Regards,

-- 

Steve Hall
Email: [email protected]
Web: http://www.coop7.com


<<attachment: LDAPAuth.php>>

_______________________________________________
Bongo-devel mailing list
[email protected]
https://mail.gna.org/listinfo/bongo-devel

Reply via email to