[horde] new cyrus/sql driver for admin/users

Ilya mail at krel.org
Mon Sep 2 00:25:53 PDT 2002


this is a driver for cyrus-imap with sql backend, derrived from sql driver. It
allows to:
1 create mailboxes (will create automatically saved, trash, sent-items (could be
customizable in future, if it will be included in cvs))
2 delete mailboxes (will set correct acl for deletion)
3 everything else sql driver can do.

In order to use this driver you need following entries in your
horde/config/conf.php:

// This is the cyrsql driver for managing cyrus users which are based in sql db
// You need to change horde/admin/user.php as following:
//-$auth = &Auth::factory($conf['auth']['driver'], $conf['auth']['params']);
//+$auth = &Auth::factory($conf['users']['driver'], $conf['users']['params']);

$conf['users']['driver'] = 'cyrsql';
$conf['users']['params']['phptype'] = 'mysql';
$conf['users']['params']['hostspec'] = 'localhost.alchemistry.net'; //sql
hostname
$conf['users']['params']['protocol'] = 'tcp';
$conf['users']['params']['username'] = 'sqluser'; //sql username
$conf['users']['params']['password'] = 'sqlpassword'; //sql password
$conf['users']['params']['database'] = 'database'; //sql database
$conf['users']['params']['cyradmin'] = 'cyrus_admin'; //imap admin username
$conf['users']['params']['cyrpass'] = 'cyrus_password'; //imap admin password
$conf['users']['params']['imaps'] = '{localhost:993/imap/ssl/novalidate-cert}';
//imap server
$conf['users']['params']['table'] = 'users'; //sql table to use
$conf['users']['params']['users'] = 'user'; //sql field with usernames
$conf['users']['params']['passwords'] = 'password'; //sql field with passwords


on my wish list is: allow changing the password for other users, warning window
before delete ;)


Chuck, let me know if you think it can be added in cvs

-------------- next part --------------
<?php
/**
 * The Auth_cyrsql class provides a sql implementation of the Horde
 * authentication system for Cyrus IMAP server.
 *
 * Required values for $params:
 *   'phptype'       The database type (ie. 'pgsql', 'mysql, etc.).
 *   'hostspec'      The hostname of the database server.
 *   'protocol'      The communication protocol ('tcp', 'unix', etc.).
 *   'username'      The username with which to connect to the database.
 *   'password'      The password associated with 'username'.
 *   'database'      The name of the database.
 *   'cyradmin'      The username of cyrus administrator
 *   'cyrpass'       The password associated woth cyrus administrator
 *   'impas' 	     The full imap hostname (ie {localhost:993/imap/ssl/novalidate-cert} )
 *
 * Optional values:
 *   'table'         The name of the auth table in 'database'. Defaults to
 *                   'horde_users'.
 *   'users'         The name of the username filed in auth table in 'database'.
 *   'passwords'     The name of the passwords field in auth table in 'database'. Defaults to
 *
 * Required by some database implementations:
 *   'options'       Additional options to pass to the database.
 *   'tty'           The TTY on which to connect to the database.
 *   'port'          The port on which to connect to the database.
 *
 * The table structure for the auth system is as follows:
 *
 *  create table horde_users (
 *      user_uid        varchar(255) not null,
 *      user_pass       varchar(255) not null,
 *      primary key (user)
 *  );
 *
 * $Horde: horde/lib/Auth/sql.php,v 1.33 2002/08/12 23:59:36 chuck Exp $
 *
 * Copyright 1999-2002 Chuck Hagenbuch <chuck at horde.org>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Chuck Hagenbuch <chuck at horde.org>
 * @version $Revision: 1.33 $
 * @since   Horde 1.3
 * @package horde.auth
 */
class Auth_cyrsql extends Auth {

    /**
     * An array of capabilities, so that the driver can report which
     * operations it supports and which it doesn't.
     *
     * @var array $capabilities
     */
    var $capabilities = array('add'         => true,
                              'update'      => true,
                              'remove'      => true,
                              'list'        => true,
                              'transparent' => false,
                              'loginscreen' => false);

    /**
     * Hash containing connection parameters.
     *
     * @var array $_params
     */
    var $_params = array();

    /**
     * Handle for the current database connection.
     *
     * @var object DB $_db
     */
    var $_db;
    
	/**
     * Handle for the current imap connection.
     *
     */
    var $_mbox;

    /**
     * Boolean indicating whether or not we're connected to the SQL server.
     *
     * @var boolean $connected
     */
    var $_connected = false;


    /**
     * Constructs a new SQL authentication object.
     *
     * @access public
     *
     * @param optional array $params  A hash containing connection parameters.
     */
    function Auth_cyrsql($params = array())
    {
        $this->_params = $params;
    }

    /**
     * Find out if a set of login credentials are valid.
     *
     * @access private
     *
     * @param string $userID      The userID to check.
     * @param array $credentials  The credentials to use.
     *
     * @return boolean  Whether or not the credentials are valid.
     */
    function _authenticate($userID, $credentials)
    {
        /* _connect() will die with Horde::fatal() upon failure. */
        $this->_connect();

        /* Build the SQL query. */
        $query = 'SELECT ' . $this->_params['users']  . ' FROM ' . $this->_params['table'];
        $query .= ' WHERE ' . $this->_params['users'] . ' = ' . $this->_db->quote($userID);
        $query .= ' AND ' . $this->_params['passwords'] . ' = ' . $this->_db->quote(md5($credentials['password']));

        /* Execute the query. */
        $result = $this->_db->query($query);

        if (!DB::isError($result)) {
            $row = $result->fetchRow(DB_GETMODE_ASSOC);
            if (is_array($row)) {
                $result->free();
                return true;
            } else {
                $result->free();
                $this->_setAuthError();
                return false;
            }
        } else {
            $this->_setAuthError();
            return false;
        }
    }

    /**
     * Add a set of authentication credentials.
     *
     * @access public
     *
     * @param string $userID      The userID to add.
     * @param array $credentials  The credentials to add.
     *
     * @return mixed  True on success or a PEAR_Error object on failure.
     */
    function addUser($userID, $credentials)
    {
        /* _connect() will die with Horde::fatal() upon failure. */
        $this->_connect();

        /* Build the SQL query. */
        $query = 'INSERT INTO ' . $this->_params['table'] . ' (' . $this->_params['users'] . ', ' . $this->_params['passwords'] . ') ';
        $query .= 'VALUES (' . $this->_db->quote($userID) . ', ' . $this->_db->quote(md5($credentials['password'])) . ')';

        /* Execute the query. */
        $result = $this->_db->query($query);

		$name = imap_utf7_encode("$userID");
		if(@imap_createmailbox($this->_mbox,imap_utf7_encode($this->_params['imaps'] . "user.$name"))) {
			@imap_createmailbox($this->_mbox,imap_utf7_encode($this->_params['imaps'] . "user.$name.saved"));
			@imap_createmailbox($this->_mbox,imap_utf7_encode($this->_params['imaps'] . "user.$name.sent-mail"));
			@imap_createmailbox($this->_mbox,imap_utf7_encode($this->_params['imaps'] . "user.$name.drafts"));
			@imap_createmailbox($this->_mbox,imap_utf7_encode($this->_params['imaps'] . "user.$name.trash"));
		} else {
			Horde::logMessage("imap mailbox create failed ", __FILE__, __LINE__, LOG_DEBUG);
            return (new PEAR_Error(_("Database query failed.")));
		}
        if ($result !== DB_OK) {
            return (new PEAR_Error(_("Database query failed.")));
        }

        return true;
    }

    /**
     * Update a set of authentication credentials.
     *
     * @access public
     *
     * @param string $oldID       The old userID.
     * @param string $newID       The new userID.
     * @param array $credentials  The new credentials
     *
     * @return mixed  True on success or a PEAR_Error object on failure.
     */
    function updateUser($oldID, $newID, $credentials)
    {
        /* _connect() will die with Horde::fatal() upon failure. */
        $this->_connect();

        /* Build the SQL query. */
        $query = 'UPDATE ' . $this->_params['table'] . ' SET ' . $this->_params['users'] . ' = ' . $this->_db->quote($newID) . ', ' . $this->_params['passwords'] . ' = ' . $this->_db->quote(md5($credentials['password']));
        $query .= 'WHERE ' . $this->_params['users'] . ' = ' . $this->_db->quote($oldID);

        /* Execute the query. */
        $result = $this->_db->query($query);

        if ($result !== DB_OK) {
            return (new PEAR_Error(_("Database query failed.")));
        }

        return true;
    }

    /**
     * Delete a set of authentication credentials.
     *
     * @access public
     *
     * @param string $userID  The userID to delete.
     *
     * @return boolean        Success or failure.
     */
    function removeUser($userID)
    {
        /* _connect() will die with Horde::fatal() upon failure. */
        $this->_connect();

        /* Build the SQL query. */
        $query = 'DELETE FROM ' . $this->_params['table'];
        $query .= ' WHERE ' . $this->_params['users'] . ' = ' . $this->_db->quote($userID);

        /* Execute the query. */
        $result = $this->_db->query($query);

		/* Set acl for deletion */
		imap_setacl ( $this->_mbox, "user.$userID", "cyradmin", "lrswipcda");

		/*Delete imap mailbox */
		$resulti = imap_deletemailbox ( $this->_mbox, $this->_params['imaps'] . "user.$userID");

        if ($result !== DB_OK || $resulti !== 1) {
            return (new PEAR_Error(_("Database query failed.")));
        }

        return true;
    }

    /**
     * List all users in the system.
     *
     * @access public
     *
     * @return mixed  The array of userIDs, or false on failure/unsupported.
     */
    function listUsers()
    {
        /* _connect() will die with Horde::fatal() upon failure. */
        $this->_connect();

        /* Build the SQL query. */
        $query = 'SELECT ' . $this->_params['users'] . ' from ' . $this->_params['table'];

        /* Execute the query. */
        $result = $this->_db->getAll($query, null, DB_FETCHMODE_ORDERED);
        if (PEAR::isError($result)) {
            return $result;
        }

        /* Loop through and build return value. */
        $users = array();
        foreach ($result as $ar) {
            $users[] = $ar[0];
        }

        return $users;
    }

    /**
     * Attempts to open a persistent connection to the SQL server.
     *
     * @access private
     *
     * @return mixed  True on success or a PEAR_Error object on failure.
     */
    function _connect()
    {
        if (!$this->_connected) {
            if (!is_array($this->_params)) {
                Horde::fatal(new PEAR_Error(_("No configuration information specified for SQL authentication.")), __FILE__, __LINE__);
            }
            if (!isset($this->_params['phptype'])) {
                Horde::fatal(new PEAR_Error(_("Required 'phptype' not specified in authentication configuration.")), __FILE__, __LINE__);
            }
            if (!isset($this->_params['hostspec'])) {
                Horde::fatal(new PEAR_Error(_("Required 'hostspec' not specified in authentication configuration.")), __FILE__, __LINE__);
            }
            if (!isset($this->_params['username'])) {
                Horde::fatal(new PEAR_Error(_("Required 'username' not specified in authentication configuration.")), __FILE__, __LINE__);
            }
            if (!isset($this->_params['password'])) {
                Horde::fatal(new PEAR_Error(_("Required 'password' not specified in authentication configuration.")), __FILE__, __LINE__);
            }
            if (!isset($this->_params['database'])) {
                Horde::fatal(new PEAR_Error(_("Required 'database' not specified in authentication configuration.")), __FILE__, __LINE__);
            }
            if (!array_key_exists('table', $this->_params)) {
                $this->_params['table'] = 'horde_users';
            }

            /* Connect to the SQL server using the supplied parameters. */
            include_once 'DB.php';
            $this->_db = &DB::connect($this->_params, true);
            if (DB::isError($this->_db)) {
                Horde::fatal(new PEAR_Error(_("Unable to connect to SQL server.")), __FILE__, __LINE__);
            }

            /* Enable the "portability" option. */
            $this->_db->setOption('optimize', 'portability');


			$this->_mbox = imap_open($this->_params['imaps'],$this->_params['cyradmin'],$this->_params['cyrpass'],OP_HALFOPEN)
     		or die("can't connect: ".imap_last_error());
            $this->_connected = true;
        }

        return true;
    }

    /**
     * Disconnect from the SQL server and clean up the connection.
     *
     * @access private
     *
     * @return boolean  True on success, false on failure.
     */
    function _disconnect()
    {
        if ($this->_connected) {
            $this->_connected = false;
            return $this->_db->disconnect();
			imap_close();
        }

        return true;
    }

}


More information about the horde mailing list