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 | } |
---|