From ccf1fc8f91e42edd643537eece874e573a3620d1 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Sat, 24 Jun 2006 15:13:29 +0000 Subject: [PATCH] =?UTF-8?q?D=E9but=20ajout=20gestion=20utilisateurs=20ldap?= =?UTF-8?q?=20Modification=20de=20la=20classe=20ldap.lib.php=20en=20authld?= =?UTF-8?q?ap.lib.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/admin/ldap.php | 44 ++- htdocs/conf/conf.class.php | 2 + htdocs/contact.class.php | 141 ++++---- htdocs/langs/en_US/users.lang | 3 +- htdocs/langs/fr_FR/users.lang | 1 + htdocs/lib/authldap.lib.php | 608 ++++++++++++++++++++++++++++++++ htdocs/lib/ldap.lib.php | 163 --------- htdocs/user.class.php | 12 +- htdocs/user/fiche.php | 245 +++++++++++-- htdocs/user/home.php | 6 +- htdocs/user/index.php | 6 +- mysql/data/data.sql | 11 + mysql/migration/2.0.0-2.1.0.sql | 4 +- mysql/tables/llx_user.sql | 1 + 14 files changed, 962 insertions(+), 285 deletions(-) create mode 100644 htdocs/lib/authldap.lib.php delete mode 100644 htdocs/lib/ldap.lib.php diff --git a/htdocs/admin/ldap.php b/htdocs/admin/ldap.php index 64d27f34a8e..9cbd9ed876e 100644 --- a/htdocs/admin/ldap.php +++ b/htdocs/admin/ldap.php @@ -40,7 +40,7 @@ */ require("./pre.inc.php"); -require_once(DOL_DOCUMENT_ROOT."/lib/ldap.lib.php"); +require_once(DOL_DOCUMENT_ROOT."/lib/authldap.lib.php"); $langs->load("admin"); @@ -66,10 +66,18 @@ if ($_GET["action"] == 'setvalue' && $user->admin) { print $db->error(); } + if (! dolibarr_set_const($db, 'LDAP_SERVER_HOST_SLAVE',$_POST["slave"])) + { + print $db->error(); + } if (! dolibarr_set_const($db, 'LDAP_SERVER_PORT',$_POST["port"])) { print $db->error(); } + if (! dolibarr_set_const($db, 'LDAP_SERVER_DN',$_POST["dn"])) + { + print $db->error(); + } if (! dolibarr_set_const($db, 'LDAP_ADMIN_DN',$_POST["admin"])) { print $db->error(); @@ -191,6 +199,13 @@ print $langs->trans("LDAPServer").''; print ''; print ''.$langs->trans("LDAPServerExample").''; +// Serveur +$var=!$var; +print ''; +print $langs->trans("LDAPServerSlave").''; +print ''; +print ''.$langs->trans("LDAPServerExample").''; + // Port $var=!$var; print ''.$langs->trans("LDAPServerPort").''; @@ -204,6 +219,12 @@ else } print ''.$langs->trans("LDAPServerPortExample").''; +// DNserver +$var=!$var; +print ''.$langs->trans("DNServer").''; +print ''; +print ''.$langs->trans("LDAPServerDnExample").''; + // DNAdmin $var=!$var; print ''.$langs->trans("DNAdmin").''; @@ -215,7 +236,7 @@ $var=!$var; print ''.$langs->trans("LDAPPassword").''; if ($conf->global->LDAP_ADMIN_PASS) { - print '';// je le met en visible pour test + print '';// je le met en visible pour test } else { @@ -274,7 +295,7 @@ if ($conf->global->LDAP_FILTER_CONNECTION) } else { - print ''; + print ''; } print ''.$langs->trans("LDAPFilterConnectionExample").''; @@ -381,11 +402,11 @@ if (function_exists("ldap_connect")) if ($conf->global->LDAP_SERVER_HOST && $conf->global->LDAP_ADMIN_DN && $conf->global->LDAP_ADMIN_PASS && $_GET["action"] == 'test') { - $ldap = New Ldap(); + $ldap = New AuthLdap(); // Test ldap_connect // ce test n'est pas fiable car une ressource est constamment retournée // il faut se fier au test ldap_bind - $ds = $ldap->dolibarr_ldap_connect(); + $ds = $ldap->connect(); if ($ds) { print img_picto('','info'); @@ -396,14 +417,14 @@ if (function_exists("ldap_connect")) print img_picto('','alerte'); print $langs->trans("LDAPTestKO").'
'; print "
"; - print $ldap->err; + print $ldap->ldapErrorCode." - ".$ldap->ldapErrorText; print "
"; } if ($ds) { // Test ldap_getversion - if (($ldap->dolibarr_ldap_getversion($ds) == 3)) + if (($ldap->getVersion() == 3)) { print img_picto('','info'); print $langs->trans("LDAPSetupForVersion3").'
'; @@ -415,7 +436,7 @@ if (function_exists("ldap_connect")) } // Test ldap_bind - $bind = $ldap->dolibarr_ldap_bind($ds); + $bind = $ldap->bind(); if ($bind) { @@ -426,14 +447,14 @@ if (function_exists("ldap_connect")) { print img_picto('','alerte'); print "Connexion au dn $dn raté : "; - print $ldap->err; + print $ldap->ldapErrorCode." - ".$ldap->ldapErrorText; print "
"; } // Test ldap_unbind - $unbind = $ldap->dolibarr_ldap_unbind($ds); + $unbind = $ldap->unbind(); - if ($bind && $unbind) + if ($unbind) { print img_picto('','info'); print "Déconnection du dn $dn réussi
"; @@ -443,6 +464,7 @@ if (function_exists("ldap_connect")) print img_picto('','alerte'); print "Déconnection du dn $dn raté"; print "
"; + print $ldap->ldapErrorCode." - ".$ldap->ldapErrorText; } } } diff --git a/htdocs/conf/conf.class.php b/htdocs/conf/conf.class.php index 57dc35e750b..f4324b7ee45 100644 --- a/htdocs/conf/conf.class.php +++ b/htdocs/conf/conf.class.php @@ -275,6 +275,8 @@ class Conf // Module export $this->export->enabled=defined("MAIN_MODULE_EXPORT")?MAIN_MODULE_EXPORT:0; $this->export->dir_ouput=DOL_DATA_ROOT."/export"; + // Module ldap + $this->ldap->enabled=defined("MAIN_MODULE_LDAP")?MAIN_MODULE_LDAP:0; /* diff --git a/htdocs/contact.class.php b/htdocs/contact.class.php index e375c496257..8c7fd07f1da 100644 --- a/htdocs/contact.class.php +++ b/htdocs/contact.class.php @@ -186,17 +186,14 @@ class Contact dolibarr_syslog("Contact::update_ldap",LOG_DEBUG); $this->fetch($this->id); + $ldap = New AuthLdap(); - $ds = dolibarr_ldap_connect(); - - if ($ds) - { - $ldapbind = dolibarr_ldap_bind($ds); - - if ($ldapbind) - { - if (LDAP_SERVER_TYPE == 'activedirectory') //enlever utf8 pour etre compatible Windows - { + if ($ldap->connect()) + { + if (bind()) + { + if (LDAP_SERVER_TYPE == 'activedirectory') //enlever utf8 pour etre compatible Windows + { $info["objectclass"][0] = "top"; $info["objectclass"][1] = "person"; $info["objectclass"][2] = "organizationalPerson"; @@ -207,33 +204,41 @@ class Contact $info["sn"] = $this->name; $info["givenName"] = $this->firstname; - if ($this->poste) - $info["title"] = $this->poste; + if ($this->poste) $info["title"] = $this->poste; if ($this->socid > 0) - { - $soc = new Societe($this->db); - $soc->fetch($this->socid); - $info["o"] = $soc->nom; - $info["company"] = $soc->nom; - - if ($soc->client == 1) - $info["businessCategory"] = "Clients"; - elseif ($soc->client == 2) - $info["businessCategory"] = "Prospects"; - - if ($soc->fournisseur == 1) - $info["businessCategory"] = "Fournisseurs"; - - if ($soc->ville) - { - if ($soc->adresse) - $info["streetAddress"] = $soc->adresse; - - if ($soc->cp) - $info["postalCode"] = $soc->cp; - - $info["l"] = $soc->ville; + { + $soc = new Societe($this->db); + $soc->fetch($this->socid); + $info["o"] = $soc->nom; + $info["company"] = $soc->nom; + + if ($soc->client == 1) + { + $info["businessCategory"] = "Clients"; + } + elseif ($soc->client == 2) + { + $info["businessCategory"] = "Prospects"; + } + + if ($soc->fournisseur == 1) + { + $info["businessCategory"] = "Fournisseurs"; + } + + if ($soc->ville) + { + if ($soc->adresse) + { + $info["streetAddress"] = $soc->adresse; + } + if ($soc->cp) + { + $info["postalCode"] = $soc->cp; + } + + $info["l"] = $soc->ville; } } @@ -370,7 +375,7 @@ class Contact dolibarr_syslog("Contact::update_ldap bind failed",LOG_DEBUG); } - dolibarr_ldap_unbind($ds); + $ldap->unbind(); } else @@ -636,46 +641,42 @@ class Contact { if (defined('LDAP_CONTACT_ACTIVE') && LDAP_CONTACT_ACTIVE == 1) { + $ldap = New AuthLdap(); - $ds = dolibarr_ldap_connect(); - - if ($ds) - { - $ldapbind = dolibarr_ldap_bind($ds); - - if ($ldapbind) - { - // delete from ldap directory - if (LDAP_SERVER_TYPE == 'activedirectory') - { - $userdn = $this->old_firstname." ".$this->old_name; //enlever utf8 pour etre compatible Windows - } - else - { - $userdn = utf8_encode($this->old_firstname." ".$this->old_name); - } - $dn = "cn=".$userdn.",".LDAP_CONTACT_DN; - - $r = @ldap_delete($ds, $dn); - - } - else - { - echo "LDAP bind failed..."; - } - ldap_close($ds); - - } + if ($ldap->connect()) + { + if ($ldap->bind()) + { + // delete from ldap directory + if (LDAP_SERVER_TYPE == 'activedirectory') + { + $userdn = $this->old_firstname." ".$this->old_name; //enlever utf8 pour etre compatible Windows + } + else + { + $userdn = utf8_encode($this->old_firstname." ".$this->old_name); + } + + $dn = "cn=".$userdn.",".LDAP_CONTACT_DN; + $r = @ldap_delete($ds, $dn); + } + else + { + echo "LDAP bind failed..."; + } + + $ldap->close(); + } else - { - echo "Unable to connect to LDAP server"; - } - + { + echo "Unable to connect to LDAP server"; + } return $result; } + } } - } + /* * \brief Charge les informations sur le contact, depuis la base diff --git a/htdocs/langs/en_US/users.lang b/htdocs/langs/en_US/users.lang index 026daa3a34f..26758763b6f 100755 --- a/htdocs/langs/en_US/users.lang +++ b/htdocs/langs/en_US/users.lang @@ -72,4 +72,5 @@ ErrorFailedToSaveFile=Error - Failed to save file GuiLanguage=Interface language InternalUser=Internal user MyInformations=My informations -ExportDataset_user_1=Dolibarr's users and properties \ No newline at end of file +ExportDataset_user_1=Dolibarr's users and properties +DomainUser=Domain user \ No newline at end of file diff --git a/htdocs/langs/fr_FR/users.lang b/htdocs/langs/fr_FR/users.lang index 397d44667ed..3e4599165c7 100755 --- a/htdocs/langs/fr_FR/users.lang +++ b/htdocs/langs/fr_FR/users.lang @@ -73,3 +73,4 @@ GuiLanguage=Langage de l'interface InternalUser=Utilisateur interne MyInformations=Mes informations ExportDataset_user_1=Utilisateurs Dolibarr et attributs +DomainUser=Utilisateur du domaine \ No newline at end of file diff --git a/htdocs/lib/authldap.lib.php b/htdocs/lib/authldap.lib.php new file mode 100644 index 00000000000..c969bcfab99 --- /dev/null +++ b/htdocs/lib/authldap.lib.php @@ -0,0 +1,608 @@ + + * Copyright (C) 2004 Benoit Mortier + * Copyright (C) 2005-2006 Regis Houssin + * Copyright (C) 2006 Laurent Destailleur + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * or see http://www.gnu.org/ + * + * $Id$ + * $Source$ + */ + +/** + \file htdocs/lib/authldap.lib.php + \brief Librairie contenant les fonctions pour accèder au serveur ldap. + \author Rodolphe Quiedeville. + \author Benoit Mortier. + \author Regis Houssin. + \author Laurent Destailleur. + \version $Revision$ + + Ensemble des fonctions permettant d'accèder à un serveur LDAP. +*/ + +class AuthLdap { + + + /** + * Tableau des serveurs (IP addresses ou nom d'hôtes) + */ + var $server; + /** + * Base DN (e.g. "dc=foo,dc=com") + */ + var $dn; + /** + * type de serveur, actuellement OpenLdap et Active Directory + */ + var $serverType; + /** + * Version du protocole ldap + */ + var $domain; + /** + * Administrateur Ldap + * Active Directory ne supporte pas les connexions anonymes + */ + var $searchUser; + /** + * Mot de passe de l'administrateur + * Active Directory ne supporte pas les connexions anonymes + */ + var $searchPassword; + /** + * DN des utilisateurs + */ + var $people; + /** + * DN des groupes + */ + var $groups; + /** + * Code erreur retourné par le serveur Ldap + */ + var $ldapErrorCode; + /** + * Message texte de l'erreur + */ + var $ldapErrorText; + + // 1.2 Private properties ---------------------------------------------------- + /** + * The internal LDAP connection handle + */ + var $connection; + /** + * Result of any connections etc. + */ + var $result; + + /** + * Constructor- creates a new instance of the authentication class + * + * @param string the ldap server to connect to + * @param string the base dn + * @param string the server type- current supports OpenLdap and ActiveDirectory + * @param string the domain to use when authenticating against Active Directory + * @param string the username to authenticate with when searching if anonymous binding is not supported + * @param string the password to authenticate with when searching if anonymous binding is not supported + */ + function AuthLdap () { + global $conf; + + $this->server = array($conf->global->LDAP_SERVER_HOST, $conf->global->LDAP_SERVER_HOST_SLAVE); + $this->serverPort = $conf->global->LDAP_SERVER_PORT; + $this->ldapProtocolVersion = $conf->global->LDAP_SERVER_PROTOCOLVERSION; + $this->dn = $conf->global->LDAP_SERVER_DN; + $this->serverType = $conf->global->LDAP_SERVER_TYPE; + $this->domain = $sDomain; + $this->searchUser = $conf->global->LDAP_ADMIN_DN; + $this->searchPassword = $conf->global->LDAP_ADMIN_PASS; + $this->people = $conf->global->LDAP_USER_DN; + $this->groups = $conf->global->LDAP_GROUP_DN; + } + + // 2.1 Connection handling methods ------------------------------------------- + + /** + * 2.1.1 : Connects to the server. Just creates a connection which is used + * in all later access to the LDAP server. If it can't connect and bind + * anonymously, it creates an error code of -1. Returns true if connected, + * false if failed. Takes an array of possible servers - if one doesn't work, + * it tries the next and so on. + */ + function connect() { + foreach ($this->server as $key => $host) { + if (ereg('^ldap',$host)) { + $this->connection = ldap_connect($host); + } else { + $this->connection = ldap_connect($host,$this->serverPort); + } + if ( $this->connection) { + $this->setVersion(); + if ($this->serverType == "activedirectory") { + return true; + } else { + // Connected, now try binding anonymously + $this->result=@ldap_bind( $this->connection); + } + return true; + } + } + + $this->ldapErrorCode = -1; + $this->ldapErrorText = "Unable to connect to any server"; + return false; + } + + /** + * 2.1.2 : Simply closes the connection set up earlier. + * Returns true if OK, false if there was an error. + */ + function close() { + if ( !@ldap_close($this->connection)) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } else { + return true; + } + } + + /** + * 2.1.3 : Anonymously binds to the connection. After this is done, + * queries and searches can be done - but read-only. + */ + function bind() { + if ( !$this->result=@ldap_bind( $this->connection)) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } else { + return true; + } + } + + /** + * \brief unbind du serveur ldap. + * \param ds + * \return bool + */ + function unbind() { + if (!$this->result=@ldap_unbind($this->connection)) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } else { + return true; + } + } + + + /** + * 2.1.4 : Binds as an authenticated user, which usually allows for write + * access. The FULL dn must be passed. For a directory manager, this is + * "cn=Directory Manager" under iPlanet. For a user, it will be something + * like "uid=jbloggs,ou=People,dc=foo,dc=com". + */ + function authBind( $bindDn,$pass) { + if ( !$this->result = @ldap_bind( $this->connection,$bindDn,$pass)) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } else { + return true; + } + } + + /** + * \brief verification de la version du serveur ldap. + * \param ds + * \return version + */ + function getVersion() { + $version = 0; + $version = @ldap_get_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $version); + return $version; + } + + /** + * \brief changement de la version du serveur ldap. + * \param ds + * \param version + * \return version + */ + function setVersion() { + $ldapsetversion = ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldapProtocolVersion); + return $ldapsetversion; + } + + // 2.2 Password methods ------------------------------------------------------ + + /** + * 2.2.1 : Checks a username and password - does this by logging on to the + * server as a user - specified in the DN. There are several reasons why + * this login could fail - these are listed below. + */ + function checkPass( $uname,$pass) { + /* Construct the full DN, eg:- + ** "uid=username, ou=People, dc=orgname,dc=com" + */ + if ($this->serverType == "activedirectory") { + $checkDn = "$uname@$this->domain"; + } else { + $checkDn = $this->getUserIdentifier() . "=$uname, " . $this->setDn(true); + } + // Try and connect... + $this->result = @ldap_bind( $this->connection,$checkDn,$pass); + if ( $this->result) { + // Connected OK - login credentials are fine! + return true; + } else { + /* Login failed. Return false, together with the error code and text from + ** the LDAP server. The common error codes and reasons are listed below : + ** (for iPlanet, other servers may differ) + ** 19 - Account locked out (too many invalid login attempts) + ** 32 - User does not exist + ** 49 - Wrong password + ** 53 - Account inactive (manually locked out by administrator) + */ + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } + } + + + /** + * 2.2.2 : Allows a password to be changed. Note that on most LDAP servers, + * a new ACL must be defined giving users the ability to modify their + * password attribute (userPassword). Otherwise this will fail. + */ + function changePass( $uname,$oldPass,$newPass) { + // builds the appropriate dn, based on whether $this->people and/or $this->group is set + if ($this->serverType == "activedirectory") { + $checkDn = "$uname@$this->domain"; + } else { + $checkDn = $this->getUserIdentifier() . "=$uname, " . $this->setDn(true); + } + $this->result = @ldap_bind( $this->connection,$checkDn,$oldPass); + + if ( $this->result) { + // Connected OK - Now modify the password... + $info["userPassword"] = $newPass; + $this->result = @ldap_modify( $this->connection, $checkDn, $info); + if ( $this->result) { + // Change went OK + return true; + } else { + // Couldn't change password... + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } + } else { + // Login failed - see checkPass method for common error codes + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } + } + + + /** + * 2.2.3 : Returns days until the password will expire. + * We have to explicitly state this is what we want returned from the + * LDAP server - by default, it will only send back the "basic" + * attributes. + */ + function checkPassAge ( $uname) { + + $results[0] = "passwordexpirationtime"; + // builds the appropriate dn, based on whether $this->people and/or $this->group is set + $checkDn = $this->setDn(true); + $this->result = @ldap_search( $this->connection,$checkDn,$this->getUserIdentifier()."=$uname",$results); + + if ( !$info=@ldap_get_entries( $this->connection, $this->result)) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } else { + /* Now work out how many days remaining.... + ** Yes, it's very verbose code but I left it like this so it can easily + ** be modified for your needs. + */ + $date = $info[0]["passwordexpirationtime"][0]; + $year = substr( $date,0,4); + $month = substr( $date,4,2); + $day = substr( $date,6,2); + $hour = substr( $date,8,2); + $min = substr( $date,10,2); + $sec = substr( $date,12,2); + + $timestamp = mktime( $hour,$min,$sec,$month,$day,$year); + $today = mktime(); + $diff = $timestamp-$today; + return round( ( ( ( $diff/60)/60)/24)); + } + } + + // 2.3 Group methods --------------------------------------------------------- + + /** + * 2.3.1 : Checks to see if a user is in a given group. If so, it returns + * true, and returns false if the user isn't in the group, or any other + * error occurs (eg:- no such user, no group by that name etc.) + */ + function checkGroup ( $uname,$group) { + // builds the appropriate dn, based on whether $this->people and/or $this->group is set + $checkDn = $this->setDn(false); + + // We need to search for the group in order to get it's entry. + $this->result = @ldap_search( $this->connection, $checkDn, "cn=" .$group); + $info = @ldap_get_entries( $this->connection, $this->result); + + // Only one entry should be returned(no groups will have the same name) + $entry = ldap_first_entry( $this->connection,$this->result); + + if ( !$entry) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; // Couldn't find the group... + } + // Get all the member DNs + if ( !$values = @ldap_get_values( $this->connection, $entry, "uniqueMember")) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; // No users in the group + } + + foreach ( $values as $key => $value) { + /* Loop through all members - see if the uname is there... + ** Also check for sub-groups - this allows us to define a group as + ** having membership of another group. + ** FIXME:- This is pretty ugly code and unoptimised. It takes ages + ** to search if you have sub-groups. + */ + list( $cn,$ou) = explode( ",",$value); + list( $ou_l,$ou_r) = explode( "=",$ou); + + if ( $this->groups==$ou_r) { + list( $cn_l,$cn_r) = explode( "=",$cn); + // OK, So we now check the sub-group... + if ( $this->checkGroup ( $uname,$cn_r)) { + return true; + } + } + + if ( preg_match( "/$uname/i",$value)) { + return true; + } + } + } + + // 2.4 Attribute methods ----------------------------------------------------- + /** + * 2.4.1 : Returns an array containing a set of attribute values. + * For most searches, this will just be one row, but sometimes multiple + * results are returned (eg:- multiple email addresses) + */ + function getAttribute ( $uname,$attribute) { + + global $conf; + + // builds the appropriate dn, based on whether $this->people and/or $this->group is set + //$checkDn = $this->setDn( true); + $checkDn = $this->people; + $results[0] = $attribute; + + // We need to search for this user in order to get their entry. + $this->result = @ldap_search( $this->connection,$checkDn,$this->getUserIdentifier()."=$uname",$results); + $info = ldap_get_entries( $this->connection, $this->result); + + // Only one entry should ever be returned (no user will have the same uid) + $entry = ldap_first_entry( $this->connection, $this->result); + + if ( !$entry) { + $this->ldapErrorCode = -1; + $this->ldapErrorText = "Couldn't find user"; + return false; // Couldn't find the user... + } + + // Get all the member DNs + if ( !$values = @ldap_get_values( $this->connection, $entry, $attribute)) { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; // No matching attributes + } + + // Return an array containing the attributes. + return $values; + } + + /** + * 2.4.2 : Allows an attribute value to be set. + * This can only usually be done after an authenticated bind as a + * directory manager - otherwise, read/write access will not be granted. + */ + function setAttribute( $uname, $attribute, $value) { + // Construct a full DN... + // builds the appropriate dn, based on whether $this->people and/or $this->group is set + $attrib_dn = $this->getUserIdentifier()."=$uname," . $this->setDn(true); + + $info[$attribute] = $value; + // Change attribute + $this->result = ldap_modify( $this->connection, $attrib_dn, $info); + if ( $this->result) { + // Change went OK + return true; + } else { + // Couldn't change password... + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + return false; + } + } + + // 2.5 User methods ---------------------------------------------------------- + /** + * 2.5.1 : Returns an array containing a details of users, sorted by + * username. The search criteria is a standard LDAP query - * returns all + * users. The $attributeArray variable contains the required user detail field names + */ + function getUsers( $search, $attributeArray) { + + global $conf; + + // builds the appropriate dn, based on whether $this->people and/or $this->group is set + //$checkDn = $this->setDn( true); + $checkDn = $conf->global->LDAP_USER_DN; + + // Perform the search and get the entry handles + + // if the directory is AD, then bind first with the search user first + if ($this->serverType == "activedirectory") { + $this->authBind($this->searchUser, $this->searchPassword); + } + + $filter = '('.$conf->global->LDAP_FILTER_CONNECTION.'('.$this->getUserIdentifier().'='.$search.'))'; + + $this->result = @ldap_search( $this->connection, $checkDn, $filter); + + if (!$this->result) + { + $this->ldapErrorCode = ldap_errno( $this->connection); + $this->ldapErrorText = ldap_error( $this->connection); + } + + $info = @ldap_get_entries( $this->connection, $this->result); + + for( $i = 0; $i < $info["count"]; $i++) + { + // Get the username, and create an array indexed by it... + // Modify these as you see fit. + $uname = $info[$i][$this->getUserIdentifier()][0]; + + // add to the array for each attribute in my list + for ( $j = 0; $j < count( $attributeArray); $j++) + { + if (strtolower($attributeArray[$j]) == "dn") + { + $userslist["$uname"]["$attributeArray[$j]"] = $info[$i][strtolower($attributeArray[$j])]; + } + else if (strtolower($attributeArray[$j]) == "objectsid") + { + $objectsid = $this->getObjectSid($uname); + $userslist["$uname"]["$attributeArray[$j]"] = $objectsid[0]; + } + else + { + $userslist["$uname"]["$attributeArray[$j]"] = $info[$i][strtolower($attributeArray[$j])][0]; + } + } + } + + if ( !@asort( $userslist)) { + /* Sort into alphabetical order. If this fails, it's because there + ** were no results returned (array is empty) - so just return false. + */ + $this->ldapErrorCode = -1; + $this->ldapErrorText = "No users found matching search criteria ".$search; + return false; + } + return $userslist; + + } + + /** + * Récupère le SID de l'utilisateur + * ldapuser. le login de l'utilisateur + */ + function getObjectSid($ldapUser) + { + global $conf; + + $criteria = $this->getUserIdentifier()."=$ldapUser"; + $justthese = array("objectsid"); + $checkDn = $conf->global->LDAP_USER_DN; + + $ldapSearchResult = ldap_search($this->connection, $checkDn, $criteria, $justthese); + + $entry = ldap_first_entry($this->connection, $ldapSearchResult); + $ldapBinary = ldap_get_values_len ($this->connection, $entry, "objectsid"); + + return $ldapBinary; + } + + + // 2.6 helper methods + + /** + * Sets and returns the appropriate dn, based on whether there + * are values in $this->people and $this->groups. + * + * @param boolean specifies whether to build a groups dn or a people dn + * @return string if true ou=$this->people,$this->dn, else ou=$this->groups,$this->dn + */ + function setDn($peopleOrGroups) { + + if ($peopleOrGroups) { + if ( isset($this->people) && (strlen($this->people) > 0) ) { + $checkDn = "ou=" .$this->people. ", " .$this->dn; + } + } else { + if ( isset($this->groups) && (strlen($this->groups) > 0) ) { + $checkDn = "ou=" .$this->groups. ", " .$this->dn; + } + } + + if ( !isset($checkDn) ) { + $checkDn = $this->dn; + } + return $checkDn; + } + + /** + * Returns the correct user identifier to use, based on the ldap server type + */ + function getUserIdentifier() { + if ($this->serverType == "activedirectory") { + return "samaccountname"; + } else { + return "uid"; + } + } + + /** + * \brief permet d'enlever les accents d'une chaine. + * \param str + * \return string + */ + function dolibarr_ldap_unacc($str) + { + $stu = ereg_replace("é","e",$str); + $stu = ereg_replace("è","e",$stu); + $stu = ereg_replace("ê","e",$stu); + $stu = ereg_replace("à","a",$stu); + $stu = ereg_replace("ç","c",$stu); + $stu = ereg_replace("ï","i",$stu); + $stu = ereg_replace("ä","a",$stu); + return $stu; + } + +} // End of class +?> diff --git a/htdocs/lib/ldap.lib.php b/htdocs/lib/ldap.lib.php deleted file mode 100644 index 72f4abe0c31..00000000000 --- a/htdocs/lib/ldap.lib.php +++ /dev/null @@ -1,163 +0,0 @@ - - * Copyright (C) 2004 Benoit Mortier - * Copyright (C) 2005 Regis Houssin - * Copyright (C) 2006 Laurent Destailleur - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * or see http://www.gnu.org/ - * - * $Id$ - * $Source$ - */ - -/** - \file htdocs/lib/ldap.lib.php - \brief Librairie contenant les fonctions pour accèder au serveur ldap. - \author Rodolphe Quiedeville. - \author Benoit Mortier. - \version $Revision$ - - Ensemble des fonctions permettant d'accèder à un serveur LDAP. -*/ - -class Ldap -{ - var $err; // erreur ldap - - - /** - * \brief Constructeur de la classe - */ - function Ldap() - { - $this->err = ""; - } - - -/** - \brief Ouverture d'une connection vers le serveur LDAP - \return resource -*/ -function dolibarr_ldap_connect() -{ - global $conf; - - if (ereg('^ldap',$conf->global->LDAP_SERVER_HOST)) - { - // ex url: ldaps://ldap.example.com/ - $ldapconnect = ldap_connect($conf->global->LDAP_SERVER_HOST); - } - else - { - // ex serveur: localhost - // ex port: 389 - $ldapconnect = ldap_connect($conf->global->LDAP_SERVER_HOST,$conf->global->LDAP_SERVER_PORT); - } - - if ($ldapconnect) - { - ldap_set_option($ldapconnect, LDAP_OPT_PROTOCOL_VERSION, $conf->global->LDAP_SERVER_PROTOCOLVERSION); - } - return $ldapconnect; -} - - -/** - \brief Se connecte au serveur LDAP avec user et mot de passe - \param ds - \return bool -*/ -function dolibarr_ldap_bind($ds) -{ - global $conf; - - if (defined("LDAP_ADMIN_PASS") && $conf->global->LDAP_ADMIN_DN && $conf->global->LDAP_ADMIN_PASS) - { - $ldapbind = @ldap_bind($ds, $conf->global->LDAP_ADMIN_DN, $conf->global->LDAP_ADMIN_PASS); - } - - if ($ldapbind) - { - return $ldapbind; - } - else - { - $this->err = ldap_error($ds); - } -} - -/** - \brief unbind du serveur ldap. - \param ds - \return bool -*/ -function dolibarr_ldap_unbind($ds) -{ - $ldapunbind = @ldap_unbind($ds); - - return $ldapunbind; -} - -/** - \brief verification de la version du serveur ldap. - \param ds - \return version -*/ -function dolibarr_ldap_getversion($ds) -{ - global $conf; - - $version = 0; - - ldap_get_option($ds, LDAP_OPT_PROTOCOL_VERSION, $version); - - return $version; -} - -/** - \brief changement de la version du serveur ldap. - \param ds - \param version - \return version -*/ -function dolibarr_ldap_setversion($ds,$version) -{ - global $conf; - - $ldapsetversion = ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $version); - - return $ldapsetversion; -} - -/** - \brief permet d'enlever les accents d'une chaine. - \param str - \return string -*/ -function dolibarr_ldap_unacc($str) -{ - $stu = ereg_replace("é","e",$str); - $stu = ereg_replace("è","e",$stu); - $stu = ereg_replace("ê","e",$stu); - $stu = ereg_replace("à","a",$stu); - $stu = ereg_replace("ç","c",$stu); - $stu = ereg_replace("ï","i",$stu); - $stu = ereg_replace("ä","a",$stu); - return $stu; -} -} - -?> diff --git a/htdocs/user.class.php b/htdocs/user.class.php index 88ad673e225..c45e8e7aa07 100644 --- a/htdocs/user.class.php +++ b/htdocs/user.class.php @@ -49,6 +49,7 @@ class User var $db; var $id; + var $ldap_sid; var $fullname; var $nom; var $prenom; @@ -102,7 +103,7 @@ class User { // Recupere utilisateur $sql = "SELECT u.rowid, u.name, u.firstname, u.email, u.office_phone, u.office_fax, u.user_mobile, u.code, u.admin, u.login, u.pass, u.webcal_login, u.note,"; - $sql.= " u.fk_societe, u.fk_socpeople, "; + $sql.= " u.fk_societe, u.fk_socpeople, u.ldap_sid,"; $sql.= " ".$this->db->pdate("u.datec")." as datec, ".$this->db->pdate("u.tms")." as datem,"; $sql.= " ".$this->db->pdate("u.datelastaccess")." as datel"; $sql.= " FROM ".MAIN_DB_PREFIX."user as u"; @@ -122,6 +123,7 @@ class User if ($obj) { $this->id = $obj->rowid; + $this->ldap_sid = $obj->ldap_sid; $this->nom = stripslashes($obj->name); $this->prenom = stripslashes($obj->firstname); @@ -129,9 +131,9 @@ class User $this->code = $obj->code; $this->login = $obj->login; $this->pass = $obj->pass; - $this->office_phone = $obj->office_phone; - $this->office_fax = $obj->office_fax; - $this->user_mobile = $obj->user_mobile; + $this->office_phone = $obj->office_phone; + $this->office_fax = $obj->office_fax; + $this->user_mobile = $obj->user_mobile; $this->email = $obj->email; $this->admin = $obj->admin; $this->contact_id = $obj->fk_socpeople; @@ -574,7 +576,7 @@ class User } else { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."user (datec,login) VALUES(now(),'".addslashes($this->login)."')"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."user (datec,login,ldap_sid) VALUES(now(),'".addslashes($this->login)."','".$this->ldap_sid."')"; $result=$this->db->query($sql); if ($result) diff --git a/htdocs/user/fiche.php b/htdocs/user/fiche.php index 6fee56868af..f405bb4ee96 100644 --- a/htdocs/user/fiche.php +++ b/htdocs/user/fiche.php @@ -32,6 +32,7 @@ require("./pre.inc.php"); require_once(DOL_DOCUMENT_ROOT."/contact.class.php"); +require_once(DOL_DOCUMENT_ROOT."/lib/authldap.lib.php"); // Defini si peux creer un utilisateur ou gerer groupe sur un utilisateur @@ -124,12 +125,13 @@ if ($_POST["action"] == 'add' && $canadduser) $edituser->prenom = trim($_POST["prenom"]); $edituser->login = trim($_POST["login"]); $edituser->admin = trim($_POST["admin"]); - $edituser->office_phone = trim($_POST["office_phone"]); - $edituser->office_fax = trim($_POST["office_fax"]); - $edituser->user_mobile = trim($_POST["user_mobile"]); + $edituser->office_phone = trim($_POST["office_phone"]); + $edituser->office_fax = trim($_POST["office_fax"]); + $edituser->user_mobile = trim($_POST["user_mobile"]); $edituser->email = trim($_POST["email"]); $edituser->webcal_login = trim($_POST["webcal_login"]); $edituser->note = trim($_POST["note"]); + $edituser->ldap_sid = trim($_POST["ldap_sid"]); $db->begin(); @@ -295,7 +297,7 @@ if ((($_POST["action"] == 'confirm_password' && $_POST["confirm"] == 'yes') llxHeader('',$langs->trans("UserCard")); -if ($action == 'create') +if (($action == 'create') || ($action == 'adduserldap')) { /* ************************************************************************** */ /* */ @@ -307,33 +309,154 @@ if ($action == 'create') print "
"; if ($message) { print $message.'
'; } + + /* + * ajout utilisateur ldap + */ + if ($conf->ldap->enabled) + { + if ($conf->global->LDAP_SERVER_HOST && $conf->global->LDAP_ADMIN_DN && $conf->global->LDAP_ADMIN_PASS) + { + $ldap = new AuthLdap(); + + if ($ldap->connect()) + { + $justthese = array( "sn", "givenname", "samaccountname"); + $ldapusers = $ldap->getUsers('*', $justthese); + + if ($ldapusers) + { + $html = new Form($db); + + foreach ($ldapusers as $key => $ldapuser) + { + if($ldapuser["sn"] != "") + $liste[$ldapuser["samaccountname"]] = utf8_decode($ldapuser["sn"])." ".utf8_decode($ldapuser["givenname"]); + } + + print '
'; + print ''; + print $html->select_array('users', $liste, '', 1); + print ''; + print '
'; + print "
"; + } + + if ($action == 'adduserldap') + { + + + $selecteduser = $_POST['users']; + $justthese = array( "samaccountname", + "sn", + "givenname", + "mail", + "telephonenumber", + "facsimiletelephonenumber", + "mobile", + "objectsid"); + + $selectedUser = $ldap->getUsers($selecteduser, $justthese); + + if ($selectedUser) + { + foreach ($selectedUser as $key => $attribute) + { + $ldap_nom = utf8_decode($attribute["sn"]?$attribute["sn"]:''); + $ldap_prenom = utf8_decode($attribute["givenname"]?$attribute["givenname"]:''); + $ldap_login = utf8_decode($attribute["samaccountname"]?$attribute["samaccountname"]:''); + $ldap_phone = utf8_decode($attribute["telephonenumber"]?$attribute["telephonenumber"]:''); + $ldap_fax = utf8_decode($attribute["facsimiletelephonenumber"]?$attribute["facsimiletelephonenumber"]:''); + $ldap_mobile = utf8_decode($attribute["mobile"]?$attribute["mobile"]:''); + $ldap_mail = utf8_decode($attribute["mail"]?$attribute["mail"]:''); + $ldap_SID = bin2hex($attribute["objectsid"]); + } + } + } + } + else + { + print $ldap->ldapErrorCode; + print $ldap->ldapErrorText; + } + if (!$ldap->close()) + { + print $ldap->ldapErrorCode; + print $ldap->ldapErrorText; + } + } + } print '
'; print ''; + if ($ldap_SID) print ''; print ''; print "".''; - print ''; + print ''; print ''; - print ''; + print ''; print ''; - print ''; - - $generated_password=''; - if ($conf->global->USER_PASSWORD_GENERATED) + print ''; - print ''; + else + { + print ''; + } + print ''; + + if (!$ldap_SID) + { + $generated_password=''; + if ($conf->global->USER_PASSWORD_GENERATED) + { + $nomclass="modGeneratePass".ucfirst($conf->global->USER_PASSWORD_GENERATED); + $nomfichier=$nomclass.".class.php"; + //print DOL_DOCUMENT_ROOT."/includes/modules/security/generate/".$nomclass; + require_once(DOL_DOCUMENT_ROOT."/includes/modules/security/generate/".$nomfichier); + $genhandler=new $nomclass($db,$conf,$lang,$user); + $generated_password=$genhandler->getNewGeneratedPassword(); + } + } + + print ''; + print ''; if ($user->admin) { @@ -344,16 +467,56 @@ if ($action == 'create') } print ''; - print ''; + print ''; print ''; - print ''; + print ''; print ''; - print ''; + print ''; print ''; - print ''; + print ''; print '
'.$langs->trans("Lastname").'
'; + if ($ldap_nom) + { + print ''; + print $ldap_nom; + } + else + { + print ''; + } + print '
'.$langs->trans("Firstname").'
'; + if ($ldap_prenom) + { + print ''; + print $ldap_prenom; + } + else + { + print ''; + } + print '
'.$langs->trans("Login").'
'; + if ($ldap_login) { - $nomclass="modGeneratePass".ucfirst($conf->global->USER_PASSWORD_GENERATED); - $nomfichier=$nomclass.".class.php"; - //print DOL_DOCUMENT_ROOT."/includes/modules/security/generate/".$nomclass; - require_once(DOL_DOCUMENT_ROOT."/includes/modules/security/generate/".$nomfichier); - $genhandler=new $nomclass($db,$conf,$lang,$user); - $generated_password=$genhandler->getNewGeneratedPassword(); + print ''; + print $ldap_login; } - print '
'.$langs->trans("Password").'
'.$langs->trans("Password").''; + if ($ldap_SID) + { + print 'mot de passe du domaine'; + } + else + { + print ''; + } + print '
'.$langs->trans("Phone").'
'; + if ($ldap_phone) + { + print ''; + print $ldap_phone; + } + else + { + print ''; + } + print '
'.$langs->trans("Fax").'
'; + if ($ldap_fax) + { + print ''; + print $ldap_fax; + } + else + { + print ''; + } + print '
'.$langs->trans("Mobile").'
'; + if ($ldap_mobile) + { + print ''; + print $ldap_mobile; + } + else + { + print ''; + } + print '
'.$langs->trans("EMail").'
'; + if ($ldap_mail) + { + print ''; + print $ldap_mail; + } + else + { + print ''; + } + print '
'.$langs->trans("Note").''; print "