[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