Exponential 6.0.13 Exponential Enterprise Open Source CMS - PHP Class Reference

ezldapuser.php
Go to the documentation of this file.
1 <?php
17 class eZLDAPUser extends eZUser
18 {
24 static function loginUser( $login, $password, $authenticationMatch = false )
25 {
26 $http = eZHTTPTool::instance();
27 $db = eZDB::instance();
28
29 if ( $authenticationMatch === false )
30 $authenticationMatch = eZUser::authenticationMatch();
31
32 $loginEscaped = $db->escapeString( $login );
33 $passwordEscaped = $db->escapeString( $password );
34
35 $loginLdapEscaped = self::ldap_escape( $login );
36
37 $loginArray = array();
38 if ( $authenticationMatch & eZUser::AUTHENTICATE_LOGIN )
39 $loginArray[] = "login='$loginEscaped'";
40 if ( $authenticationMatch & eZUser::AUTHENTICATE_EMAIL )
41 $loginArray[] = "email='$loginEscaped'";
42 if ( count( $loginArray ) == 0 )
43 $loginArray[] = "login='$loginEscaped'";
44 $loginText = implode( ' OR ', $loginArray );
45
46 $contentObjectStatus = eZContentObject::STATUS_PUBLISHED;
47
48 $ini = eZINI::instance();
49 $LDAPIni = eZINI::instance( 'ldap.ini' );
50 $databaseName = $db->databaseName();
51 // if mysql
52 if ( $databaseName === 'mysql' )
53 {
54 $query = "SELECT contentobject_id, password_hash, password_hash_type, email, login
55 FROM ezuser, ezcontentobject
56 WHERE ( $loginText ) AND
57 ezcontentobject.status='$contentObjectStatus' AND
58 ( ezcontentobject.id=contentobject_id OR ( password_hash_type=4 AND ( $loginText ) AND password_hash=PASSWORD('$passwordEscaped') ) )";
59 }
60 else
61 {
62 $query = "SELECT contentobject_id, password_hash, password_hash_type, email, login
63 FROM ezuser, ezcontentobject
64 WHERE ( $loginText ) AND
65 ezcontentobject.status='$contentObjectStatus' AND
66 ezcontentobject.id=contentobject_id";
67 }
68
69 $users = $db->arrayQuery( $query );
70 $exists = false;
71 if ( count( $users ) >= 1 )
72 {
73 foreach ( $users as $userRow )
74 {
75 $userID = $userRow['contentobject_id'];
76 $hashType = $userRow['password_hash_type'];
77 $hash = $userRow['password_hash'];
78 $exists = eZUser::authenticateHash( $userRow['login'], $password, eZUser::site(),
79 $hashType,
80 $hash );
81
82 // If hash type is MySql
83 if ( $hashType == eZUser::PASSWORD_HASH_MYSQL and $databaseName === 'mysql' )
84 {
85 $queryMysqlUser = "SELECT contentobject_id, password_hash, password_hash_type, email, login
86 FROM ezuser, ezcontentobject
87 WHERE ezcontentobject.status='$contentObjectStatus' AND
88 password_hash_type=4 AND ( $loginText ) AND password_hash=PASSWORD('$passwordEscaped') ";
89 $mysqlUsers = $db->arrayQuery( $queryMysqlUser );
90 if ( count( $mysqlUsers ) >= 1 )
91 $exists = true;
92 }
93
94 // If current user has been disabled after a few failed login attempts.
95 $canLogin = eZUser::isEnabledAfterFailedLogin( $userID );
96
97 if ( $exists )
98 {
99 eZDebugSetting::writeDebug( 'kernel-user', eZUser::createHash( $userRow['login'], $password, eZUser::site(),
100 $hashType ), "check hash" );
101 eZDebugSetting::writeDebug( 'kernel-user', $hash, "stored hash" );
102
103 // We should store userID for warning message.
104 $GLOBALS['eZFailedLoginAttemptUserID'] = $userID;
105
106 $userSetting = eZUserSetting::fetch( $userID );
107 $isEnabled = $userSetting->attribute( "is_enabled" );
108 if ( $hashType != eZUser::hashType() and
109 strtolower( $ini->variable( 'UserSettings', 'UpdateHash' ) ) == 'true' )
110 {
111 $hashType = eZUser::hashType();
112 $hash = eZUser::createHash( $login, $password, eZUser::site(),
113 $hashType );
114 $db->query( "UPDATE ezuser SET password_hash='$hash', password_hash_type='$hashType' WHERE contentobject_id='$userID'" );
115 }
116 break;
117 }
118 }
119 }
120 if ( $exists and $isEnabled and $canLogin )
121 {
122 eZDebugSetting::writeDebug( 'kernel-user', $userRow, 'user row' );
123 $user = new eZUser( $userRow );
124 eZDebugSetting::writeDebug( 'kernel-user', $user, 'user' );
125 $userID = $user->attribute( 'contentobject_id' );
126
127 eZUser::updateLastVisit( $userID );
128 eZUser::setCurrentlyLoggedInUser( $user, $userID );
129
130 // Reset number of failed login attempts
131 eZUser::setFailedLoginAttempts( $userID, 0 );
132
133 return $user;
134 }
135 else if ( $LDAPIni->variable( 'LDAPSettings', 'LDAPEnabled' ) === 'true' )
136 {
137 // read LDAP ini settings
138 // and then try to bind to the ldap server
139
140 $LDAPDebugTrace = $LDAPIni->variable( 'LDAPSettings', 'LDAPDebugTrace' ) === 'enabled';
141 $LDAPVersion = $LDAPIni->variable( 'LDAPSettings', 'LDAPVersion' );
142 $LDAPServer = $LDAPIni->variable( 'LDAPSettings', 'LDAPServer' );
143 $LDAPPort = $LDAPIni->variable( 'LDAPSettings', 'LDAPPort' );
144 $LDAPFollowReferrals = (int) $LDAPIni->variable( 'LDAPSettings', 'LDAPFollowReferrals' );
145 $LDAPBaseDN = $LDAPIni->variable( 'LDAPSettings', 'LDAPBaseDn' );
146 $LDAPBindUser = $LDAPIni->variable( 'LDAPSettings', 'LDAPBindUser' );
147 $LDAPBindPassword = $LDAPIni->variable( 'LDAPSettings', 'LDAPBindPassword' );
148 $LDAPSearchScope = $LDAPIni->variable( 'LDAPSettings', 'LDAPSearchScope' );
149
150 $LDAPLoginAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPLoginAttribute' ) );
151 $LDAPFirstNameAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPFirstNameAttribute' ) );
152 $LDAPFirstNameIsCN = $LDAPIni->variable( 'LDAPSettings', 'LDAPFirstNameIsCommonName' ) === 'true';
153 $LDAPLastNameAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPLastNameAttribute' ) );
154 $LDAPEmailAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPEmailAttribute' ) );
155
156 $defaultUserPlacement = $ini->variable( "UserSettings", "DefaultUserPlacement" );
157
158 $LDAPUserGroupAttributeType = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupAttributeType' ) );
159 $LDAPUserGroupAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupAttribute' ) );
160
161 if ( $LDAPIni->hasVariable( 'LDAPSettings', 'Utf8Encoding' ) )
162 {
163 $Utf8Encoding = $LDAPIni->variable( 'LDAPSettings', 'Utf8Encoding' );
164 if ( $Utf8Encoding == "true" )
165 $isUtf8Encoding = true;
166 else
167 $isUtf8Encoding = false;
168 }
169 else
170 {
171 $isUtf8Encoding = false;
172 }
173
174 if ( $LDAPIni->hasVariable( 'LDAPSettings', 'LDAPSearchFilters' ) )
175 {
176 $LDAPFilters = $LDAPIni->variable( 'LDAPSettings', 'LDAPSearchFilters' );
177 }
178 if ( $LDAPIni->hasVariable( 'LDAPSettings', 'LDAPUserGroupType' ) and $LDAPIni->hasVariable( 'LDAPSettings', 'LDAPUserGroup' ) )
179 {
180 $LDAPUserGroupType = $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupType' );
181 $LDAPUserGroup = $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroup' );
182 }
183
184 $LDAPFilter = "( &";
185 if ( count( $LDAPFilters ) > 0 )
186 {
187 foreach ( array_keys( $LDAPFilters ) as $key )
188 {
189 $LDAPFilter .= "(" . $LDAPFilters[$key] . ")";
190 }
191 }
192 $LDAPEqualSign = trim($LDAPIni->variable( 'LDAPSettings', "LDAPEqualSign" ) );
193 $LDAPBaseDN = str_replace( $LDAPEqualSign, "=", $LDAPBaseDN );
194 $LDAPFilter = str_replace( $LDAPEqualSign, "=", $LDAPFilter );
195 $LDAPBindUser = str_replace( $LDAPEqualSign, "=", $LDAPBindUser );
196
197 if ( $LDAPDebugTrace )
198 {
199 $debugArray = array( 'stage' => '1/5: Connecting and Binding to LDAP server',
200 'LDAPServer' => $LDAPServer,
201 'LDAPPort' => $LDAPPort,
202 'LDAPBindUser' => $LDAPBindUser,
203 'LDAPVersion' => $LDAPVersion
204 );
205 // Set debug trace mode for ldap connections
206 if ( function_exists( 'ldap_set_option' ) )
207 ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
208 eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
209 }
210
211 if ( function_exists( 'ldap_connect' ) )
212 $ds = ldap_connect( $LDAPServer, $LDAPPort );
213 else
214 $ds = false;
215
216 if ( $ds )
217 {
218 ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, $LDAPVersion );
219 ldap_set_option( $ds, LDAP_OPT_REFERRALS, $LDAPFollowReferrals );
220 if ( $LDAPBindUser == '' )
221 {
222 $r = ldap_bind( $ds );
223 }
224 else
225 {
226 $r = ldap_bind( $ds, $LDAPBindUser, $LDAPBindPassword );
227 }
228 if ( !$r )
229 {
230 // Increase number of failed login attempts.
231 eZDebug::writeError( 'Cannot bind to LDAP server, might be something wronge with connetion or bind user!', __METHOD__ );
232 if ( isset( $userID ) )
233 eZUser::setFailedLoginAttempts( $userID );
234
235 $user = false;
236 return $user;
237 }
238
239 $LDAPFilter .= "($LDAPLoginAttribute=$loginLdapEscaped)";
240 $LDAPFilter .= ")";
241
242 ldap_set_option( $ds, LDAP_OPT_SIZELIMIT, 0 );
243 ldap_set_option( $ds, LDAP_OPT_TIMELIMIT, 0 );
244
245 $retrieveAttributes = array( $LDAPLoginAttribute,
246 $LDAPFirstNameAttribute,
247 $LDAPLastNameAttribute,
248 $LDAPEmailAttribute );
249 if ( $LDAPUserGroupAttributeType )
250 $retrieveAttributes[] = $LDAPUserGroupAttribute;
251
252 if ( $LDAPDebugTrace )
253 {
254 $debugArray = array( 'stage' => '2/5: finding user',
255 'LDAPFilter' => $LDAPFilter,
256 'retrieveAttributes' => $retrieveAttributes,
257 'LDAPSearchScope' => $LDAPSearchScope,
258 'LDAPBaseDN' => $LDAPBaseDN
259 );
260 eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
261 }
262
263 if ( $LDAPSearchScope == "one" )
264 $sr = ldap_list( $ds, $LDAPBaseDN, $LDAPFilter, $retrieveAttributes );
265 else if ( $LDAPSearchScope == "base" )
266 $sr = ldap_read( $ds, $LDAPBaseDN, $LDAPFilter, $retrieveAttributes );
267 else
268 $sr = ldap_search( $ds, $LDAPBaseDN, $LDAPFilter, $retrieveAttributes );
269
270 $info = ldap_get_entries( $ds, $sr ) ;
271 if ( $info['count'] > 1 )
272 {
273 // More than one user with same uid, not allow login.
274 eZDebug::writeWarning( 'More then one user with same uid, not allowed to login!', __METHOD__ );
275 $user = false;
276 return $user;
277 }
278 else if ( $info['count'] < 1 )
279 {
280 // Increase number of failed login attempts.
281 if ( isset( $userID ) )
282 eZUser::setFailedLoginAttempts( $userID );
283
284 // user DN was not found
285 eZDebug::writeWarning( 'User DN was not found!', __METHOD__ );
286 $user = false;
287 return $user;
288 }
289 else if ( $LDAPDebugTrace )
290 {
291 $debugArray = array( 'stage' => '3/5: real authentication of user',
292 'info' => $info
293 );
294 eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
295 }
296
297 if( !$password )
298 {
299 $password = crypt( microtime() );
300 }
301
302 // is it real authenticated LDAP user?
303 if ( !@ldap_bind( $ds, $info[0]['dn'], $password ) )
304 {
305 // Increase number of failed login attempts.
306 if ( isset( $userID ) )
307 eZUser::setFailedLoginAttempts( $userID );
308
309 eZDebug::writeWarning( "User $userID failed to login!", __METHOD__ );
310 $user = false;
311 return $user;
312 }
313
314 $extraNodeAssignments = array();
315 $userGroupClassID = $ini->variable( "UserSettings", "UserGroupClassID" );
316
317 // default user group assigning
318 if ( $LDAPUserGroupType != null )
319 {
320 if ( $LDAPUserGroupType == "name" )
321 {
322 if ( is_array( $LDAPUserGroup ) )
323 {
324 foreach ( array_keys( $LDAPUserGroup ) as $key )
325 {
326 $groupName = $db->escapeString( $LDAPUserGroup[$key] );
327 $groupQuery = "SELECT ezcontentobject_tree.node_id
328 FROM ezcontentobject, ezcontentobject_tree
329 WHERE ezcontentobject.name like '$groupName'
330 AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
331 AND ezcontentobject.contentclass_id=$userGroupClassID";
332 $groupObject = $db->arrayQuery( $groupQuery );
333 if ( count( $groupObject ) > 0 and $key == 0 )
334 {
335 $defaultUserPlacement = $groupObject[0]['node_id'];
336 }
337 else if ( count( $groupObject ) > 0 )
338 {
339 $extraNodeAssignments[] = $groupObject[0]['node_id'];
340 }
341 }
342 }
343 else
344 {
345 $groupName = $db->escapeString( $LDAPUserGroup );
346 $groupQuery = "SELECT ezcontentobject_tree.node_id
347 FROM ezcontentobject, ezcontentobject_tree
348 WHERE ezcontentobject.name like '$groupName'
349 AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
350 AND ezcontentobject.contentclass_id=$userGroupClassID";
351 $groupObject = $db->arrayQuery( $groupQuery );
352
353 if ( count( $groupObject ) > 0 )
354 {
355 $defaultUserPlacement = $groupObject[0]['node_id'];
356 }
357 }
358 }
359 else if ( $LDAPUserGroupType == "id" )
360 {
361 if ( is_array( $LDAPUserGroup ) )
362 {
363 foreach ( array_keys( $LDAPUserGroup ) as $key )
364 {
365 $groupID = $LDAPUserGroup[$key];
366 $groupQuery = "SELECT ezcontentobject_tree.node_id
367 FROM ezcontentobject, ezcontentobject_tree
368 WHERE ezcontentobject.id='$groupID'
369 AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
370 AND ezcontentobject.contentclass_id=$userGroupClassID";
371 $groupObject = $db->arrayQuery( $groupQuery );
372 if ( count( $groupObject ) > 0 and $key == 0 )
373 {
374 $defaultUserPlacement = $groupObject[0]['node_id'];
375 }
376 else if ( count( $groupObject ) > 0 )
377 {
378 $extraNodeAssignments[] = $groupObject[0]['node_id'];
379 }
380 }
381 }
382 else
383 {
384 $groupID = $LDAPUserGroup;
385 $groupQuery = "SELECT ezcontentobject_tree.node_id
386 FROM ezcontentobject, ezcontentobject_tree
387 WHERE ezcontentobject.id='$groupID'
388 AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
389 AND ezcontentobject.contentclass_id=$userGroupClassID";
390 $groupObject = $db->arrayQuery( $groupQuery );
391
392 if ( count( $groupObject ) > 0 )
393 {
394 $defaultUserPlacement = $groupObject[0]['node_id'];
395 }
396 }
397 }
398 }
399
400 // read group mapping LDAP settings
401 $LDAPGroupMappingType = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupMappingType' );
402 $LDAPUserGroupMap = $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupMap' );
403
404 if ( !is_array( $LDAPUserGroupMap ) )
405 $LDAPUserGroupMap = array();
406
407 // group mapping constants
408 $ByMemberAttribute = 'SimpleMapping'; // by group's member attributes (with mapping)
409 $ByMemberAttributeHierarhicaly = 'GetGroupsTree'; // by group's member attributes hierarhically
410 $ByGroupAttribute = 'UseGroupAttribute'; // by user's group attribute (old style)
411 $groupMappingTypes = array( $ByMemberAttribute,
412 $ByMemberAttributeHierarhicaly,
413 $ByGroupAttribute);
414
415 $userData =& $info[ 0 ];
416
417 // default mapping using old style
418 if ( !in_array( $LDAPGroupMappingType, $groupMappingTypes ) )
419 {
420 $LDAPGroupMappingType = $ByGroupAttribute;
421 }
422
423 if ( $LDAPDebugTrace )
424 {
425 $debugArray = array( 'stage' => '4/5: group mapping init',
426 'LDAPUserGroupType' => $LDAPUserGroupType,
427 'LDAPGroupMappingType' => $LDAPGroupMappingType,
428 'LDAPUserGroup' => $LDAPUserGroup,
429 'defaultUserPlacement' => $defaultUserPlacement,
430 'extraNodeAssignments' => $extraNodeAssignments
431 );
432 eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
433 }
434
435 if ( $LDAPGroupMappingType == $ByMemberAttribute or
436 $LDAPGroupMappingType == $ByMemberAttributeHierarhicaly )
437 {
438 $LDAPGroupBaseDN = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupBaseDN' );
439 $LDAPGroupBaseDN = str_replace( $LDAPEqualSign, '=', $LDAPGroupBaseDN );
440 $LDAPGroupClass = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupClass' );
441
442 $LDAPGroupNameAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupNameAttribute' ) );
443 $LDAPGroupMemberAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupMemberAttribute' ) );
444 $LDAPGroupDescriptionAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupDescriptionAttribute' ) );
445
446 $groupSearchingDepth = ( $LDAPGroupMappingType == '1' ) ? 1 : 1000;
447
448 // now, get all parents for currently ldap authenticated user
449 $requiredParams = array();
450 $requiredParams[ 'LDAPLoginAttribute' ] = $LDAPLoginAttribute;
451 $requiredParams[ 'LDAPGroupBaseDN' ] = $LDAPGroupBaseDN;
452 $requiredParams[ 'LDAPGroupClass' ] = $LDAPGroupClass;
453 $requiredParams[ 'LDAPGroupNameAttribute' ] = $LDAPGroupNameAttribute;
454 $requiredParams[ 'LDAPGroupMemberAttribute' ] = $LDAPGroupMemberAttribute;
455 $requiredParams[ 'LDAPGroupDescriptionAttribute' ] = $LDAPGroupDescriptionAttribute;
456 $requiredParams[ 'ds' ] =& $ds;
457 if ( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupRootNodeId' ) !== '' )
458 $requiredParams[ 'TopUserGroupNodeID' ] = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupRootNodeId' );
459 else
460 $requiredParams[ 'TopUserGroupNodeID' ] = 5;
461
462 $groupsTree = array();
463 $stack = array();
464 $newfilter = '(&(objectClass=' . $LDAPGroupClass . ')(' . $LDAPGroupMemberAttribute . '=' . $userData['dn'] . '))';
465
466 $groupsTree[ $userData['dn'] ] = array( 'data' => & $userData,
467 'parents' => array(),
468 'children' => array() );
469
470 eZLDAPUser::getUserGroupsTree( $requiredParams, $newfilter, $userData['dn'], $groupsTree, $stack, $groupSearchingDepth );
471 $userRecord =& $groupsTree[ $userData['dn'] ];
472
473 if ( $LDAPGroupMappingType == $ByMemberAttribute )
474 {
475 if ( count( $userRecord[ 'parents' ] ) > 0 )
476 {
477 $remappedGroupNames = array();
478 foreach ( array_keys( $userRecord[ 'parents' ] ) as $key )
479 {
480 $parentGroup =& $userRecord[ 'parents' ][ $key ];
481 if ( isset( $parentGroup[ 'data' ][ $LDAPGroupNameAttribute ] ) )
482 {
483 $ldapGroupName = $parentGroup[ 'data' ][ $LDAPGroupNameAttribute ];
484 if ( is_array( $ldapGroupName ) )
485 {
486 $ldapGroupName = ( $ldapGroupName[ 'count' ] > 0 ) ? $ldapGroupName[ 0 ] : '';
487 }
488
489 // remap group name and check that group exists
490 if ( array_key_exists( $ldapGroupName, $LDAPUserGroupMap ) )
491 {
492 $remmapedGroupName = $db->escapeString( $LDAPUserGroupMap[ $ldapGroupName ] );
493 $groupQuery = "SELECT ezcontentobject_tree.node_id
494 FROM ezcontentobject, ezcontentobject_tree
495 WHERE ezcontentobject.name like '$remmapedGroupName'
496 AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
497 AND ezcontentobject.contentclass_id=$userGroupClassID";
498 $groupRow = $db->arrayQuery( $groupQuery );
499
500 if ( count( $groupRow ) > 0 )
501 {
502 $userRecord['new_parents'][] = $groupRow[ 0 ][ 'node_id' ];
503 }
504 }
505 }
506 }
507 }
508 }
509 else if ( $LDAPGroupMappingType == $ByMemberAttributeHierarhicaly )
510 {
511 $stack = array();
512 self::goAndPublishGroups( $requiredParams, $userData['dn'], $groupsTree, $stack, $groupSearchingDepth, true );
513 }
514 if ( isset( $userRecord['new_parents'] ) and
515 count( $userRecord['new_parents'] ) > 0 )
516 {
517 $defaultUserPlacement = $userRecord['new_parents'][0];
518 $extraNodeAssignments = array_merge( $extraNodeAssignments, $userRecord['new_parents'] );
519 }
520 }
521 else if ( $LDAPGroupMappingType == $ByGroupAttribute ) // old style mapping by group (employeetype) attribute
522 {
523 if ( $LDAPUserGroupAttributeType )
524 {
525 // Should we create user groups that are specified in LDAP, but not found in eZ Publish?
526 $createMissingGroups = ( $LDAPIni->variable( 'LDAPSettings', 'LDAPCreateMissingGroups' ) === 'enabled' );
527 if ( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupRootNodeId' ) !== '' )
528 $parentNodeID = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupRootNodeId' );
529 else
530 $parentNodeID = 5;
531
532 $groupAttributeCount = $info[0][$LDAPUserGroupAttribute]['count'];
533 if ( $LDAPUserGroupAttributeType == "name" )
534 {
535 for ( $i = 0; $i < $groupAttributeCount; $i++ )
536 {
537 if ( $isUtf8Encoding )
538 {
539 $groupName = mb_convert_encoding( $info[0][$LDAPUserGroupAttribute][$i], 'ISO-8859-1', 'UTF-8' );
540 }
541 else
542 {
543 $groupName = $info[0][$LDAPUserGroupAttribute][$i];
544 }
545
546 // Save group node id to either defaultUserPlacement or extraNodeAssignments
547 self::getNodeAssignmentsForGroupName( $groupName, ($i == 0), $defaultUserPlacement, $extraNodeAssignments,
548 $createMissingGroups, $parentNodeID );
549 }
550 }
551 else if ( $LDAPUserGroupAttributeType == "id" )
552 {
553 for ( $i = 0; $i < $groupAttributeCount; $i++ )
554 {
555 if ( $isUtf8Encoding )
556 {
557 $groupID = mb_convert_encoding( $info[0][$LDAPUserGroupAttribute][$i], 'ISO-8859-1', 'UTF-8' );
558 }
559 else
560 {
561 $groupID = $info[0][$LDAPUserGroupAttribute][$i];
562 }
563 $groupName = "LDAP $groupID";
564
565 // Save group node id to either defaultUserPlacement or extraNodeAssignments
566 self::getNodeAssignmentsForGroupName( $groupName, ($i == 0), $defaultUserPlacement, $extraNodeAssignments,
567 $createMissingGroups, $parentNodeID );
568 }
569 }
570 else if ( $LDAPUserGroupAttributeType == "dn" )
571 {
572 for ( $i = 0; $i < $groupAttributeCount; $i++ )
573 {
574 $groupDN = $info[0][$LDAPUserGroupAttribute][$i];
575 $groupName = self::getGroupNameByDN( $ds, $groupDN );
576
577 if ( $groupName )
578 {
579 // Save group node id to either defaultUserPlacement or extraNodeAssignments
580 self::getNodeAssignmentsForGroupName( $groupName, ($i == 0), $defaultUserPlacement, $extraNodeAssignments,
581 $createMissingGroups, $parentNodeID );
582 }
583 }
584 }
585 else
586 {
587 eZDebug::writeError( "Bad LDAPUserGroupAttributeType '$LDAPUserGroupAttributeType'. It must be either 'name', 'id' or 'dn'.", __METHOD__ );
588 $user = false;
589 return $user;
590 }
591 }
592 }
593
594 // remove ' last_name' from first_name if cn is used for first name
595 if ( $LDAPFirstNameIsCN && isset( $userData[ $LDAPFirstNameAttribute ] ) && isset( $userData[ $LDAPLastNameAttribute ] ) )
596 {
597 $userData[ $LDAPFirstNameAttribute ][0] = str_replace( ' ' . $userData[ $LDAPLastNameAttribute ][0], '', $userData[ $LDAPFirstNameAttribute ][0] );
598 }
599
600 if ( isset( $userData[ $LDAPEmailAttribute ] ) )
601 $LDAPuserEmail = $userData[ $LDAPEmailAttribute ][0];
602 else if( trim( $LDAPIni->variable( 'LDAPSettings', 'LDAPEmailEmptyAttributeSuffix' ) ) )
603 $LDAPuserEmail = $login . $LDAPIni->variable( 'LDAPSettings', 'LDAPEmailEmptyAttributeSuffix' );
604 else
605 $LDAPuserEmail = false;
606
607
608 $userAttributes = array( 'login' => $login,
609 'first_name' => isset( $userData[ $LDAPFirstNameAttribute ] ) ? $userData[ $LDAPFirstNameAttribute ][0] : false,
610 'last_name' => isset( $userData[ $LDAPLastNameAttribute ] ) ? $userData[ $LDAPLastNameAttribute ][0] : false,
611 'email' => $LDAPuserEmail );
612
613 if ( $LDAPDebugTrace )
614 {
615 $debugArray = array( 'stage' => '5/5: storing user',
616 'userAttributes' => $userAttributes,
617 'isUtf8Encoding' => $isUtf8Encoding,
618 'defaultUserPlacement' => $defaultUserPlacement,
619 'extraNodeAssignments' => $extraNodeAssignments
620 );
621 eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
622 }
623
624 $oldUser = clone eZUser::currentUser();
625 $existingUser = eZLDAPUser::publishUpdateUser( $extraNodeAssignments, $defaultUserPlacement, $userAttributes, $isUtf8Encoding );
626
627 if ( is_object( $existingUser ) )
628 {
629 eZUser::setCurrentlyLoggedInUser( $existingUser, $existingUser->attribute( 'contentobject_id' ) );
630 }
631 else
632 {
633 eZUser::setCurrentlyLoggedInUser( $oldUser, $oldUser->attribute( 'contentobject_id' ) );
634 }
635
636 ldap_close( $ds );
637 return $existingUser;
638 }
639 else
640 {
641 eZDebug::writeError( 'Cannot initialize connection for LDAP server', __METHOD__ );
642 $user = false;
643 return $user;
644 }
645 }
646 else
647 {
648 // Increase number of failed login attempts.
649 if ( isset( $userID ) )
650 eZUser::setFailedLoginAttempts( $userID );
651
652 eZDebug::writeWarning( 'User does not exist or LDAP is not enabled in php', __METHOD__ );
653 $user = false;
654 return $user;
655 }
656 }
657
658 /*
659 Static method, for internal usage only.
660 Publishes new or update existing user
661 */
662 static function publishUpdateUser( $parentNodeIDs, $defaultUserPlacement, $userAttributes, $isUtf8Encoding = false )
663 {
664 if ( !is_array( $userAttributes ) or
665 !isset( $userAttributes[ 'login' ] ) or empty( $userAttributes[ 'login' ] ) )
666 {
667 eZDebug::writeWarning( 'Empty user login passed.', __METHOD__ );
668 return false;
669 }
670
671 if ( ( !is_array( $parentNodeIDs ) or count( $parentNodeIDs ) < 1 ) and
672 !is_numeric( $defaultUserPlacement ) )
673 {
674 eZDebug::writeWarning( 'No one parent node IDs was passed for publishing new user (login = "' .
675 $userAttributes[ 'login' ] . '")',
676 __METHOD__ );
677 return false;
678 }
679 $parentNodeIDs[] = $defaultUserPlacement;
680 $parentNodeIDs = array_unique( $parentNodeIDs );
681
682
683 $login = $userAttributes[ 'login' ];
684 $first_name = $userAttributes[ 'first_name' ];
685 $last_name = $userAttributes[ 'last_name' ];
686 $email = $userAttributes[ 'email' ];
687
688 if ( $isUtf8Encoding )
689 {
690 $first_name = mb_convert_encoding( $first_name, 'ISO-8859-1', 'UTF-8' );
691 $last_name = mb_convert_encoding( $last_name, 'ISO-8859-1', 'UTF-8' );
692 }
693
694 $user = eZUser::fetchByName( $login );
695 $createNewUser = ( is_object( $user ) ) ? false : true;
696
697 if ( $createNewUser )
698 {
699 if ( !isset( $first_name ) or empty( $first_name ) or
700 !isset( $last_name ) or empty( $last_name ) or
701 !isset( $email ) or empty( $email ) )
702 {
703 eZDebug::writeWarning( 'Cannot create user with empty first name (last name or email).', __METHOD__ );
704 return false;
705 }
706
707 $ini = eZINI::instance();
708 $userClassID = $ini->variable( "UserSettings", "UserClassID" );
709 $userCreatorID = $ini->variable( "UserSettings", "UserCreatorID" );
710 $defaultSectionID = $ini->variable( "UserSettings", "DefaultSectionID" );
711
712 $class = eZContentClass::fetch( $userClassID );
713 $contentObject = $class->instantiate( $userCreatorID, $defaultSectionID );
714
715 $contentObject->store();
716
717 $userID = $contentObjectID = $contentObject->attribute( 'id' );
718
719 $version = $contentObject->version( 1 );
720 $version->setAttribute( 'modified', time() );
721 $version->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
722 $version->store();
723
724 $user = eZLDAPUser::create( $userID );
725 $user->setAttribute( 'login', $login );
726 }
727 else
728 {
729 $userID = $contentObjectID = $user->attribute( 'contentobject_id' );
730 $contentObject = eZContentObject::fetch( $userID );
731 $version = $contentObject->attribute( 'current' );
732 }
733
734 //================= common part 1: start ========================
735 $contentObjectAttributes = $version->contentObjectAttributes();
736
737 // find and set 'name' and 'description' attributes (as standard user group class)
738 $firstNameIdentifier = 'first_name';
739 $lastNameIdentifier = 'last_name';
740 $firstNameAttribute = null;
741 $lastNameAttribute = null;
742
743 foreach ( $contentObjectAttributes as $attribute )
744 {
745 if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $firstNameIdentifier )
746 {
747 $firstNameAttribute = $attribute;
748 }
749 else if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $lastNameIdentifier )
750 {
751 $lastNameAttribute = $attribute;
752 }
753 }
754 //================= common part 1: end ==========================
755
756 // If we are updating an existing user, we must find out if some data should be changed.
757 // In that case, we must create a new version and publish it.
758 if ( !$createNewUser )
759 {
760 $userDataChanged = false;
761 $firstNameChanged = false;
762 $lastNameChanged = false;
763 $emailChanged = false;
764
765 if ( $firstNameAttribute and $firstNameAttribute->attribute( 'data_text' ) != $first_name )
766 {
767 $firstNameChanged = true;
768 }
769 $firstNameAttribute = false; // We will load this again from the new version we will create, if it has changed
770 if ( $lastNameAttribute and $lastNameAttribute->attribute( 'data_text' ) != $last_name )
771 {
772 $lastNameChanged = true;
773 }
774 $lastNameAttribute = false; // We will load this again from the new version we will create, if it has changed
775 if ( $user->attribute( 'email' ) != $email )
776 {
777 $emailChanged = true;
778 }
779
780 if ( $firstNameChanged or $lastNameChanged or $emailChanged )
781 {
782 $userDataChanged = true;
783 // Create new version
784 $version = $contentObject->createNewVersion();
785 $contentObjectAttributes = $version->contentObjectAttributes();
786 foreach ( $contentObjectAttributes as $attribute )
787 {
788 if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $firstNameIdentifier )
789 {
790 $firstNameAttribute = $attribute;
791 }
792 else if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $lastNameIdentifier )
793 {
794 $lastNameAttribute = $attribute;
795 }
796 }
797 }
798 }
799
800 //================= common part 2: start ========================
801 if ( $firstNameAttribute )
802 {
803 $firstNameAttribute->setAttribute( 'data_text', $first_name );
804 $firstNameAttribute->store();
805 }
806 if ( $lastNameAttribute )
807 {
808 $lastNameAttribute->setAttribute( 'data_text', $last_name );
809 $lastNameAttribute->store();
810 }
811
812 if ( !isset( $userDataChanged ) or $userDataChanged === true )
813 {
814 $contentClass = $contentObject->attribute( 'content_class' );
815 $name = $contentClass->contentObjectName( $contentObject );
816 $contentObject->setName( $name );
817 }
818
819 if ( !isset( $emailChanged ) or $emailChanged === true )
820 {
821 $user->setAttribute( 'email', $email );
822 }
823
824 $user->setAttribute( 'password_hash', "" );
825 $user->setAttribute( 'password_hash_type', self::PASSWORD_HASH_EMPTY );
826 $user->store();
827
828 $debugArray = array( 'Updating user data',
829 'createNewUser' => $createNewUser,
830 'userDataChanged' => isset( $userDataChanged ) ? $userDataChanged : null,
831 'login' => $login,
832 'first_name' => $first_name,
833 'last_name' => $last_name,
834 'email' => $email,
835 'firstNameAttribute is_object' => is_object( $firstNameAttribute ),
836 'lastNameAttribute is_object' => is_object( $lastNameAttribute ),
837 'content object id' => $contentObjectID,
838 'version id' => $version->attribute( 'version' )
839 );
840 eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
841 //================= common part 2: end ==========================
842
843 if ( $createNewUser )
844 {
845 reset( $parentNodeIDs );
846 // prepare node assignments for publishing new user
847 foreach( $parentNodeIDs as $parentNodeID )
848 {
849 $newNodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $contentObjectID,
850 'contentobject_version' => 1,
851 'parent_node' => $parentNodeID,
852 // parent_remote_id in node assignment holds remote id of the tree node,
853 // not of the parent location or of the node assignment itself
854 'parent_remote_id' => uniqid( 'LDAP_' ),
855 'is_main' => ( $defaultUserPlacement == $parentNodeID ? 1 : 0 ) ) );
856 $newNodeAssignment->store();
857 }
858
859 $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
860 'version' => 1 ) );
861 }
862 else
863 {
864 if ( $userDataChanged )
865 {
866 // Publish object
867 $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
868 'version' => $version->attribute( 'version' ) ) );
869 // Refetch object
870 $contentObject = eZContentObject::fetch( $contentObjectID );
871 $version = $contentObject->attribute( 'current' );
872 }
873
874 $LDAPIni = eZINI::instance( 'ldap.ini' );
875 $keepGroupAssignment = ( $LDAPIni->hasVariable( 'LDAPSettings', 'KeepGroupAssignment' ) ) ?
876 ( $LDAPIni->variable( 'LDAPSettings', 'KeepGroupAssignment' ) == "enabled" ) : false;
877
878 if ( $keepGroupAssignment == false )
879 {
880 $objectIsChanged = false;
881
882 $db = eZDB::instance();
883 $db->begin();
884
885 // First check existing assignments, remove any that should not exist
886 $assignedNodesList = $contentObject->assignedNodes();
887 $existingParentNodeIDs = array();
888 foreach ( $assignedNodesList as $node )
889 {
890 $parentNodeID = $node->attribute( 'parent_node_id' );
891 if ( !in_array( $parentNodeID, $parentNodeIDs ) )
892 {
893 $node->removeThis();
894 $objectIsChanged = true;
895 }
896 else
897 {
898 $existingParentNodeIDs[] = $parentNodeID;
899 }
900 }
901
902 // Then check assignments that should exist, add them if they are missing
903 foreach( $parentNodeIDs as $parentNodeID )
904 {
905 if ( !in_array( $parentNodeID, $existingParentNodeIDs ) )
906 {
907 $newNode = $contentObject->addLocation( $parentNodeID, true );
908 $newNode->updateSubTreePath();
909 $newNode->setAttribute( 'contentobject_is_published', 1 );
910 $newNode->sync();
911 $existingParentNodeIDs[] = $parentNodeID;
912 $objectIsChanged = true;
913 }
914 }
915
916 // Then ensure that the main node is correct
917 $currentMainParentNodeID = $contentObject->attribute( 'main_parent_node_id' );
918 if ( $currentMainParentNodeID != $defaultUserPlacement )
919 {
920 $existingNode = eZContentObjectTreeNode::fetchNode( $contentObjectID, $defaultUserPlacement );
921 if ( !is_object( $existingNode ) )
922 {
923 eZDebug::writeError( "Cannot find assigned node as $defaultUserPlacement's child.", __METHOD__ );
924 }
925 else
926 {
927 $existingNodeID = $existingNode->attribute( 'node_id' );
928 $versionNum = $version->attribute( 'version' );
929 eZContentObjectTreeNode::updateMainNodeID( $existingNodeID, $contentObjectID, $versionNum, $defaultUserPlacement );
930 $objectIsChanged = true;
931 }
932 }
933
934 $db->commit();
935
936 // Finally, clear object view cache if something was changed
937 if ( $objectIsChanged )
938 {
939 eZContentCacheManager::clearObjectViewCache( $contentObjectID, true );
940 }
941 }
942 }
943
944 eZUser::updateLastVisit( $userID );
945 //eZUser::setCurrentlyLoggedInUser( $user, $userID );
946 // Reset number of failed login attempts
947 eZUser::setFailedLoginAttempts( $userID, 0 );
948 return $user;
949 }
950
951 /*
952 Static method, for internal usage only.
953 Note: used user group class (see 'UserGroupClassID' ini setting, in 'UserSettings' section)
954 must have name attribute with indentifier equal 'name'
955 */
956 static function publishNewUserGroup( $parentNodeIDs, $newGroupAttributes, $isUtf8Encoding = false )
957 {
958 $newNodeIDs = array();
959
960 if ( !is_array( $newGroupAttributes ) or
961 !isset( $newGroupAttributes[ 'name' ] ) or
962 empty( $newGroupAttributes[ 'name' ] ) )
963 {
964 eZDebug::writeWarning( 'Cannot create user group with empty name.', __METHOD__ );
965 return $newNodeIDs;
966 }
967 if ( !is_array( $parentNodeIDs ) or count( $parentNodeIDs ) < 1 )
968 {
969 eZDebug::writeWarning( 'No one parent node IDs was passed for publishing new group (group name = "' .
970 $newGroupAttributes[ 'name' ] . '")',
971 __METHOD__ );
972 return $newNodeIDs;
973 }
974
975 $ini = eZINI::instance();
976 $userGroupClassID = $ini->variable( "UserSettings", "UserGroupClassID" );
977 $userCreatorID = $ini->variable( "UserSettings", "UserCreatorID" );
978 $defaultSectionID = $ini->variable( "UserSettings", "DefaultSectionID" );
979
980 $userGroupClass = eZContentClass::fetch( $userGroupClassID );
981 $contentObject = $userGroupClass->instantiate( $userCreatorID, $defaultSectionID );
982
983 $contentObject->store();
984
985 $contentObjectID = $contentObject->attribute( 'id' );
986
987 reset( $parentNodeIDs );
988 $defaultPlacement = current( $parentNodeIDs );
989 array_shift( $parentNodeIDs );
990
991 $nodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $contentObjectID,
992 'contentobject_version' => 1,
993 'parent_node' => $defaultPlacement,
994 // parent_remote_id in node assignment holds remote id of the tree node,
995 // not of the parent location or of the node assignment itself
996 'parent_remote_id' => uniqid( 'LDAP_' ),
997 'is_main' => 1 ) );
998 $nodeAssignment->store();
999
1000 foreach( $parentNodeIDs as $parentNodeID )
1001 {
1002 $newNodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $contentObjectID,
1003 'contentobject_version' => 1,
1004 'parent_node' => $parentNodeID,
1005 // parent_remote_id in node assignment holds remote id of the tree node,
1006 // not of the parent location or of the node assignment itself
1007 'parent_remote_id' => uniqid( 'LDAP_' ),
1008 'is_main' => 0 ) );
1009 $newNodeAssignment->store();
1010 }
1011
1012 $version = $contentObject->version( 1 );
1013 $version->setAttribute( 'modified', time() );
1014 $version->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
1015 $version->store();
1016
1017 $contentObjectAttributes = $version->contentObjectAttributes();
1018
1019 // find ant set 'name' and 'description' attributes (as standard user group class)
1020 $nameIdentifier = 'name';
1021 $descIdentifier = 'description';
1022 $nameContentAttribute = null;
1023 $descContentAttribute = null;
1024 foreach( $contentObjectAttributes as $attribute )
1025 {
1026 if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $nameIdentifier )
1027 {
1028 $nameContentAttribute = $attribute;
1029 }
1030 else if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $descIdentifier )
1031 {
1032 $descContentAttribute = $attribute;
1033 }
1034 }
1035 if ( $nameContentAttribute )
1036 {
1037 if ( $isUtf8Encoding )
1038 $newGroupAttributes[ 'name' ] = utf8_decode( $newGroupAttributes[ 'name' ] );
1039 $nameContentAttribute->setAttribute( 'data_text', $newGroupAttributes[ 'name' ] );
1040 $nameContentAttribute->store();
1041 }
1042 if ( $descContentAttribute and
1043 isset( $newGroupAttributes[ 'description' ] ) )
1044 {
1045 if ( $isUtf8Encoding )
1046 $newGroupAttributes[ 'description' ] = utf8_decode( $newGroupAttributes[ 'description' ] );
1047 $descContentAttribute->setAttribute( 'data_text', $newGroupAttributes[ 'description' ] );
1048 $descContentAttribute->store();
1049 }
1050
1051 $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
1052 'version' => 1 ) );
1053 $newNodes = eZContentObjectTreeNode::fetchByContentObjectID( $contentObjectID, true, 1 );
1054 foreach ( $newNodes as $newNode )
1055 {
1056 $newNodeIDs[] = $newNode->attribute( 'node_id' );
1057 }
1058
1059 return $newNodeIDs;
1060 }
1061
1062 /*
1063 Static method, for internal usage only.
1064 Recursive, publishes groups by prepared tree of groups returned by getUserGroupsTree() method
1065 */
1066 static function goAndPublishGroups( &$requiredParams,
1067 $curDN,
1068 &$groupsTree,
1069 &$stack,
1070 $depth,
1071 $isUser = false )
1072 {
1073 if ( !isset( $groupsTree[ $curDN ] ) )
1074 {
1075 eZDebug::writeError( 'Passed $curDN is not in result tree array.', __METHOD__ );
1076 return false;
1077 }
1078
1079 array_push( $stack, $curDN );
1080 $current =& $groupsTree[ $curDN ];
1081
1082 // check the name
1083 if ( $isUser )
1084 {
1085 $currentName = $current[ 'data' ][ $requiredParams[ 'LDAPLoginAttribute' ] ];
1086 }
1087 else
1088 {
1089 $currentName = $current[ 'data' ][ $requiredParams[ 'LDAPGroupNameAttribute' ] ];
1090 }
1091
1092 if ( is_array( $currentName ) and //count( $currentName ) > 1 and
1093 isset( $currentName[ 'count' ] ) and $currentName[ 'count' ] > 0 )
1094 {
1095 $currentName = $currentName[ 0 ];
1096 }
1097
1098 if ( empty( $currentName ) )
1099 {
1100 eZDebug::writeWarning( "Cannot create/use group with empty name (dn = $curDN)", __METHOD__ );
1101 return false;
1102 }
1103
1104 // go through parents
1105 if ( is_array( $current['parents'] ) and count( $current['parents'] ) > 0 )
1106 {
1107 foreach( array_keys( $current['parents'] ) as $key )
1108 {
1109 $parent =& $groupsTree[ $key ];
1110
1111 if ( in_array( $parent['data']['dn'], $stack ) )
1112 {
1113 $groupsTree[ '_recursion_detected_' ] = true;
1114 eZDebug::writeError( 'Recursion is detected in the user-groups tree while getting parent groups for ' . $curDN, __METHOD__ );
1115 return false;
1116 }
1117 if ( isset( $parent[ 'nodes' ] ) and count( $parent[ 'nodes' ] ) > 0 )
1118 {
1119 continue;
1120 }
1121 $ret = self::goAndPublishGroups( $requiredParams,
1122 $parent['data']['dn'],
1123 $groupsTree,
1124 $stack,
1125 $depth - 1 );
1126 if ( isset( $groupsTree[ '_recursion_detected_' ] ) and $groupsTree[ '_recursion_detected_' ] )
1127 {
1128 return false;
1129 }
1130 }
1131 }
1132 else
1133 {
1134 // We've reached a top node
1135 if ( !isset( $groupsTree[ 'root' ] ) )
1136 {
1137 $groupsTree[ 'root' ] = array( 'data' => null,
1138 'parents' => null,
1139 'children' => array(),
1140 'nodes' => array( $requiredParams[ 'TopUserGroupNodeID' ] ) );
1141 }
1142 if ( !isset( $groupsTree[ 'root' ][ 'children' ][ $curDN ] ) )
1143 $groupsTree[ 'root' ][ 'children' ][ $curDN ] =& $current;
1144 if ( !isset( $current[ 'parents' ][ 'root' ] ) )
1145 $current[ 'parents' ][ 'root' ] =& $groupsTree[ 'root' ];
1146 }
1147
1148 if ( !isset( $current[ 'nodes' ] ) )
1149 $current[ 'nodes' ] = array();
1150
1151 $parentNodesForNew = array();
1152 foreach( array_keys( $current[ 'parents' ] ) as $key )
1153 {
1154 $parent =& $groupsTree[ $key ];
1155 if ( is_array( $parent[ 'nodes' ] ) and count( $parent[ 'nodes' ] ) > 0 )
1156 {
1157 foreach ( $parent[ 'nodes' ] as $parentNodeID )
1158 {
1159 // fetch current parent node
1160 $parentNode = eZContentObjectTreeNode::fetch( $parentNodeID );
1161 if ( is_object( $parentNode ) )
1162 {
1163 $params = array( 'AttributeFilter' => array( array( 'name', '=', $currentName ) ),
1164 'Limitation' => array() );
1165 $nodes = eZContentObjectTreeNode::subTreeByNodeID( $params, $parentNodeID );
1166
1167 if ( is_array( $nodes ) and count( $nodes ) > 0 and !$isUser )
1168 {
1169 // if group with given name already exist under $parentNode then get fetch
1170 // group node and remember its ID
1171 $node =& $nodes[ 0 ];
1172 $nodeID = $node->attribute( 'node_id' );
1173 $current[ 'nodes' ][] = $nodeID;
1174 }
1175 else
1176 {
1177 // if not exist then remember $parentNodeID to publish a new one
1178 $parentNodesForNew[] = $parentNodeID;
1179 }
1180 }
1181 else
1182 {
1183 eZDebug::writeError( 'Cannot fetch parent node for creating new user group ' . $parentNodeID, __METHOD__ );
1184 }
1185 }
1186 }
1187 else
1188 {
1189 eZDebug::writeError( "Cannot get any published parent group for group/user with name = '$currentName'" .
1190 " (dn = '" . $current[ 'data' ]['dn'] . "')",
1191 __METHOD__ );
1192 }
1193 }
1194
1195 if ( count( $parentNodesForNew ) > 0 )
1196 {
1197 if ( $isUser )
1198 {
1199 $current[ 'new_parents' ] = $parentNodesForNew;
1200 $newNodeIDs = array();
1201 }
1202 else
1203 {
1204 $newNodeIDs = eZLDAPUser::publishNewUserGroup( $parentNodesForNew, array( 'name' => $currentName,
1205 'description' => '' ) );
1206 }
1207 $current[ 'nodes' ] = array_merge( $current[ 'nodes' ], $newNodeIDs );
1208 }
1209
1210 array_pop( $stack );
1211 return true;
1212 }
1213
1214 /*
1215 Static method, for internal usage only
1216 Recursive method, which parses tree of groups from ldap server
1217 */
1218 static function getUserGroupsTree( &$requiredParams,
1219 $filter,
1220 $curDN,
1221 &$groupsTree,
1222 &$stack, // stack for recursion checking
1223 $depth = 0 )
1224 {
1225 if ( $depth == 0 )
1226 {
1227 return false;
1228 }
1229
1230 if ( !isset( $requiredParams[ 'LDAPGroupBaseDN' ] ) or empty( $requiredParams[ 'LDAPGroupBaseDN' ] ) or
1231 !isset( $requiredParams[ 'LDAPGroupClass' ] ) or empty( $requiredParams[ 'LDAPGroupClass' ] ) or
1232 !isset( $requiredParams[ 'LDAPGroupNameAttribute' ] ) or empty( $requiredParams[ 'LDAPGroupNameAttribute' ] ) or
1233 !isset( $requiredParams[ 'LDAPGroupMemberAttribute' ] ) or empty( $requiredParams[ 'LDAPGroupMemberAttribute' ] ) or
1234 !isset( $requiredParams[ 'ds' ] ) or !$requiredParams[ 'ds' ] )
1235 {
1236 eZDebug::writeError( 'Missing one of required parameters.', __METHOD__ );
1237 return false;
1238 }
1239 if ( !isset( $groupsTree[ $curDN ] ) )
1240 {
1241 eZDebug::writeError( 'Passed $curDN is not in result tree array. Algorithm\'s usage error.', __METHOD__ );
1242 return false;
1243 }
1244 array_push( $stack, $curDN );
1245
1246 $LDAPGroupBaseDN =& $requiredParams[ 'LDAPGroupBaseDN' ];
1247 $LDAPGroupClass =& $requiredParams[ 'LDAPGroupClass' ];
1248 $LDAPGroupNameAttribute =& $requiredParams[ 'LDAPGroupNameAttribute' ];
1249 $LDAPGroupMemberAttribute =& $requiredParams[ 'LDAPGroupMemberAttribute' ];
1250 $LDAPGroupDescriptionAttribute =& $requiredParams[ 'LDAPGroupDescriptionAttribute' ];
1251 $ds =& $requiredParams[ 'ds' ];
1252
1253 $current =& $groupsTree[ $curDN ];
1254
1255 $retrieveAttributes = array( $LDAPGroupNameAttribute,
1256 $LDAPGroupMemberAttribute );
1257 $sr = ldap_search( $ds, $LDAPGroupBaseDN, $filter, $retrieveAttributes );
1258 $entries = ldap_get_entries( $ds, $sr );
1259
1260 if ( is_array( $entries ) and
1261 isset( $entries[ 'count' ] ) and $entries[ 'count' ] > 0 )
1262 {
1263 $newfilter = '(&(objectClass=' . $LDAPGroupClass . ')';
1264
1265 for ( $i = 0; $i < $entries[ 'count' ]; $i++ )
1266 {
1267 $parent =& $entries[ $i ];
1268 if ( $parent === null )
1269 continue;
1270
1271 $parentDN =& $parent['dn'];
1272 if ( in_array( $parentDN, $stack ) )
1273 {
1274 $requiredParams[ 'LDAPGroupNameAttribute' ];
1275
1276 eZDebug::writeError( 'Recursion is detected in the user-groups tree while getting parent groups for ' . $curDN, __METHOD__ );
1277 $groupsTree[ '_recursion_detected_' ] = true;
1278 return false;
1279 }
1280
1281 if ( !isset( $groupsTree[ $parentDN ] ) )
1282 {
1283 $groupsTree[ $parentDN ] = array( 'data' => $parent,
1284 'parents' => array(),
1285 'children' => array() );
1286 }
1287 $groupsTree[ $parentDN ][ 'children' ][ $curDN ] =& $current;
1288 $current[ 'parents' ][ $parentDN ] =& $groupsTree[ $parentDN ];
1289 $newfilter1 = $newfilter . '(' . $LDAPGroupMemberAttribute . '=' . $parentDN . '))';
1290 $ret = eZLDAPUser::getUserGroupsTree( $requiredParams,
1291 $newfilter1,
1292 $parentDN,
1293 $groupsTree,
1294 $stack,
1295 $depth - 1 );
1296 if ( isset( $groupsTree[ '_recursion_detected_' ] ) and
1297 $groupsTree[ '_recursion_detected_' ] )
1298 {
1299 return false;
1300 }
1301 }
1302 }
1303 else
1304 {
1305 // We've reached a top node
1306 if ( !isset( $groupsTree[ 'root' ] ) )
1307 {
1308 $groupsTree[ 'root' ] = array( 'data' => null,
1309 'parents' => null,
1310 'children' => array(),
1311 'nodes' => array( $requiredParams[ 'TopUserGroupNodeID' ] ) );
1312 }
1313 if ( !isset( $groupsTree[ 'root' ][ 'children' ][ $curDN ] ) )
1314 $groupsTree[ 'root' ][ 'children' ][ $curDN ] =& $current;
1315 if ( !isset( $current[ 'parents' ][ 'root' ] ) )
1316 $current[ 'parents' ][ 'root' ] =& $groupsTree[ 'root' ];
1317 }
1318
1319 array_pop( $stack );
1320 return true;
1321 }
1322
1323 /*
1324 Static method, for internal usage only
1325 Finds a user group with the given name and remembers the node ID for it. The first match is always used.
1326 If $createMissingGroups is true, it will create any groups it does not find.
1327 */
1328 static function getNodeAssignmentsForGroupName( $groupName,
1329 $isFirstGroupAssignment,
1330 &$defaultUserPlacement,
1331 &$extraNodeAssignments,
1332 $createMissingGroups,
1333 $parentNodeID )
1334 {
1335 if ( !is_string( $groupName ) or $groupName === '' )
1336 {
1337 eZDebug::writeError( 'The groupName must be a non empty string. Bad groupName: ' . $groupName, __METHOD__ );
1338 return;
1339 }
1340
1341 $db = eZDB::instance();
1342 $ini = eZINI::instance();
1343 $userGroupClassID = $ini->variable( "UserSettings", "UserGroupClassID" );
1344
1345 $groupNameEscaped = $db->escapeString( $groupName );
1346 $groupQuery = "SELECT ezcontentobject_tree.node_id
1347 FROM ezcontentobject, ezcontentobject_tree
1348 WHERE ezcontentobject.name like '$groupNameEscaped'
1349 AND ezcontentobject.id = ezcontentobject_tree.contentobject_id
1350 AND ezcontentobject.contentclass_id = $userGroupClassID";
1351 $groupRows = $db->arrayQuery( $groupQuery );
1352
1353 if ( count( $groupRows ) > 0 and $isFirstGroupAssignment )
1354 {
1355 $defaultUserPlacement = $groupRows[0]['node_id'];
1356 return;
1357 }
1358 else if ( count( $groupRows ) > 0 )
1359 {
1360 $extraNodeAssignments[] = $groupRows[0]['node_id'];
1361 return;
1362 }
1363
1364 // Should we create user groups that are specified in LDAP, but not found in eZ Publish?
1365 if ( !$createMissingGroups )
1366 {
1367 return;
1368 }
1369
1370 $newNodeIDs = self::publishNewUserGroup( array( $parentNodeID ), array( 'name' => $groupName ) );
1371
1372 if ( count( $newNodeIDs ) > 0 and $isFirstGroupAssignment )
1373 {
1374 $defaultUserPlacement = $newNodeIDs[0]; // We only supplied one parent to publishNewUserGroup(), so there is only one node
1375 }
1376 else if ( count( $newNodeIDs ) > 0 )
1377 {
1378 $extraNodeAssignments[] = $newNodeIDs[0]; // We only supplied one parent to publishNewUserGroup(), so there is only one node
1379 }
1380 }
1381
1382 /*
1383 Static method, for internal usage only
1384 Fetch the LDAP group object given by the DN, and return its name
1385 */
1386 static function getGroupNameByDN( $ds, $groupDN )
1387 {
1388 $LDAPIni = eZINI::instance( 'ldap.ini' );
1389 $LDAPGroupNameAttribute = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupNameAttribute' );
1390
1391 // First, try to see if the $LDAPGroupNameAttribute is contained within the DN, in that case we can read it directly
1392 $groupDNParts = ldap_explode_dn( $groupDN, 0 );
1393 list( $firstName, $firstValue ) = explode( '=', $groupDNParts[0] );
1394
1395 if ( $firstName = $LDAPGroupNameAttribute ) // Read the group name attribute directly from the group DN
1396 {
1397 $groupName = $firstValue;
1398 }
1399 else // Read the LDAP group object, get the group name attribute from it
1400 {
1401 $sr = ldap_read( $ds, $groupDN, "($LDAPGroupNameAttribute=*)", array( $LDAPGroupNameAttribute ) );
1402 $info = ldap_get_entries( $ds, $sr );
1403
1404 if ( $info['count'] < 1 or $info[0]['count'] < 1 )
1405 {
1406 eZDebug::writeWarning( 'LDAP group not found, tried DN: ' . $groupDN, __METHOD__ );
1407 return false;
1408 }
1409
1410 $groupName = $info[0][$LDAPGroupNameAttribute];
1411 if ( is_array( $groupName ) ) // This may be a string or an array of strings, depending on LDAP setup
1412 $groupName = $groupName[0]; // At least one must exist, since we specified it in the search filter
1413 }
1414
1415 return $groupName;
1416 }
1417
1418 /*
1419 Based on a similar function suggested at: http://php.net/manual/en/function.ldap-search.php
1420 */
1421 static function ldap_escape( $str, $for_dn = false )
1422 {
1423 // see: RFC2254
1424 // http://msdn.microsoft.com/en-us/library/ms675768(VS.85).aspx
1425 // http://www-03.ibm.com/systems/i/software/ldap/underdn.html
1426
1427 if ( $for_dn )
1428 {
1429 $metaChars = array( ',', '=', '+', '<', '>', ';', '\\', '"', '#' );
1430 $quotedMetaChars = array( '\2c', '\3d', '\2b', '\3c', '\3e', '\3b', '\5c', '\22', '\23' );
1431 }
1432 else
1433 {
1434 $metaChars = array( '*', '(', ')', '\\', chr(0) );
1435 $quotedMetaChars = array( '\2a', '\28', '\29', '\5c', '\00' );
1436 }
1437
1438 return str_replace( $metaChars, $quotedMetaChars, $str );
1439 }
1440
1441 }
1442
1443 ?>
eZContentCacheManager\clearObjectViewCache
static clearObjectViewCache( $objectID, $versionNum=true, $additionalNodeList=false)
Definition: ezcontentcachemanager.php:676
eZContentClass\fetch
static fetch( $id, $asObject=true, $version=eZContentClass::VERSION_STATUS_DEFINED, $user_id=false, $parent_id=null)
Definition: ezcontentclass.php:1116
eZContentObjectTreeNode\updateMainNodeID
static updateMainNodeID( $mainNodeID, $objectID, $version, $parentMainNodeID, $updateSection=true)
Definition: ezcontentobjecttreenode.php:2882
eZContentObjectTreeNode\fetch
static fetch( $nodeID=false, $lang=false, $asObject=true, $conditions=false)
Definition: ezcontentobjecttreenode.php:3058
eZContentObjectTreeNode\fetchNode
static fetchNode( $contentObjectID, $parentNodeID)
Definition: ezcontentobjecttreenode.php:3172
eZContentObjectTreeNode\fetchByContentObjectID
static fetchByContentObjectID( $contentObjectID, $asObject=true, $contentObjectVersion=false)
Definition: ezcontentobjecttreenode.php:2918
eZContentObjectTreeNode\subTreeByNodeID
static subTreeByNodeID( $params=false, $nodeID=0)
Definition: ezcontentobjecttreenode.php:1940
eZContentObjectVersion\STATUS_DRAFT
const STATUS_DRAFT
Definition: ezcontentobjectversion.php:29
eZContentObject\STATUS_PUBLISHED
const STATUS_PUBLISHED
Definition: ezcontentobject.php:20
eZContentObject\fetch
static fetch( $id, $asObject=true)
Definition: ezcontentobject.php:885
eZDB\instance
static instance( $databaseImplementation=false, $databaseParameters=false, $forceNewInstance=false)
Definition: ezdb.php:117
eZDebugSetting\writeDebug
static writeDebug( $conditionName, $string, $label="")
Definition: ezdebugsetting.php:127
eZDebug\writeError
static writeError( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:545
eZDebug\writeNotice
static writeNotice( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:459
eZDebug\writeWarning
static writeWarning( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:502
eZHTTPTool\instance
static instance()
Definition: ezhttptool.php:189
eZLDAPUser
The class eZLDAPUser does.
Definition: ezldapuser.php:18
eZLDAPUser\goAndPublishGroups
static goAndPublishGroups(&$requiredParams, $curDN, &$groupsTree, &$stack, $depth, $isUser=false)
Definition: ezldapuser.php:1066
eZLDAPUser\ldap_escape
static ldap_escape( $str, $for_dn=false)
Definition: ezldapuser.php:1421
eZLDAPUser\loginUser
static loginUser( $login, $password, $authenticationMatch=false)
Definition: ezldapuser.php:24
eZLDAPUser\getUserGroupsTree
static getUserGroupsTree(&$requiredParams, $filter, $curDN, &$groupsTree, &$stack, $depth=0)
Definition: ezldapuser.php:1218
eZLDAPUser\publishNewUserGroup
static publishNewUserGroup( $parentNodeIDs, $newGroupAttributes, $isUtf8Encoding=false)
Definition: ezldapuser.php:956
eZLDAPUser\publishUpdateUser
static publishUpdateUser( $parentNodeIDs, $defaultUserPlacement, $userAttributes, $isUtf8Encoding=false)
Definition: ezldapuser.php:662
eZLDAPUser\getGroupNameByDN
static getGroupNameByDN( $ds, $groupDN)
Definition: ezldapuser.php:1386
eZLDAPUser\getNodeAssignmentsForGroupName
static getNodeAssignmentsForGroupName( $groupName, $isFirstGroupAssignment, &$defaultUserPlacement, &$extraNodeAssignments, $createMissingGroups, $parentNodeID)
Definition: ezldapuser.php:1328
eZNodeAssignment\create
static create( $parameters=array())
Definition: eznodeassignment.php:193
eZOperationHandler\execute
static execute( $moduleName, $operationName, $operationParameters, $lastTriggerName=null, $useTriggers=true)
Definition: ezoperationhandler.php:42
eZPersistentObject\count
static count( $def, $conds=null, $field=null)
Definition: ezpersistentobject.php:187
eZUserSetting\fetch
static fetch( $userID, $asObject=true)
Definition: ezusersetting.php:77
eZUser
eZUser handles eZ Publish user accounts
Definition: ezuser.php:19
eZUser\authenticateHash
static authenticateHash( $user, $password, $site, $type, $hash)
Definition: ezuser.php:1741
eZUser\authenticationMatch
static authenticationMatch()
Definition: ezuser.php:719
eZUser\updateLastVisit
static updateLastVisit( $userID, $updateLoginCount=false)
Definition: ezuser.php:1529
eZUser\hashType
static hashType()
Definition: ezuser.php:675
eZUser\site
static site()
Definition: ezuser.php:687
eZUser\isEnabledAfterFailedLogin
static isEnabledAfterFailedLogin( $userID, $ignoreTrusted=false)
Definition: ezuser.php:1014
eZUser\fetchByName
static fetchByName( $login, $asObject=true)
Definition: ezuser.php:361
eZUser\create
static create( $contentObjectID)
Definition: ezuser.php:237
eZUser\setCurrentlyLoggedInUser
static setCurrentlyLoggedInUser( $user, $userID, $flags=0)
Definition: ezuser.php:1054
eZUser\setFailedLoginAttempts
static setFailedLoginAttempts( $userID, $value=false, $setByForce=false)
Definition: ezuser.php:1594
eZUser\eZUser
eZUser( $row=array())
Definition: ezuser.php:78
eZUser\PASSWORD_HASH_MYSQL
const PASSWORD_HASH_MYSQL
Definition: ezuser.php:31
eZUser\AUTHENTICATE_LOGIN
const AUTHENTICATE_LOGIN
Authenticate by matching the login field.
Definition: ezuser.php:51
eZUser\currentUser
static currentUser()
Definition: ezuser.php:1716
eZUser\AUTHENTICATE_EMAIL
const AUTHENTICATE_EMAIL
Authenticate by matching the email field.
Definition: ezuser.php:53
eZUser\createHash
static createHash( $user, $password, $site, $type, $hash=false)
Definition: ezuser.php:1846
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.