[horde] Problems with PASSWD and LDAP

Andy Dorman adorman at ironicdesign.com
Thu Jan 21 14:39:45 UTC 2016


On 01/21/2016 07:56 AM, Jan Schneider wrote:
> Zitat von David Cunningham <dcunningham at additionnetworks.net>:
>
>> Here is a further follow up…
>>
>> This works:
>>
>> <?php
>> $backends['ldap'] = array(
>>     'disabled' => false,
>>     'name' => 'Courier Mail Server',
>>     'preferred' =>
>> 'courier.additionnetworks.net<http://courier.additionnetworks.net>',
>>     'driver' => 'Ldap',
>>     'policy' => array(
>>         'minLength' => 6,
>>         'minNumeric' => 1,
>>     ),
>>     'params' => array(
>>         'host' =>
>> 'courier.additionnetworks.net<http://courier.additionnetworks.net>',
>>         'port' => 389,
>>         'basedn' =>
>> 'ou=test.mecnet.net<http://test.mecnet.net>,ou=customers,dc=mecnet,dc=net',
>>
>>         // LDAP object key attribute.
>>         'uid' => 'uid',
>>         // The attribute storing the password.
>>         //'attribute' => 'Password',
>>         // These attributes will enable shadow password policies.
>>         // 'shadowlastchange' => 'shadowLastChange',
>>         // 'shadowmin' => 'shadowMin',
>>         // This will be appended to the username when looking for the
>> userdn.
>>         //'realm' => '',
>>         // Use this filter when searching for the user's DN.
>>         //'filter' => 'uid',
>>         // Hash method to use when storing the password
>>         'encryption' => 'crypt',
>>         // Whether to enable TLS for this LDAP connection
>>         // Note: make sure that the host matches cn in the server
>> certificate.
>>         'tls' => false,
>>         // Determine the user's DN. %u will be replaced by the user's ID.
>>         // Alternatively, disable this option and instead use the
>> 'userdn'
>>         // hook (config/hooks.php) to dynamically set the userdn.
>>         //'userdn' => 'uid=%u,ou=%d,ou=customers,dc=mecnet,dc=net'
>>     ),
>> );
>>
>>
>> But!!!  I cannot do that… I need the domain name (IE,
>> test.mecnet.net<http://test.mecnet.net> in this example) to be dynamic
>> as I have dozens of different domains logging in.  This user is
>> dcunningham at test.mecnet.net<mailto:dcunningham at test.mecnet.net>.  I
>> need that OU to be dynamic.  It says that %d should be replaced with
>> the domain, but it does not work.  When searching the code, I do not
>> see a str_replace for %d… just %u.
>
> And it doesn't say that anywhere either. No idea where you got that
> information from.
>
>> Dave
>>
>>
>>
>>
>> On Jan 20, 2016, at 8:38 AM, David Cunningham
>> <dcunningham at additionnetworks.net<mailto:dcunningham at additionnetworks.net>>
>> wrote:
>>
>> Hi All, especially Jan,
>>
>> I never received a follow-up to this.  Can you help?
>>
>> Dave
>>
>>
>>
>> On Jan 14, 2016, at 3:49 PM, David Cunningham
>> <dcunningham at additionnetworks.net<mailto:dcunningham at additionnetworks.net>>
>> wrote:
>>
>>   {
>>       // Example: Provide LDAP server with a userdn so that you do not
>>       // have to perform anonymous binds.
>>       return 'uid=' . $authid .
>> ',ou=$domain,ou=customers,dc=mecnet,dc=net';
>>   }
>
> You need to parse the domain from the username. If $authid doesn't
> contain the domain, you need to get it from somewhere else.
>

We use OpenLDAP with a master write server and several replica dbs 
hosted on each Horde/Imp web server and we use Imp for our authentication.

Below is our code in imp/config/hooks.local.php for checking credentials 
and fetching and setting the IMAP server name.  It may be more complex 
than you would need for a single server hosting Horde and LDAP.

FWIW we also support multiple domains, so we manually build the dn 
ourselves with this line in the code below:

$dn = 'uid=' . $userId . ',ou=addresses,o=antespam.com';

Hope it helps.

* 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)
{
     Horde::log (sprintf ('In preauthenticate hook for: %s', $userId), 
'DEBUG');
     if ($userId && $credentials['authMethod'] == 'authenticate') {

         // set IMAP server based on sideline server value saved in LDAP 
for username
         $dn = 'uid=' . $userId . ',ou=addresses,o=antespam.com';
         $ldappass = $credentials['password'];
         $justthese = array ("asSidelineServer");
         $ldapPort = '389';

         // connect to local ldap server to read
         $ldapRead = ldap_connect ('localhost', $ldapPort)
           or die ("Could not connect to LDAP server.");

         // must manually set the version 3 protocol
         @ldap_set_option ($ldapRead, LDAP_OPT_PROTOCOL_VERSION,3);

         // bind to ldap server and search for assidelineserver
         $ldapReadBind = @ldap_bind ($ldapRead, $dn, $ldappass);

         if ($ldapReadBind) {
             $searchResult = @ldap_search ($ldapRead, $dn, 
'(objectClass=fmAddress)', $justthese);
             if ($searchResult) {
                 $information = @ldap_get_entries ($ldapRead, 
$searchResult);

                 if (isset ($information[0]["assidelineserver"][0])) {
                     $credentials['server'] = 
$information[0]["assidelineserver"][0];
                     Horde::log (sprintf ('Setting preauth hook hostname 
"%s" from client [%s]', $credentials['server'], 
$_SERVER['REMOTE_ADDR']), 'DEBUG');
                     @ldap_close ($ldapRead);
                     return array(
                         'credentials' => $credentials,
                         'userId' => $userId
                     );
                 } else {
                     Horde::log (sprintf ('Unable to find hostname for 
dn: %s', $dn), 'ERR');
                 }
             } else {
                 Horde::log (sprintf ('Problem with search for dn: %s , 
the error was %s', $dn, ldap_error($ldapRead)), 'ERR');
             }
         } else {
             Horde::log (sprintf ('Unable to bind to LDAP on localhost 
for user: %s with dn: %s and password %s, the error was %s', $userId, 
$dn, $ldappass, ldap_error ($ldapRead)), 'ERR');
         }
         return true;
     }
}

Good luck!

-- 
Andy Dorman



More information about the horde mailing list