Roundcube Community Forum

 

Ldap authentication + identity with ldap fields

Started by jfsenechal, February 17, 2011, 08:58:55 AM

Previous topic - Next topic

jfsenechal

Hello,

Because ldap plugins are obsolete
Plugin_Repository ? Roundcube Webmail

I have rewrite the plugin ldap_authentication for round 0.5

So I share with you

this is a beta version, be cool with this ;)


<?php
//config.inc.php

/* 17/02/2011 -
 Get users/identities from an LDAP directory
 Inspired by plugin ldap_authentication  
*/

$rcmail_config['ldap_hostname'] = 'ldap.domain.be';
$rcmail_config['ldap_bind_username'] = '';
$rcmail_config['ldap_bind_password'] = '';
$rcmail_config['ldap_base_dn'] = 'ou=Users,ou=Group,dc=domain,dc=be';

$rcmail_config['use_tls'] = false;
//does check bind ldap with username and password given by user ?
$rcmail_config['use_authentication'] = false;

// %u is the query for login user (or email!)
$rcmail_config['ldap_filter'] = 'uid=%u';

/*
* field for create user
*/

$rcmail_config['ldap_create_uid'] = 'uid';
#if more one element, merge the 2 fields
$rcmail_config['ldap_create_name'] = array('cn','sn'); #can array(givenName)
$rcmail_config['ldap_create_email'] = 'mail';

?>


jfsenechal

Grrrrrrrrrrrrr

Tooo short maximum characters ! :mad:

jfsenechal

My class in two thread :mad:

<?php

/**
* LDAP Authentication
*
* This plugin replaces the RoundCube login page with authentication requests
* to a LDAP server, which enables logging into RoundCube with identities
* authenticated by the LDAP server
*
* @version 0.1
* @author jf
*
*/
class ldap_authentication extends rcube_plugin {
   
/*
    * Connection and bind default variables
    *
    * @var mixed
    * @var mixed
    */

   
private $ldap_inited = false;
   private
$_conn = false;
   private
$_bind = false;
   protected
$_use_tls = false;
   protected
$_ldap_bind_username = NULL;
   protected
$_ldap_bind_password = NULL;
   protected
$_use_authentication = false;
   protected
$_base_dn = &quot;DC=mydomain,DC=local&quot;;
   protected
$_ldap_hostname = &quot;ldap.mydomain.be&quot;;

   
/**
    * Initialize plugin
    *
    */
   
function init() {

       
$ldap_inited = false;

       
// load plugin configurations
       
$this->load_config();
       
       
// add application hooks
       
$this->add_hook('authenticate', array($this, 'authenticate'));
       
$this->add_hook('user_create', array($this, 'user_create'));
       
$this->add_hook('login_failed', array($this, 'login_failed'));
   }

   
/**
    * Inject authentication credentials
    *
    * @param array $args arguments from rcmail
    * @return array modified arguments
    */
   
function authenticate($args) {

       
// retrieve configurations
       
$rcmail = rcmail::get_instance();
       
$cfg = $rcmail->config->all();

       
// initialize ldap client
       
$this->ldap_init($cfg);
       
       
/*
        * if you want to check ldap user valid
        */
       
       
if ($this->_use_authentication) {
           
$this->_bind = @ldap_bind($this->_conn, $args['user'], $args['pass']);
           return
false;
       }

       return
$args;
   }

   
/*
    * When a somebody logs in the first time and a local user is created.
    */

   
function user_create($args) {

       
$rcmail = rcmail::get_instance();
       
$attributes = array($rcmail->config->get('ldap_create_uid'), $rcmail->config->get('ldap_create_email'));
       
$attributes = array_merge($attributes, $rcmail->config->get('ldap_create_name'));

       if(!
$this->_conn) return false;

       
$res = ldap_search($this->_conn,
                       
$rcmail->config->get('ldap_base_dn'),
                       
preg_replace('/%u/', $args['user'], $rcmail->config->get('ldap_filter')), $attributes);

       if (!
$res)
           
ldapException(&quot;Error in search query &quot; . $this->get_last_error() . $e->getMessage());

       try {
           
$rows = ldap_get_entries($this->_conn, $res);

           if (
$rows[&quot;count&quot;] == 0 OR !$rows) {
               new
ldapException(&quot;user &quot; . $args['user'] . &quot; not found with query &quot; . $rcmail->config->get('ldap_filter') . &quot;And params : &quot; . $this->_conn .
                               &
quot;Base  :&quot; . $rcmail->config->get('ldap_base_dn') .
                               
preg_replace('/%u/', $args['user'], $rcmail->config->get('ldap_filter')) . &quot; Attributes: &quot;);
               new
ldapException($attributes);
           }

           
$userName = '';
           foreach (
$rcmail->config->get('ldap_create_name') as $val) {
               
$userName .= $rows[0][$val][0] . ' ';
           }

           
$userName = trim($userName);

           
$args['user'] = $rows[0][$rcmail->config->get('ldap_create_uid')][0];
           
$args['user_name'] = $userName;
           
$args['user_email'] = $rows[0][$rcmail->config->get('ldap_create_email')][0];
       } catch (
ldapException $e) {
           
ldapException(&quot;Error in search query &quot; . $this->get_last_error());
       }

       return
$args;
   }

   
/**
    * Intercept login failure
    *
    * @param array $args arguments from rcmail
    * @return array modified arguments
    */
   
function login_failed($args) {
       
// retrieve rcmail instance
       
$rcmail = rcmail::get_instance();

       
// compose error page content
       
global $__page_content, $__error_title, $__error_text;
       
$__error_title = &quot;LDAP LOGIN FAILED&quot;;
       
$__error_text = <<<EOF
Could not log into your LDAP service. The service may be interrupted, or you may not be authorized to access the service.<br />
Please contact the administrator.<br />
EOF;
       
$__page_content = <<<EOF
<div>
<h3 class=&quot;error-title&quot;>
$__error_title</h3>
<p class=&quot;error-text&quot;>
$__error_text</p>
</div>
EOF;
       
       
// redirect to error page
       
$rcmail->output->reset();
       
$rcmail->output->send('error');

       
// kill current session
       
$rcmail->kill_session();

       
// end script
       
exit;
   }    

   
/**
    * Set the domain controllers array
    *
    * @param array $_domain_controllers
    * @return void
    */
   
public function set_ldap_hostname(array $_ldap_hostname) {
       
$this->_ldap_hostname = $_ldap_hostname;
   }

   
/**
    * Get the list of domain controllers
    *
    * @return void
    */
   
public function get_ldap_hostname() {
       return
$this->_ldap_hostname;
   }

   
/**
    * Set the username of an account with higher priviledges
    *
    * @param string $_dn_username
    * @return void
    */
   
public function set_ldap_bind_username($_ad_username) {
       
$this->_ldap_bind_username = $_ldap_bind_username;
   }

   
/**
    * Get the username of the account with higher priviledges
    *
    * This will throw an exception for security reasons
    */
   
public function get_ldap_bind_username() {
       throw new
ldapException('For security reasons you cannot access the domain administrator account details');
   }

   
/**
    * Set the password of an account with higher priviledges
    *
    * @param string $_dn_password
    * @return void
    */
   
public function set_ldap_bind_password($_ad_password) {
       
$this->_ldap_bind_password = $_ldap_bind_password;
   }

   
/**
    * Get the password of the account with higher priviledges
    *
    * This will throw an exception for security reasons
    */
   
public function get_ldap_bind_password() {
       throw new
ldapException('For security reasons you cannot access the domain administrator account details');
   }

   
/**
    * Set whether to use SSL
    *
    * @param bool $_use_ssl
    * @return void
    */
   
public function set_use_ssl($_use_ssl) {
       
$this->_use_ssl = $_use_ssl;
   }

   
/**
    * Get the SSL setting
    *
    * @return bool
    */
   
public function get_use_ssl() {
       return
$this->_use_ssl;
   }

   
/**
    * Set whether to use TLS
    *
    * @param bool $_use_tls
    * @return void
    */
   
public function set_use_tls($_use_tls) {
       
$this->_use_tls = $_use_tls;
   }

   
/**
    * Get the TLS setting
    *
    * @return bool
    */
   
public function get_use_tls() {
       return
$this->_use_tls;
   }

   
/**
    * Set whether to use authentication
    *
    * @param bool $_use_authentication
    * @return void
    */
   
public function set_use_authentication($_use_authentication) {
       
$this->_use_authentication = $_use_authentication;
   }

   
/**
    * Get the use authentication setting
    *
    * @return bool
    */
   
public function get_use_authentication() {
       return
$this->_use_authentication;
   }

jfsenechal

<?php
private function ldap_init($cfg) {

       if (!
$this->ldap_inited) {
           
// retrieve configurations            

           
if (array_key_exists(&quot;base_dn&quot;, $cfg)) {
               
$this->_base_dn = $cfg[&quot;base_dn&quot;];
           }
           if (
array_key_exists(&quot;ldap_hostname&quot;, $cfg)) {
               
$this->_ldap_hostname = $cfg[&quot;ldap_hostname&quot;];
           }
           if (
array_key_exists(&quot;dn_username&quot;, $cfg)) {
               
$this->_dn_username = $cfg[&quot;dn_username&quot;];
           }
           if (
array_key_exists(&quot;dn_password&quot;, $cfg)) {
               
$this->_dn_password = $cfg[&quot;dn_password&quot;];
           }
           if (
array_key_exists(&quot;use_tls&quot;, $cfg)) {
               
$this->_use_tls = $cfg[&quot;use_tls&quot;];
           }
           if (
array_key_exists(&quot;use_authentication&quot;, $cfg)) {
               
$this->_use_authentication = $cfg[&quot;use_authentication&quot;];
           }

           
$ldap_inited = true;
       }

       return
$this->connect();
   }

   public function
connect() {

       
$dc = $this->_ldap_hostname;

       if (
$this->_use_ssl) {
           
$this->_conn = ldap_connect(&quot;ldaps://&quot; . $dc, 636);
       
} else {
           
$this->_conn = ldap_connect($dc);
       }

       if (
is_resource($this->_conn)) {
           
// Set some ldap options for talking to AD
           
ldap_set_option($this->_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
           
ldap_set_option($this->_conn, LDAP_OPT_REFERRALS, 0);

           if (
$this->_use_tls) {
               
ldap_start_tls($this->_conn);
           }

           
// Bind as a domain admin if they've set it up
           
if ($this->_ldap_bind_username != NULL && $this->_ldap_bind_password != NULL) {
               
$this->_bind = @ldap_bind($this->_conn, $this->_ldap_bind_username, $this->_ldap_bind_password);

               if (!
$this->_bind) {
                   if (
$this->_use_ssl && !$this->_use_tls) {
                       
// If you have problems troubleshooting, remove the @ character from the ldap_bind command above to get the actual error message
                       
throw new ldapException('Bind to ldap failed. Either the LDAPs connection failed or the login credentials are incorrect. Said: ' . $this->get_last_error());
                   } else {
                       throw new
ldapException('Bind to ldap failed. Check the login credentials and/or server details. Said: ' . $this->get_last_error());
                   }
               }
           }
           return (
true);
           
//catch error doesn't work !!
       
} else {
           
$error = &quot;Can't connect to serveur ldap &quot; . $dc . &quot; Error : &quot; . $e->getMessage();
           new ldapException($error);
           return false;
       }
   }

   public function get_last_error() {
       return @ldap_error($this->_conn);
   }

}

class ldapException extends Exception {

   public function ldapException($error) {
       write_log(&quot;ldap_authentication.log&quot;, $error);        
   }

}

?>


SKaero

I'd advise creating a zip of the plugin and attaching it to this thread.

jfsenechal

QuoteI'd advise creating a zip of the plugin and attaching it to this thread.

Ok I don't see this option

jml

Hello,
 we're trying to use your plugin in order to do ldap authentication, and we have several questions:
- how to be sure that this plugin is effective BEFORE imap authentication ? log file ? howto ?
- we use an SSL (port 636) only ldap server with certificates, how to configure the plugin in order to do that ?
thank you for help,
Best regards,
JM

jfsenechal

Quote- how to be sure that this plugin is effective BEFORE imap authentication ? log file ? howto ?

It's explain in the wiki :

Plugin_Hooks ? Roundcube Webmail

Quotewe use an SSL (port 636) only ldap server with certificates, how to configure the plugin in order to do that ?

In config.inc.php

set protected $_use_tls = false  to true

mattzyzy

I tried using your codes but still fail / not able to log in using the LDAP uid and password  -after hit the login button (using new uid/username account), after 3-4 seconds return only blank screen .
but , if I used the IMAP login username account that successfully logged in before the ldap_auth plugin setup(registered in mysql users table), it is OK.

If I try some gibberish /unexisted username/uid and wrong password it returns the correct/expected error -which means LDAP server is succesfully connected:" LDAP LOGIN FAILED
Could not log into your LDAP service. The service may be interrupted, or you may not be authorized to access the service.
Please contact the administrator. "

Any help would be welcome.
Thank you.

My setup in main.inc.php using RC 0.5.1
 
Quote$rcmail_config['ldap_hostname'] = '212.33.22.22';
$rcmail_config['ldap_bind_username'] = '';
$rcmail_config['ldap_bind_password'] = '';
$rcmail_config['ldap_base_dn'] = 'ou=People,o=mail.co,o=gov';

$rcmail_config['use_tls'] = false;
$rcmail_config['use_authentication'] = true;

$rcmail_config['ldap_filter'] = 'uid=%u';
$rcmail_config['ldap_create_uid'] = 'uid';
$rcmail_config['ldap_create_name'] = array('cn','sn');
$rcmail_config['ldap_create_email'] = 'mail';