[3733] | 1 | <?php |
---|
| 2 | /** |
---|
| 3 | * Manages LDAP repository connection |
---|
| 4 | * |
---|
| 5 | * @package davical |
---|
| 6 | * @category Technical |
---|
| 7 | * @subpackage ldap |
---|
| 8 | * @author Maxime Delorme <mdelorme@tennaxia.net> |
---|
| 9 | * @copyright Maxime Delorme |
---|
| 10 | * @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | require_once("auth-functions.php"); |
---|
| 14 | |
---|
| 15 | class ldapDrivers |
---|
| 16 | { |
---|
| 17 | /**#@+ |
---|
| 18 | * @access private |
---|
| 19 | */ |
---|
| 20 | |
---|
| 21 | /** |
---|
| 22 | * Holds the LDAP connection parameters |
---|
| 23 | */ |
---|
| 24 | var $connect; |
---|
| 25 | |
---|
| 26 | /**#@-*/ |
---|
| 27 | |
---|
| 28 | |
---|
| 29 | /** |
---|
| 30 | * Constructor. |
---|
| 31 | * @param array $config The configuration data |
---|
| 32 | */ |
---|
| 33 | function ldapDrivers($config){ |
---|
| 34 | $this->__construct($config); |
---|
| 35 | } |
---|
| 36 | |
---|
| 37 | |
---|
| 38 | /** |
---|
| 39 | * Initializes the LDAP connection |
---|
| 40 | * |
---|
| 41 | * @param array $config The configuration data |
---|
| 42 | */ |
---|
| 43 | function __construct($config) |
---|
| 44 | { |
---|
| 45 | global $c; |
---|
| 46 | $host=$config['host']; |
---|
| 47 | $port=$config['port']; |
---|
| 48 | if(!function_exists('ldap_connect')){ |
---|
| 49 | $c->messages[] = i18n("drivers_ldap : function ldap_connect not defined, check your php_ldap module"); |
---|
| 50 | $this->valid=false; |
---|
| 51 | return ; |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | //Set LDAP protocol version |
---|
| 55 | if (isset($config['protocolVersion'])) |
---|
| 56 | ldap_set_option($this->connect, LDAP_OPT_PROTOCOL_VERSION, $config['protocolVersion']); |
---|
| 57 | if (isset($config['optReferrals'])) |
---|
| 58 | ldap_set_option($this->connect, LDAP_OPT_REFERRALS, $config['optReferrals']); |
---|
| 59 | |
---|
| 60 | if ($port) |
---|
| 61 | $this->connect=ldap_connect($host, $port); |
---|
| 62 | else |
---|
| 63 | $this->connect=ldap_connect($host); |
---|
| 64 | |
---|
| 65 | if (! $this->connect){ |
---|
| 66 | $c->messages[] = sprintf(translate( 'drivers_ldap : Unable to connect to LDAP with port %s on host %s'), $port, $host ); |
---|
| 67 | $this->valid=false; |
---|
| 68 | return ; |
---|
| 69 | } |
---|
| 70 | |
---|
| 71 | dbg_error_log( "LDAP", "drivers_ldap : Connected to LDAP server %s",$host ); |
---|
| 72 | |
---|
| 73 | // Start TLS if desired (requires protocol version 3) |
---|
| 74 | if (isset($config['startTLS'])) { |
---|
| 75 | if (!ldap_set_option($this->connect, LDAP_OPT_PROTOCOL_VERSION, 3)) { |
---|
| 76 | $c->messages[] = i18n('drivers_ldap : Failed to set LDAP to use protocol version 3, TLS not supported'); |
---|
| 77 | $this->valid=false; |
---|
| 78 | return; |
---|
| 79 | } |
---|
| 80 | if (!ldap_start_tls($this->connect)) { |
---|
| 81 | $c->messages[] = i18n('drivers_ldap : Could not start TLS: ldap_start_tls() failed'); |
---|
| 82 | $this->valid=false; |
---|
| 83 | return; |
---|
| 84 | } |
---|
| 85 | } |
---|
| 86 | |
---|
| 87 | //Set the search scope to be used, default to subtree. This sets the functions to be called later. |
---|
| 88 | if (!isset($config['scope'])) $config['scope'] = 'subtree'; |
---|
| 89 | switch (strtolower($config['scope'])) { |
---|
| 90 | case "base": |
---|
| 91 | $this->ldap_query_one = 'ldap_read'; |
---|
| 92 | $this->ldap_query_all = 'ldap_read'; |
---|
| 93 | break; |
---|
| 94 | case "onelevel": |
---|
| 95 | $this->ldap_query_one = 'ldap_list'; |
---|
| 96 | $this->ldap_query_all = 'ldap_search'; |
---|
| 97 | break; |
---|
| 98 | default: |
---|
| 99 | $this->ldap_query_one = 'ldap_search'; |
---|
| 100 | $this->ldap_query_all = 'ldap_search'; |
---|
| 101 | break; |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | //connect as root |
---|
| 105 | if (!ldap_bind($this->connect, (isset($config['bindDN']) ? $config['bindDN'] : null), (isset($config['passDN']) ? $config['passDN'] : null) ) ){ |
---|
| 106 | $bindDN = isset($config['bindDN']) ? $config['bindDN'] : 'anonymous'; |
---|
| 107 | $passDN = isset($config['passDN']) ? $config['passDN'] : 'anonymous'; |
---|
| 108 | dbg_error_log( "LDAP", i18n('drivers_ldap : Failed to bind to host %1$s on port %2$s with bindDN of %3$s'), $host, $port, $bindDN ); |
---|
| 109 | $c->messages[] = i18n( 'drivers_ldap : Unable to bind to LDAP - check your configuration for bindDN and passDN, and that your LDAP server is reachable'); |
---|
| 110 | $this->valid=false; |
---|
| 111 | return ; |
---|
| 112 | } |
---|
| 113 | $this->valid = true; |
---|
| 114 | //root to start search |
---|
| 115 | $this->baseDNUsers = is_string($config['baseDNUsers']) ? array($config['baseDNUsers']) : $config['baseDNUsers']; |
---|
| 116 | $this->filterUsers = (isset($config['filterUsers']) ? $config['filterUsers'] : null); |
---|
| 117 | $this->baseDNGroups = is_string($config['baseDNGroups']) ? array($config['baseDNGroups']) : $config['baseDNGroups']; |
---|
| 118 | $this->filterGroups = (isset($config['filterGroups']) ? $config['filterGroups'] : null); |
---|
| 119 | } |
---|
| 120 | |
---|
| 121 | /** |
---|
| 122 | * retorna atributo especifico utilizando determinado filtro |
---|
| 123 | * |
---|
| 124 | * @param string $filter The filter used to search entries |
---|
| 125 | * @param array $attributes Attributes to be returned |
---|
| 126 | * |
---|
| 127 | * feito por Gabriel Gomes Malheiros |
---|
| 128 | * 15/07/2008 |
---|
| 129 | * |
---|
| 130 | */ |
---|
| 131 | |
---|
| 132 | function requestAtributo( $filter, $attributes=NULL) { |
---|
| 133 | |
---|
| 134 | global $c; |
---|
| 135 | $entry=NULL; |
---|
| 136 | // We get the DN of the USER |
---|
| 137 | $host=$c->authenticate_hook['config']['host']; |
---|
| 138 | $port=$c->authenticate_hook['config']['port']; |
---|
| 139 | if(!function_exists('ldap_connect')){ |
---|
| 140 | $c->messages[] = i18n("drivers_ldap : function ldap_connect not defined, check your php_ldap module"); |
---|
| 141 | $this->valid=false; |
---|
| 142 | return ; |
---|
| 143 | } |
---|
| 144 | if ($port) |
---|
| 145 | $connect=ldap_connect($host, $port); |
---|
| 146 | else |
---|
| 147 | $connect=ldap_connect($host); |
---|
| 148 | |
---|
| 149 | if (! $connect){ |
---|
| 150 | $c->messages[] = sprintf(i18n( "drivers_ldap : Unable to connect to LDAP with port %s on host %s"), $port,$host ); |
---|
| 151 | $this->valid=false; |
---|
| 152 | return ; |
---|
| 153 | } |
---|
| 154 | $baseDNUsers = $c->authenticate_hook['config']['baseDNUsers']; |
---|
| 155 | |
---|
| 156 | $entry = ldap_search($connect, $baseDNUsers, $filter,$attributes); |
---|
| 157 | if ( !ldap_first_entry($connect, $entry) ){ |
---|
| 158 | dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); |
---|
| 159 | return false; |
---|
| 160 | } else { |
---|
| 161 | dbg_error_log( "LDAP", "drivers_ldap : Found a user using filter %s",$filter ); |
---|
| 162 | $i = ldap_first_entry($connect,$entry); |
---|
| 163 | $arr = ldap_get_attributes($connect,$i); |
---|
| 164 | for( $i=0; $i<$arr['count']; $i++ ) { |
---|
| 165 | $ret[$arr[$i]]=$arr[$arr[$i]][0]; |
---|
| 166 | } |
---|
| 167 | return $ret; |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | } |
---|
| 171 | /** |
---|
| 172 | * Retrieve all groups from the LDAP directory |
---|
| 173 | */ |
---|
| 174 | function getAllGroups($attributes){ |
---|
| 175 | global $c; |
---|
| 176 | |
---|
| 177 | $query = $this->ldap_query_all; |
---|
| 178 | |
---|
| 179 | foreach($this->baseDNGroups as $baseDNGroups) { |
---|
| 180 | $entry = $query($this->connect,$baseDNGroups,$this->filterGroups,$attributes); |
---|
| 181 | |
---|
| 182 | if (!ldap_first_entry($this->connect,$entry)) { |
---|
| 183 | $c->messages[] = sprintf(translate('Error NoGroupFound with filter >%s<, attributes >%s< , dn >%s<'), |
---|
| 184 | $this->filterGroups, |
---|
| 185 | join(', ', $attributes), |
---|
| 186 | $baseDNGroups); |
---|
| 187 | } |
---|
| 188 | $row = array(); |
---|
| 189 | for($i = ldap_first_entry($this->connect,$entry); |
---|
| 190 | $i && $arr = ldap_get_attributes($this->connect,$i); |
---|
| 191 | $i = ldap_next_entry($this->connect,$i) ) { |
---|
| 192 | for ($j=0; $j < $arr['count']; $j++) { |
---|
| 193 | $row[$arr[$j]] = count($arr[$arr[$j]])>2?$arr[$arr[$j]]:$arr[$arr[$j]][0]; |
---|
| 194 | } |
---|
| 195 | $ret[]=$row; |
---|
| 196 | } |
---|
| 197 | } |
---|
| 198 | return $ret; |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | /** |
---|
| 202 | * Returns the result of the LDAP query |
---|
| 203 | * |
---|
| 204 | * @param string $filter The filter used to search entries |
---|
| 205 | * @param array $attributes Attributes to be returned |
---|
| 206 | * @param string $passwd password to check |
---|
| 207 | * @return array Contains selected attributes from all entries corresponding to the given filter |
---|
| 208 | */ |
---|
| 209 | function requestUser( $filter, $attributes=NULL, $username, $passwd) { |
---|
| 210 | global $c; |
---|
| 211 | |
---|
| 212 | $entry=NULL; |
---|
| 213 | // We get the DN of the USER |
---|
| 214 | $query = $this->ldap_query_one; |
---|
| 215 | |
---|
| 216 | foreach($this->baseDNUsers as $baseDNUsers) { |
---|
| 217 | $entry = $query($this->connect, $baseDNUsers, $filter, $attributes); |
---|
| 218 | |
---|
| 219 | if (ldap_first_entry($this->connect,$entry) ) |
---|
| 220 | break; |
---|
| 221 | |
---|
| 222 | dbg_error_log( "LDAP", "drivers_ldap : Failed to find user with baseDN: %s", $baseDNUsers ); |
---|
| 223 | } |
---|
| 224 | |
---|
| 225 | if ( !ldap_first_entry($this->connect, $entry) ){ |
---|
| 226 | dbg_error_log( "ERROR", "drivers_ldap : Unable to find the user with filter %s",$filter ); |
---|
| 227 | return false; |
---|
| 228 | } else { |
---|
| 229 | dbg_error_log( "LDAP", "drivers_ldap : Found a user using filter %s",$filter ); |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | $dnUser = ldap_get_dn($this->connect, ldap_first_entry($this->connect,$entry)); |
---|
| 233 | |
---|
| 234 | if ( isset($c->authenticate_hook['config']['i_use_mode_kerberos']) && $c->authenticate_hook['config']['i_use_mode_kerberos'] == "i_know_what_i_am_doing") { |
---|
| 235 | dbg_error_log( "LOG", "drivers_ldap : Skipping password Check for user %s which should be the same as %s",$username , $_SERVER["REMOTE_USER"]); |
---|
| 236 | if ($username != $_SERVER["REMOTE_USER"]) { |
---|
| 237 | return false; |
---|
| 238 | } |
---|
| 239 | } else { |
---|
| 240 | if ( !@ldap_bind($this->connect, $dnUser, $passwd) ) { |
---|
| 241 | dbg_error_log( "LDAP", "drivers_ldap : Failed to bind to user %s using password %s", $dnUser, $passwd ); |
---|
| 242 | return false; |
---|
| 243 | } |
---|
| 244 | } |
---|
| 245 | |
---|
| 246 | |
---|
| 247 | dbg_error_log( "LDAP", "drivers_ldap : Bound to user %s using password %s", $dnUser, $passwd ); |
---|
| 248 | |
---|
| 249 | $i = ldap_first_entry($this->connect,$entry); |
---|
| 250 | $arr = ldap_get_attributes($this->connect,$i); |
---|
| 251 | for( $i=0; $i<$arr['count']; $i++ ) { |
---|
| 252 | $ret[$arr[$i]]=$arr[$arr[$i]][0]; |
---|
| 253 | } |
---|
| 254 | return $ret; |
---|
| 255 | |
---|
| 256 | } |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | |
---|
| 260 | /** |
---|
| 261 | * A generic function to create and fetch static objects |
---|
| 262 | */ |
---|
| 263 | function getStaticLdap() { |
---|
| 264 | global $c; |
---|
| 265 | // Declare a static variable to hold the object instance |
---|
| 266 | static $instance; |
---|
| 267 | |
---|
| 268 | // If the instance is not there, create one |
---|
| 269 | if(!isset($instance)) { |
---|
| 270 | $ldapDrivers =& new ldapDrivers($c->authenticate_hook['config']); |
---|
| 271 | } |
---|
| 272 | return $ldapDrivers; |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | |
---|
| 276 | /** |
---|
| 277 | * Synchronise a cached user with one from LDAP |
---|
| 278 | * @param object $usr A user record to be updated (or created) |
---|
| 279 | */ |
---|
| 280 | function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) { |
---|
| 281 | global $c; |
---|
| 282 | |
---|
| 283 | dbg_error_log( "LDAP", "Going to sync the user from LDAP" ); |
---|
| 284 | $validUserFields = get_fields('usr'); |
---|
| 285 | |
---|
| 286 | if ( isset($c->authenticate_hook['config']['default_value']) && is_array($c->authenticate_hook['config']['default_value']) ) { |
---|
| 287 | foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { |
---|
| 288 | if ( isset($validUserFields[$field]) ) { |
---|
| 289 | $usr->{$field} = $value; |
---|
| 290 | dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value ); |
---|
| 291 | } |
---|
| 292 | } |
---|
| 293 | } |
---|
| 294 | |
---|
| 295 | foreach ( $mapping as $field => $value ) { |
---|
| 296 | dbg_error_log( "LDAP", "Considering copying %s", $field ); |
---|
| 297 | if ( isset($validUserFields[$field]) ) { |
---|
| 298 | $usr->{$field} = $ldap_values[$value]; |
---|
| 299 | dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value ); |
---|
| 300 | } |
---|
| 301 | } |
---|
| 302 | |
---|
| 303 | UpdateUserFromExternal( $usr ); |
---|
| 304 | } |
---|
| 305 | |
---|
| 306 | |
---|
| 307 | /** |
---|
| 308 | * Check the username / password against the LDAP server |
---|
| 309 | */ |
---|
| 310 | function LDAP_check($username, $password ){ |
---|
| 311 | global $c; |
---|
| 312 | |
---|
| 313 | $ldapDriver = getStaticLdap(); |
---|
| 314 | if ( !$ldapDriver->valid ) { |
---|
| 315 | dbg_error_log( "ERROR", "Couldn't contact LDAP server for authentication" ); |
---|
| 316 | return false; |
---|
| 317 | } |
---|
| 318 | |
---|
| 319 | $mapping = $c->authenticate_hook['config']['mapping_field']; |
---|
| 320 | $attributes = array_values($mapping); |
---|
| 321 | |
---|
| 322 | /** |
---|
| 323 | * If the config contains a filter that starts with a ( then believe |
---|
| 324 | * them and don't modify it, otherwise wrap the filter. |
---|
| 325 | */ |
---|
| 326 | $filter_munge = ""; |
---|
| 327 | if ( preg_match( '/^\(/', $ldapDriver->filterUsers ) ) { |
---|
| 328 | $filter_munge = $ldapDriver->filterUsers; |
---|
| 329 | } |
---|
| 330 | else if ( isset($ldapDriver->filterUsers) && $ldapDriver->filterUsers != '' ) { |
---|
| 331 | $filter_munge = "($ldapDriver->filterUsers)"; |
---|
| 332 | } |
---|
| 333 | |
---|
| 334 | $filter = "(&$filter_munge(".$mapping["username"]."=$username))"; |
---|
| 335 | $valid = $ldapDriver->requestUser( $filter, $attributes, $username, $password ); |
---|
| 336 | |
---|
| 337 | // is a valid user or not |
---|
| 338 | if ( !$valid ) { |
---|
| 339 | dbg_error_log( "LDAP", "user %s is not a valid user",$username ); |
---|
| 340 | return false; |
---|
| 341 | } |
---|
| 342 | |
---|
| 343 | $ldap_timestamp = $valid[$mapping["updated"]]; |
---|
| 344 | |
---|
| 345 | /** |
---|
| 346 | * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S |
---|
| 347 | */ |
---|
| 348 | foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) |
---|
| 349 | $$k = substr($ldap_timestamp,$v[0],$v[1]); |
---|
| 350 | |
---|
| 351 | $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; |
---|
| 352 | $valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S"; |
---|
| 353 | |
---|
| 354 | if ( $usr = getUserByName($username) ) { |
---|
| 355 | // should we update it ? |
---|
| 356 | $db_timestamp = $usr->updated; |
---|
| 357 | $db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14); |
---|
| 358 | if($ldap_timestamp <= $db_timestamp) { |
---|
| 359 | return $usr; // no need to update |
---|
| 360 | } |
---|
| 361 | // we will need to update the user record |
---|
| 362 | } |
---|
| 363 | else { |
---|
| 364 | dbg_error_log( "LDAP", "user %s doesn't exist in local DB, we need to create it",$username ); |
---|
| 365 | $usr = (object) array( 'user_no' => 0 ); |
---|
| 366 | } |
---|
| 367 | |
---|
| 368 | // The local cached user doesn't exist, or is older, so we create/update their details |
---|
| 369 | sync_user_from_LDAP($usr, $mapping, $valid ); |
---|
| 370 | |
---|
| 371 | return $usr; |
---|
| 372 | |
---|
| 373 | } |
---|
| 374 | |
---|
| 375 | /** |
---|
| 376 | * sync LDAP Groups against the DB |
---|
| 377 | */ |
---|
| 378 | function sync_LDAP_groups(){ |
---|
| 379 | global $c; |
---|
| 380 | $ldapDriver = getStaticLdap(); |
---|
| 381 | if($ldapDriver->valid){ |
---|
| 382 | $mapping = $c->authenticate_hook['config']['group_mapping_field']; |
---|
| 383 | //$attributes = array('cn','modifyTimestamp','memberUid'); |
---|
| 384 | $attributes = array_values($mapping); |
---|
| 385 | $ldap_groups_tmp = $ldapDriver->getAllGroups($attributes); |
---|
| 386 | |
---|
| 387 | if ( sizeof($ldap_groups_tmp) == 0 ) |
---|
| 388 | return; |
---|
| 389 | |
---|
| 390 | foreach($ldap_groups_tmp as $key => $ldap_group){ |
---|
| 391 | $ldap_groups_info[$ldap_group[$mapping['username']]] = $ldap_group; |
---|
| 392 | if (is_array($ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']])) { |
---|
| 393 | unset ( $ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']]['count'] ); |
---|
| 394 | } |
---|
| 395 | else { |
---|
| 396 | $ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']] = array($ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']]); |
---|
| 397 | } |
---|
| 398 | unset($ldap_groups_tmp[$key]); |
---|
| 399 | } |
---|
| 400 | $db_groups = array (); |
---|
| 401 | $db_group_members = array (); |
---|
| 402 | $qry = new AwlQuery( "SELECT g.username AS group_name, member.username AS member_name FROM dav_principal g JOIN group_member ON (g.principal_id=group_member.group_id) JOIN dav_principal member ON (member.principal_id=group_member.member_id) WHERE g.type_id = 3"); |
---|
| 403 | $qry->Exec('sync_LDAP',__LINE__,__FILE__); |
---|
| 404 | while($db_group = $qry->Fetch()) { |
---|
| 405 | $db_groups[$db_group->group_name] = $db_group->group_name; |
---|
| 406 | $db_group_members[$db_group->group_name][] = $db_group->member_name; |
---|
| 407 | } |
---|
| 408 | |
---|
| 409 | $ldap_groups = array_keys($ldap_groups_info); |
---|
| 410 | // users only in ldap |
---|
| 411 | $groups_to_create = array_diff($ldap_groups,$db_groups); |
---|
| 412 | // users only in db |
---|
| 413 | $groups_to_deactivate = array_diff($db_groups,$ldap_groups); |
---|
| 414 | // users present in ldap and in the db |
---|
| 415 | $groups_to_update = array_intersect($db_groups,$ldap_groups); |
---|
| 416 | |
---|
| 417 | if ( sizeof ( $groups_to_create ) ){ |
---|
| 418 | $c->messages[] = sprintf(i18n('- creating groups : %s'),join(', ',$groups_to_create)); |
---|
| 419 | $validUserFields = get_fields('usr'); |
---|
| 420 | foreach ( $groups_to_create as $k => $group ){ |
---|
| 421 | $user = (object) array( 'user_no' => 0, 'username' => '' ); |
---|
| 422 | |
---|
| 423 | if ( isset($c->authenticate_hook['config']['default_value']) && is_array($c->authenticate_hook['config']['default_value']) ) { |
---|
| 424 | foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) { |
---|
| 425 | if ( isset($validUserFields[$field]) ) { |
---|
| 426 | $usr->{$field} = $value; |
---|
| 427 | dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value ); |
---|
| 428 | } |
---|
| 429 | } |
---|
| 430 | } |
---|
| 431 | $user->user_no = 0; |
---|
| 432 | $ldap_values = $ldap_groups_info[$group]; |
---|
| 433 | foreach ( $mapping as $field => $value ) { |
---|
| 434 | dbg_error_log( "LDAP", "Considering copying %s", $field ); |
---|
| 435 | if ( isset($validUserFields[$field]) ) { |
---|
| 436 | $user->{$field} = $ldap_values[$value]; |
---|
| 437 | dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value ); |
---|
| 438 | } |
---|
| 439 | } |
---|
| 440 | if ($user->fullname=="") { |
---|
| 441 | $user->fullname = $group; |
---|
| 442 | } |
---|
| 443 | if ($user->displayname=="") { |
---|
| 444 | $user->displayname = $group; |
---|
| 445 | } |
---|
| 446 | $user->username = $group; |
---|
| 447 | $user->updated = "now"; /** @todo Use the 'updated' timestamp from LDAP for groups too */ |
---|
| 448 | |
---|
| 449 | UpdateUserFromExternal( $user ); |
---|
| 450 | $qry = new AwlQuery( "UPDATE dav_principal set type_id = 3 WHERE username=:group ",array(':group'=>$group) ); |
---|
| 451 | $qry->Exec('sync_LDAP',__LINE__,__FILE__); |
---|
| 452 | $c->messages[] = sprintf(i18n('- adding users %s to group : %s'),join(',',$ldap_groups_info[$group][$mapping['members']]),$group); |
---|
| 453 | foreach ( $ldap_groups_info[$group][$mapping['members']] as $member ){ |
---|
| 454 | $qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member;",array (':group'=>$group,':member'=>$member) ); |
---|
| 455 | $qry->Exec('sync_LDAP_groups',__LINE__,__FILE__); |
---|
| 456 | } |
---|
| 457 | } |
---|
| 458 | } |
---|
| 459 | |
---|
| 460 | if ( sizeof ( $groups_to_update ) ){ |
---|
| 461 | $c->messages[] = sprintf(i18n('- updating groups : %s'),join(', ',$groups_to_update)); |
---|
| 462 | foreach ( $groups_to_update as $group ){ |
---|
| 463 | $db_members = array_values ( $db_group_members[$group] ); |
---|
| 464 | $ldap_members = array_values ( $ldap_groups_info[$group][$mapping['members']] ); |
---|
| 465 | $add_users = array_diff ( $ldap_members, $db_members ); |
---|
| 466 | if ( sizeof ( $add_users ) ){ |
---|
| 467 | $c->messages[] = sprintf(i18n('- adding %s to group : %s'),join(', ', $add_users ), $group); |
---|
| 468 | foreach ( $add_users as $member ){ |
---|
| 469 | $qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member",array (':group'=>$group,':member'=>$member) ); |
---|
| 470 | $qry->Exec('sync_LDAP_groups',__LINE__,__FILE__); |
---|
| 471 | } |
---|
| 472 | } |
---|
| 473 | $remove_users = array_diff ( $db_members, $ldap_members ); |
---|
| 474 | if ( sizeof ( $remove_users ) ){ |
---|
| 475 | $c->messages[] = sprintf(i18n('- removing %s from group : %s'),join(', ', $remove_users ), $group); |
---|
| 476 | foreach ( $remove_users as $member ){ |
---|
| 477 | $qry = new AwlQuery( "DELETE FROM group_member USING dav_principal g,dav_principal m WHERE group_id=g.principal_id AND member_id=m.principal_id AND g.username=:group AND m.username=:member",array (':group'=>$group,':member'=>$member) ); |
---|
| 478 | $qry->Exec('sync_LDAP_groups',__LINE__,__FILE__); |
---|
| 479 | } |
---|
| 480 | } |
---|
| 481 | } |
---|
| 482 | } |
---|
| 483 | |
---|
| 484 | if ( sizeof ( $groups_to_deactivate ) ){ |
---|
| 485 | $c->messages[] = sprintf(i18n('- deactivate groups : %s'),join(', ',$groups_to_deactivate)); |
---|
| 486 | foreach ( $groups_to_deactivate as $group ){ |
---|
| 487 | $qry = new AwlQuery( "UPDATE dav_principal set active='f'::bool WHERE username=:group AND type_id = 3",array(':group'=>$group) ); |
---|
| 488 | $qry->Exec('sync_LDAP',__LINE__,__FILE__); |
---|
| 489 | } |
---|
| 490 | } |
---|
| 491 | } |
---|
| 492 | } |
---|
| 493 | |
---|
| 494 | /** |
---|
| 495 | * sync LDAP against the DB |
---|
| 496 | */ |
---|
| 497 | function sync_LDAP(){ |
---|
| 498 | global $c; |
---|
| 499 | $ldapDriver = getStaticLdap(); |
---|
| 500 | if($ldapDriver->valid){ |
---|
| 501 | $mapping = $c->authenticate_hook['config']['mapping_field']; |
---|
| 502 | $attributes = array_values($mapping); |
---|
| 503 | $ldap_users_tmp = $ldapDriver->getAllUsers($attributes); |
---|
| 504 | |
---|
| 505 | if ( sizeof($ldap_users_tmp) == 0 ) |
---|
| 506 | return; |
---|
| 507 | |
---|
| 508 | foreach($ldap_users_tmp as $key => $ldap_user){ |
---|
| 509 | $ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user; |
---|
| 510 | unset($ldap_users_tmp[$key]); |
---|
| 511 | } |
---|
| 512 | $qry = new AwlQuery( "SELECT username, user_no, modified as updated FROM dav_principal where type_id=1"); |
---|
| 513 | $qry->Exec('sync_LDAP',__LINE__,__FILE__); |
---|
| 514 | while($db_user = $qry->Fetch()) { |
---|
| 515 | $db_users[] = $db_user->username; |
---|
| 516 | $db_users_info[$db_user->username] = array('user_no' => $db_user->user_no, 'updated' => $db_user->updated); |
---|
| 517 | } |
---|
| 518 | |
---|
| 519 | $ldap_users = array_keys($ldap_users_info); |
---|
| 520 | // users only in ldap |
---|
| 521 | $users_to_create = array_diff($ldap_users,$db_users); |
---|
| 522 | // users only in db |
---|
| 523 | $users_to_deactivate = array_diff($db_users,$ldap_users); |
---|
| 524 | // users present in ldap and in the db |
---|
| 525 | $users_to_update = array_intersect($db_users,$ldap_users); |
---|
| 526 | |
---|
| 527 | // creation of all users; |
---|
| 528 | if ( sizeof($users_to_create) ) { |
---|
| 529 | $c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create)); |
---|
| 530 | |
---|
| 531 | foreach( $users_to_create as $username ) { |
---|
| 532 | $user = (object) array( 'user_no' => 0, 'username' => $username ); |
---|
| 533 | $valid = $ldap_users_info[$username]; |
---|
| 534 | $ldap_timestamp = $valid[$mapping["updated"]]; |
---|
| 535 | |
---|
| 536 | /** |
---|
| 537 | * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S |
---|
| 538 | */ |
---|
| 539 | foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) |
---|
| 540 | $$k = substr($ldap_timestamp,$v[0],$v[1]); |
---|
| 541 | $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; |
---|
| 542 | $valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S"; |
---|
| 543 | |
---|
| 544 | sync_user_from_LDAP( $user, $mapping, $valid ); |
---|
| 545 | } |
---|
| 546 | } |
---|
| 547 | |
---|
| 548 | // deactivating all users |
---|
| 549 | $params = array(); |
---|
| 550 | $i = 0; |
---|
| 551 | foreach( $users_to_deactivate AS $v ) { |
---|
| 552 | if ( isset($c->do_not_sync_from_ldap) && isset($c->do_not_sync_from_ldap[$v]) ) continue; |
---|
| 553 | $params[':u'.$i++] = strtolower($v); |
---|
| 554 | } |
---|
| 555 | if ( count($params) > 0 ) { |
---|
| 556 | $c->messages[] = sprintf(i18n('- deactivating users : %s'),join(', ',$users_to_deactivate)); |
---|
| 557 | $qry = new AwlQuery( 'UPDATE usr SET active = FALSE WHERE lower(username) IN ('.implode(',',array_keys($params)).')', $params); |
---|
| 558 | $qry->Exec('sync_LDAP',__LINE__,__FILE__); |
---|
| 559 | } |
---|
| 560 | |
---|
| 561 | // updating all users |
---|
| 562 | if ( sizeof($users_to_update) ) { |
---|
| 563 | foreach ( $users_to_update as $key=> $username ) { |
---|
| 564 | $valid=$ldap_users_info[$username]; |
---|
| 565 | $ldap_timestamp = $valid[$mapping["updated"]]; |
---|
| 566 | |
---|
| 567 | $valid["user_no"] = $db_users_info[$username]["user_no"]; |
---|
| 568 | $mapping["user_no"] = "user_no"; |
---|
| 569 | |
---|
| 570 | /** |
---|
| 571 | * This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S |
---|
| 572 | */ |
---|
| 573 | foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) |
---|
| 574 | $$k = substr($ldap_timestamp,$v[0],$v[1]); |
---|
| 575 | $ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S"; |
---|
| 576 | $valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S"; |
---|
| 577 | |
---|
| 578 | $db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14); |
---|
| 579 | if ( $ldap_timestamp > $db_timestamp ) { |
---|
| 580 | sync_user_from_LDAP($usr, $mapping, $valid ); |
---|
| 581 | } |
---|
| 582 | else { |
---|
| 583 | unset($users_to_update[$key]); |
---|
| 584 | $users_nothing_done[] = $username; |
---|
| 585 | } |
---|
| 586 | } |
---|
| 587 | if ( sizeof($users_to_update) ) |
---|
| 588 | $c->messages[] = sprintf(i18n('- updating user records : %s'),join(', ',$users_to_update)); |
---|
| 589 | if ( sizeof($users_nothing_done) ) |
---|
| 590 | $c->messages[] = sprintf(i18n('- nothing done on : %s'),join(', ', $users_nothing_done)); |
---|
| 591 | } |
---|
| 592 | |
---|
| 593 | $admins = 0; |
---|
| 594 | $qry = new AwlQuery( "select count(*) as admins from usr join role_member using ( user_no ) join roles using (role_no) where usr.active = true and role_name='Admin'"); |
---|
| 595 | $qry->Exec('sync_LDAP',__LINE__,__FILE__); |
---|
| 596 | while($db_user = $qry->Fetch()) { |
---|
| 597 | $admins = $db_user->admins; |
---|
| 598 | } |
---|
| 599 | if ( $admins == 0 ) { |
---|
| 600 | $c->messages[] = sprintf(i18n('Warning: there are no active admin users, you should fix this before logging out.')); |
---|
| 601 | } |
---|
| 602 | } |
---|
| 603 | } |
---|