[commits] [Wiki] changed: ImapSelect

Jan Schneider jan at horde.org
Wed Sep 4 09:36:30 UTC 2013


jan  Wed, 04 Sep 2013 09:36:30 +0000

Modified page: http://wiki.horde.org/ImapSelect
New Revision:  14
Change log:  Strip down to what is currently valid

@@ -1,195 +1,45 @@
  + Dynamically selecting an IMAP server for authentication

-++ Introduction
+**##red|This information is valid for Horde 5 or later only. See  
ImapSelectH4 for Horde 4 or ImapSelectH3 for Horde 3.##**

-During a migration from one IMAP server to another, the need arose to  
run both the old and the new IMAP servers in parallel. By default,  
Horde only allows a single primary server to be enabled in  
servers.php. Of course, we could have allowed our users to simply  
select their server by enabling IMAP server selection, but there is a  
better way.
-The first example shows a way using a !MySQL backend to select an  
IMAP server for authentication, given a username.
-The second example instead uses the realmed username to select the  
IMAP server \
-(i.e. the username used by Horde internally to prevent username clashes).
-----
-
-++ The SQL table
-
-There are many ways to do this of course. In this example, we'll just  
be using a table with two rows:
-
-<code>
----------------------------------------------------------
-|   username        |     cyrus                         |
----------------------------------------------------------
-</code>
-
-Your table can be constructed however you like. It can even be a part  
of your existing Horde DB. The important point is that you need the  
table to be constructed in such a way as to be able to query a  
username and have the lookup return a server name from  
{{imp/config/servers.php}}.
-
-++ Writing a hook
-
-Here's some sample code for a hook placed inside horde/config/hooks.php:
+For Horde 5 or later there already exists an example hook for dynamic  
IMAP server selection in IMP (imp/config/hooks.php.dist). For the sake  
of completeness, here is a stripped down copy of the example:

-<code type="php">
-if (!function_exists('_horde_hook_preauthenticate')) {
-    function _horde_hook_preauthenticate($userID, $credential, $realm)
-    {
-        require dirname(__FILE__) . '/../imp/config/servers.php';
-
-        // Strip domain part from user.
-        $userID = substr($userID, 0, strpos($userID, '@'));
-        // Connect to database server.
-        $db = mysql_connect('hostname', 'dbuser', 'dbpasswd') or  
die('Can not connect to database.');
-        // Select database.
-        mysql_select_db('dbname') or die('Can not select database.');
-        // Execute the query
-        $sth = mysql_query('SELECT server_name FROM users WHERE  
user=\'' . mysql_real_escape_string($userID) . '\'') or die ('Can not  
query database.');
-        // Fetch the server name.
-        $server = mysql_fetch_row($sth);
-        if ($server === false) {
-            die('Can not read user from database.');
-        }
-
-        // Set IMAP server values.
-        foreach (array('server', 'folders', 'namespace') as $key) {
-            $_SESSION['imp'][$key] = $servers[$server[0]][$key];
-        }
-
-        return true;
-    }
-}
-
-</code>
-
-All that's left to do, is to activate the preauthenticate hook in  
Horde's configuration.
-----
-
-++ IMAP server selection by realmed username
-+++ Requirements
-* IMP is used to do the authentication
-* The usernames to authenticate against the mailserver may not have a  
domain part (separated with '@' from the username).
-* There is more than one active server entry in {{imp/config/servers.php}}. _
- The realm values are different and the default server has an empty  
string as realm. _
- //**Note:**// The default server is either the first server entry in  
the list or the one with the **preferred** value _
- set.
-* Realm values are only lowercase strings (e.g. 'server1.example.com').
-
-++++ Examplary snippet of {{imp/config/servers.php}}
-<code>/* Example configuration: */
-
-$servers['imap'] = array(
-    'name' => 'IMAP Server',
-    'server' => 'imap.example.com',
-    'hordeauth' => true,
-    'protocol' => 'imap/notls',
-    'port' => 143,
-    'maildomain' => 'example.com',
-    'smtphost' => 'smtp.example.com',
-    'smtpport' => 25,
-    'realm' => '',
-    'preferred' => '',
-);
-
-$servers['imap1'] = array(
-    'name' => 'IMAP Server 1',
-    'server' => 'imap1.example.com',
-    'hordeauth' => true,
-    'protocol' => 'imap/ssl/novalidate-cert',
-    'port' => 993,
-    'maildomain' => 'example.com',
-    'smtphost' => 'smtp.example.com',
-    'smtpport' => 25,
-    'realm' => 'imap1.example.com',
-    'preferred' => '',
-);
-</code>
-
-++++ Functionality of the hook
-Entering the username {{smith}} in the login screen selects the  
necessary values given by {{$servers['imap']}}:
-* Authentication against {{imap.example.com}}
-* using protocol {{imap/notls}}
-* ...
-
-Entering the username {{smith at imap1.example.com}} instead selects the  
values of {{$servers['imap1']}}:
-* Authentication against {{imap1.example.com}}
-* using protocol {{imap/ssl/novalidate-cert}}
-* ...
-
-//**Note:**//
-* Horde treats them as different users with their own preferences.
-* The selection of the server is done by the **realm** value **NOT**  
by the **server** value.
-
-+++ The Preauthenticate-Hook
-The following hook has to be inserted in {{config/hooks.php}}:
-<code type="php">if (!function_exists('_horde_hook_preauthenticate')) {
-    function _horde_hook_preauthenticate($userID, $credential, $realm)
-    {
-        require dirname(__FILE__) . '/../imp/config/servers.php';
-
-        // Convert all to lower chars (even the possible domain part)
-        $userID=strtolower($userID);
-        // Strip domain part from user, if it exists.
-        if (($domainpart = strpos($userID, '@'))) {
-          $server=substr($userID, $domainpart+1);
-          $userID=substr($userID, 0, $domainpart);
-          // Change the values only if a domain part was found ...
-          if (!empty($server)) {
-            foreach ($servers as $serverkey => $curServer) {
-              if (!empty($curServer['realm']) && $server ==  
$curServer['realm']) {
-                // We found an entry, now set IMAP server values.
-                foreach (array('server', 'folders', 'namespace',
-                  'protocol', 'port', 'smtphost', 'smtpport',  
'maildomain') as $key) {
-                  if (isset($servers[$serverkey][$key])) {
-                    $_SESSION['imp'][$key] = $servers[$serverkey][$key];
-                  }
-                }
-                // Now use only the stripped version of the userID to  
logon to the server
-                $_SESSION['imp']['user'] = $userID;
-                // Setup the correct base_protocol
-                $_SESSION['imp']['base_protocol'] =  
$_SESSION['imp']['protocol'];
-                if (($pos = strpos($_SESSION['imp']['protocol'], '/'))) {
-                  $_SESSION['imp']['base_protocol'] =  
substr($_SESSION['imp']['protocol'], 0, $pos);
-                }
-              }
-            }
-          }
-        }
-        return true;
-    }
-}
-</code>
-
-Like in the first example, the hook has to be activated inside  
{{config/conf.php}}.
-* Either use the administration user interface of Horde (recommended)
-* or set the following entry in {{config/conf.php}} with your favorite editor
-<code>...
-$conf['hooks']['preauthenticate'] = true;
-...
-</code>
-
-++ The same IMAP server selector hook function in Hode 4  
{{imp/config/hooks.php}}
  <code type="php">
  class IMP_Hooks
  {
-
-public function preauthenticate($userId, $credentials)
-{
-    //Horde::logMessage('authM: '.$credentials['authMethod'].'  
id='.$userId, 'ERROR');
-    //return true;
-
-    /* when no userId given */
-    if (empty($userId)) return true;
-
-    /* list of ALL remote users */
-    $remote_users = array('username at remoteserver.hu' =>  
'remote-imap-servers-key');
-
-    /* local user */
-    if (!array_key_exists($userId, $remote_users)) return true;
-
-    /* remote user */
-    return array('credentials' => array('server' => $remote_users[$userId],
-                                        'transparent' => true,
-                                        'password' =>  
$GLOBALS['registry']->getAuthCredential('password')
-                                  )
-    );
-}
-
+    /**
+     * AUTHENTICATION HOOK: pre-authentication actions.
+     *
+     * See horde/config/hooks.php.dist for more information.
+     *
+     * IMP uses the following credentials:
+     *   - password: (string) The password for mail server authentication.
+     *   - server: (string) [optional] Use this server key (see
+     *             config/backends.php).
+     *   - transparent: (boolean) If $credentials['authMethod'] is
+     *                  'transparent', and you want IMP to use the
+     *                  userId/credentials generated in the preauthenticate
+     *                  hook, this must be true. If false, IMP will instead
+     *                  try to authenticate using hordeauth.
+     *
+     * The following credentials will exist in $credentials, but changing
+     * these values has no effect on authentication:
+     *   - imp_server_key: (string; 'authenticate' only) The backend server
+     *                     key selected on the login page.
+     */
+     public function preauthenticate($userId, $credentials)
+     {
+         if ($credentials['authMethod'] == 'authenticate') {
+             // Example: Load-balance - pick IMAP server based on first
+             // letter in username. Server entries 'server_[a-z]' must
+             // be defined in config/backends.local.php.
+             $credentials['server'] = 'server_' . substr($userId, 0, 1);
+             return array(
+                 'credentials' => $credentials,
+                 'userId' => $userId
+             );
+         }
+         return true;
+    }
  }
  </code>
-
-Set server list to 'hidden' in Imp prefs, and all backend's hordeauth  
to full.
-



More information about the commits mailing list