diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php index d5c7faff..0d94335d 100644 --- a/inc/drivers_ldap.php +++ b/inc/drivers_ldap.php @@ -2,14 +2,15 @@ /** * Manages LDAP repository connection * -* @package rscds +* @package davical * @category Technical -* @subpackage caldav +* @subpackage ldap * @author Maxime Delorme * @copyright Maxime Delorme * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 */ +require_once("auth-functions.php"); class ldapDrivers { @@ -80,20 +81,20 @@ class ldapDrivers /** * Retrieve all users from the LDAP directory */ - function getAllUsers($attributs){ + function getAllUsers($attributes){ global $c; - $entry = ldap_list($this->connect,$this->baseDNUsers,$this->filterUsers,$attributs); + $entry = ldap_list($this->connect,$this->baseDNUsers,$this->filterUsers,$attributes); if (!ldap_first_entry($this->connect,$entry)) - $c->messages[] = sprintf(i18n("Error NoUserFound with filter >%s<, attributs >%s< , dn >%s<"),$this->filterUsers,join(', ',$attributs), $this->baseDNUsers); + $c->messages[] = sprintf(i18n("Error NoUserFound with filter >%s<, attributes >%s< , dn >%s<"),$this->filterUsers,join(', ',$attributes), $this->baseDNUsers); for($i=ldap_first_entry($this->connect,$entry); $i&&$arr=ldap_get_attributes($this->connect,$i); $i=ldap_next_entry($this->connect,$i) ) { - for($j=0;$j<$arr['count'];$j++){ - $row[$arr[$j]] = $arr[$arr[$j]][0]; - } - $ret[]=$row; + for($j=0;$j<$arr['count'];$j++){ + $row[$arr[$j]] = $arr[$arr[$j]][0]; + } + $ret[]=$row; } return $ret; } @@ -102,30 +103,29 @@ class ldapDrivers * Returns the result of the LDAP query * * @param string $filter The filter used to search entries - * @param array $attributs Attributes to be returned + * @param array $attributes Attributes to be returned * @param string $passwd password to check * @return array Contains selected attributes from all entries corresponding to the given filter */ - function requestUser($filter,$attributs=NULL,$passwd) - { + function requestUser( $filter, $attributes=NULL, $passwd) { - $entry=NULL; - // We get the DN of the USER - $entry = ldap_search($this->connect,$this->baseDNUsers,$filter,$attributs); - if ( !ldap_first_entry($this->connect,$entry) ){ - dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); - return false; - } - $dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry)); - if(!@ldap_bind($this->connect,$dnUser,$passwd)) - return false; + $entry=NULL; + // We get the DN of the USER + $entry = ldap_search($this->connect, $this->baseDNUsers, $filter,$attributs); + if ( !ldap_first_entry($this->connect, $entry) ){ + dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); + return false; + } + $dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry)); + if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) + return false; - $i=ldap_first_entry($this->connect,$entry); - $arr=ldap_get_attributes($this->connect,$i); - for($i=0;$i<$arr['count'];$i++){ - $ret[$arr[$i]]=$arr[$arr[$i]][0]; - } - return $ret; + $i = ldap_first_entry($this->connect,$entry); + $arr = ldap_get_attributes($this->connect,$i); + for( $i=0; $i<$arr['count']; $i++ ) { + $ret[$arr[$i]]=$arr[$arr[$i]][0]; + } + return $ret; } } @@ -146,70 +146,93 @@ function getStaticLdap() { return $ldapDrivers; } + +/** +* Synchronise a cached user with one from LDAP +* @param object $usr A user record to be updated (or created) +*/ +function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ); + $validUserFields = get_fields('usr'); + + foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { + if ( in_array($field, $validUserFields) ) $usr->{$field} = $value; + } + + foreach ( $mapping as $field => $value ) { + if ( in_array($field, $validUserFields) ) $usr->{$field} = $ldap_values[$value]; + } + + $user->updated = "$Y-$m-$d $H:$M:$S"; + + UpdateUserFromExternal( $usr ); +} + + /** * Check the username / password against the LDAP server */ function LDAP_check($username, $password ){ global $c; + $ldapDriver = getStaticLdap(); - if ( $ldapDriver->valid ) { - $mapping = $c->authenticate_hook['config']['mapping_field']; - $attributs=array_values($mapping); - - // If the config contains a filter that starts with a ( then believe - // them and don't modify it, otherwise wrap the filter. - $filter_munge = ""; - if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) { - $filter_munge = $ldapDriver->filterUsers; - } else { - $filter_munge = "($ldapDriver->filterUsers)"; - } - - $filter="(&$filter_munge(".$mapping["username"]."=$username))"; - dbg_error_log( "LDAP", "checking user %s for password %s against LDAP",$username,$password ); - $valid = $ldapDriver->requestUser($filter,$attributs,$password); - - //is a valid user or not - if ( !$valid ) return false; - - - $ldap_timestamp = $valid[$mapping["updated"]]; - foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) - $$k = substr($ldap_timestamp,$v[0],$v[1]); - - //ok it is valid is already exist in db ? - $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; - if ( $usr = getUserByName($username) ){ - //should we update it ? - $db_timestamp = $usr->updated; - $db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14); - if($ldap_timestamp <= $db_timestamp){ - return $usr;//no need to update - } - //we should update the user record - } - - //it doesn't exist so we create the new user or if we should be updated the user record - require_once("RSCDSUser.php"); - - $user_no = ( isset($usr->user_no) ? $usr->user_no:0); - $user = new RSCDSUser($user_no); - $validUserField = array_keys($user->Fields); - - foreach($c->authenticate_hook['config']['default_value'] as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $value); - - foreach($mapping as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]); - - $user->Set("updated", "$Y-$m-$d $H:$M:$S"); - $user->write(); + if ( !$ldapDriver->valid ) { + dbg_error_log( "ERROR", "Couldn't contact LDAP server for authentication" ); + return false; } - if ( $return = getUserByName($username) ){ - return $return; + $mapping = $c->authenticate_hook['config']['mapping_field']; + $attributes = array_values($mapping); + + /** + * If the config contains a filter that starts with a ( then believe + * them and don't modify it, otherwise wrap the filter. + */ + $filter_munge = ""; + if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) { + $filter_munge = $ldapDriver->filterUsers; } + else { + $filter_munge = "($ldapDriver->filterUsers)"; + } + + $filter = "(&$filter_munge(".$mapping["username"]."=$username))"; + dbg_error_log( "LDAP", "checking user %s for password %s against LDAP",$username,$password ); + $valid = $ldapDriver->requestUser( $filter, $attributes, $password ); + + // is a valid user or not + if ( !$valid ) return false; + + $ldap_timestamp = $valid[$mapping["updated"]]; + + /** + * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S + */ + foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) + $$k = substr($ldap_timestamp,$v[0],$v[1]); + + // ok it is valid is already exist in db ? + $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + if ( $usr = getUserByName($username) ) { + // should we update it ? + $db_timestamp = $usr->updated; + $db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14); + if($ldap_timestamp <= $db_timestamp) { + return $usr; // no need to update + } + // we will need to update the user record + } + else { + $usr = (object) array( 'user_no' => 0 ); + } + + // The local cached user doesn't exist, or is older, so we create/update their details + sync_user_from_LDAP($usr, $mapping, $valid ); + + return $usr; + } + + /** * sync LDAP against the DB */ @@ -218,80 +241,75 @@ function sync_LDAP(){ $ldapDriver = getStaticLdap(); if($ldapDriver->valid){ $mapping = $c->authenticate_hook['config']['mapping_field']; - $attributs=array_values($mapping); - $ldap_users_tmp = $ldapDriver->getAllUsers($attributs); + $attributes = array_values($mapping); + $ldap_users_tmp = $ldapDriver->getAllUsers($attributes); foreach($ldap_users_tmp as $key => $ldap_user){ $ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user; unset($ldap_users_tmp[$key]); } - $qry = new PgQuery( "SELECT username ,user_no, updated FROM usr "); + $qry = new PgQuery( "SELECT username, user_no, updated FROM usr "); $qry->Exec('sync_LDAP',__LINE__,__FILE__); while($db_user = $qry->Fetch(true)){ $db_users[] = $db_user['username']; $db_users_info[$db_user['username']] = array('user_no' => $db_user['user_no'], 'updated' => $db_user['updated']); } - require_once("RSCDSUser.php"); + include_once("RSCDSUser.php"); $ldap_users = array_keys($ldap_users_info); - //users only in ldap + // users only in ldap $users_to_create = array_diff($ldap_users,$db_users); - //users only in db - $users_to_desactivate = array_diff($db_users,$ldap_users); - //users present in ldap and in the db + // users only in db + $users_to_deactivate = array_diff($db_users,$ldap_users); + // users present in ldap and in the db $users_to_update = array_intersect($db_users,$ldap_users); - //creation of all users; - if(sizeof($users_to_create)) $c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create)); - foreach($users_to_create as $username){ - $valid=$ldap_users_info[$username]; - $ldap_timestamp = $valid[$mapping["updated"]]; - foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) - $$k = substr($ldap_timestamp,$v[0],$v[1]); - $user = new RSCDSUser(0); - $validUserField = array_keys($user->Fields); - foreach($c->authenticate_hook['config']['default_value'] as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $value); - foreach($mapping as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]); - $user->Set("updated", "$Y-$m-$d $H:$M:$S"); - $messages = $c->messages; - $user->write(); - $c->messages = $messages; + // creation of all users; + if ( sizeof($users_to_create) ) + $c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create)); + + foreach( $users_to_create as $username ) { + $user = (object) array( 'user_no' => 0, 'username' => $username ); + sync_user_from_LDAP( $user, $mapping, $ldap_users_info[$username] ); + } } - //desactivating all users - if(sizeof($users_to_desactivate)){ - foreach( $users_to_desactivate AS $v ) { + + // deactivating all users + if ( sizeof($users_to_deactivate) ) { + foreach( $users_to_deactivate AS $v ) { $usr_in .= ', ' . qpg($v); } $usr_in = substr($usr_in,1); - $c->messages[] = sprintf(i18n('- desactivating users : %s'),$usr_in); - $qry = new PgQuery( "UPDATE usr set active = FALSE WHERE lower(username) in ($usr_in)"); + $c->messages[] = sprintf(i18n('- deactivating users : %s'),$usr_in); + $qry = new PgQuery( "UPDATE usr SET active = FALSE WHERE lower(username) IN ($usr_in)"); $qry->Exec('sync_LDAP',__LINE__,__FILE__); } - //updating all users - foreach($users_to_update as $key=> $username){ - $valid=$ldap_users_info[$username]; - $ldap_timestamp = $valid[$mapping["updated"]]; - foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) - $$k = substr($ldap_timestamp,$v[0],$v[1]); - $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; - $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14); - if($ldap_timestamp > $db_timestamp){ - $user = new RSCDSUser($db_users_info[$username]['user_no']); - $validUserField = array_keys($user->Fields); - foreach($c->authenticate_hook['config']['default_value'] as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $value); - foreach($mapping as $field => $value) - if(in_array($field,$validUserField)) $user->Set($field, $valid[$value]); - $user->Set("updated", "$Y-$m-$d $H:$M:$S"); - $user->write(); - } else { - unset($users_to_update[$key]); - $users_nothing_done[] = $username; + + // updating all users + if ( sizeof($users_to_update) ) { + foreach ( $users_to_update as $key=> $username ) { + $valid=$ldap_users_info[$username]; + $ldap_timestamp = $valid[$mapping["updated"]]; + + /** + * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S + */ + foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) + $$k = substr($ldap_timestamp,$v[0],$v[1]); + $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; + + $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14); + if ( $ldap_timestamp > $db_timestamp ) { + sync_user_from_LDAP($usr, $mapping, $valid ); + } + else { + unset($users_to_update[$key]); + $users_nothing_done[] = $username; + } } + $c->messages[] = sprintf(i18n('- updating user record %s'),join(', ',$users_to_update)); + if ( sizeof($users_nothing_done) ) + $c->messages[] = sprintf(i18n('- nothing done on %s'),join(', ', $users_nothing_done)); } - if(sizeof($users_to_update)) $c->messages[] = sprintf(i18n('- updating user record %s'),join(', ',$users_to_update)); - if(sizeof($users_nothing_done))$c->messages[] = sprintf(i18n('- nothing done on %s'),join(', ', $users_nothing_done)); } } -?> +