eZ Publish  [4.0]
ezldapuser.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZLDAPUser class
00004 //
00005 // Created on: <24-Jul-2003 15:48:06 wy>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*! \file ezldapuser.php
00032 */
00033 
00034 /*!
00035   \class eZLDAPUser ezldapuser.php
00036   \ingroup eZDatatype
00037   \brief The class eZLDAPUser does
00038 
00039 */
00040 //include_once( "kernel/classes/datatypes/ezuser/ezusersetting.php" );
00041 //include_once( "kernel/classes/datatypes/ezuser/ezuser.php" );
00042 //include_once( 'lib/ezutils/classes/ezini.php' );
00043 
00044 class eZLDAPUser extends eZUser
00045 {
00046     /*!
00047      Constructor
00048     */
00049     function eZLDAPUser()
00050     {
00051     }
00052 
00053     /*!
00054     \static
00055      Logs in the user if applied username and password is
00056      valid. The userID is returned if succesful, false if not.
00057     */
00058     static function loginUser( $login, $password, $authenticationMatch = false )
00059     {
00060         $http = eZHTTPTool::instance();
00061         $db = eZDB::instance();
00062 
00063         if ( $authenticationMatch === false )
00064             $authenticationMatch = eZUser::authenticationMatch();
00065 
00066         $loginEscaped = $db->escapeString( $login );
00067         $passwordEscaped = $db->escapeString( $password );
00068 
00069         $loginArray = array();
00070         if ( $authenticationMatch & eZUser::AUTHENTICATE_LOGIN )
00071             $loginArray[] = "login='$loginEscaped'";
00072         if ( $authenticationMatch & eZUser::AUTHENTICATE_EMAIL )
00073             $loginArray[] = "email='$loginEscaped'";
00074         if ( count( $loginArray ) == 0 )
00075             $loginArray[] = "login='$loginEscaped'";
00076         $loginText = implode( ' OR ', $loginArray );
00077 
00078         $contentObjectStatus = eZContentObject::STATUS_PUBLISHED;
00079 
00080         $ini = eZINI::instance();
00081         $LDAPIni = eZINI::instance( 'ldap.ini' );
00082         $databaseName = $db->databaseName();
00083         // if mysql
00084         if ( $databaseName === 'mysql' )
00085         {
00086             $query = "SELECT contentobject_id, password_hash, password_hash_type, email, login
00087                       FROM ezuser, ezcontentobject
00088                       WHERE ( $loginText ) AND
00089                             ezcontentobject.status='$contentObjectStatus' AND
00090                             ( ezcontentobject.id=contentobject_id OR ( password_hash_type=4 AND ( $loginText ) AND password_hash=PASSWORD('$passwordEscaped') ) )";
00091         }
00092         else
00093         {
00094             $query = "SELECT contentobject_id, password_hash, password_hash_type, email, login
00095                       FROM ezuser, ezcontentobject
00096                       WHERE ( $loginText ) AND
00097                             ezcontentobject.status='$contentObjectStatus' AND
00098                             ezcontentobject.id=contentobject_id";
00099         }
00100 
00101         $users = $db->arrayQuery( $query );
00102         $exists = false;
00103         if ( count( $users ) >= 1 )
00104         {
00105             foreach ( $users as $userRow )
00106             {
00107                 $userID = $userRow['contentobject_id'];
00108                 $hashType = $userRow['password_hash_type'];
00109                 $hash = $userRow['password_hash'];
00110                 $exists = eZUser::authenticateHash( $userRow['login'], $password, eZUser::site(),
00111                                                     $hashType,
00112                                                     $hash );
00113 
00114                 // If hash type is MySql
00115                 if ( $hashType == eZUser::PASSWORD_HASH_MYSQL and $databaseName === 'mysql' )
00116                 {
00117                     $queryMysqlUser = "SELECT contentobject_id, password_hash, password_hash_type, email, login
00118                                        FROM ezuser, ezcontentobject
00119                                        WHERE ezcontentobject.status='$contentObjectStatus' AND
00120                                              password_hash_type=4 AND ( $loginText ) AND password_hash=PASSWORD('$passwordEscaped') ";
00121                     $mysqlUsers = $db->arrayQuery( $queryMysqlUser );
00122                     if ( count( $mysqlUsers ) >= 1 )
00123                         $exists = true;
00124                 }
00125 
00126                 eZDebugSetting::writeDebug( 'kernel-user', eZUser::createHash( $userRow['login'], $password, eZUser::site(),
00127                                                                                $hashType ), "check hash" );
00128                 eZDebugSetting::writeDebug( 'kernel-user', $hash, "stored hash" );
00129                  // If current user has been disabled after a few failed login attempts.
00130                 $canLogin = eZUser::isEnabledAfterFailedLogin( $userID );
00131 
00132                 if ( $exists )
00133                 {
00134                     // We should store userID for warning message.
00135                     $GLOBALS['eZFailedLoginAttemptUserID'] = $userID;
00136 
00137                     $userSetting = eZUserSetting::fetch( $userID );
00138                     $isEnabled = $userSetting->attribute( "is_enabled" );
00139                     if ( $hashType != eZUser::hashType() and
00140                          strtolower( $ini->variable( 'UserSettings', 'UpdateHash' ) ) == 'true' )
00141                     {
00142                         $hashType = eZUser::hashType();
00143                         $hash = eZUser::createHash( $login, $password, eZUser::site(),
00144                                                     $hashType );
00145                         $db->query( "UPDATE ezuser SET password_hash='$hash', password_hash_type='$hashType' WHERE contentobject_id='$userID'" );
00146                     }
00147                     break;
00148                 }
00149             }
00150         }
00151         if ( $exists and $isEnabled and $canLogin )
00152         {
00153             eZDebugSetting::writeDebug( 'kernel-user', $userRow, 'user row' );
00154             $user = new eZUser( $userRow );
00155             eZDebugSetting::writeDebug( 'kernel-user', $user, 'user' );
00156             $userID = $user->attribute( 'contentobject_id' );
00157 
00158             eZUser::updateLastVisit( $userID );
00159             eZUser::setCurrentlyLoggedInUser( $user, $userID );
00160 
00161             // Reset number of failed login attempts
00162             eZUser::setFailedLoginAttempts( $userID, 0 );
00163 
00164             return $user;
00165         }
00166         else if ( $LDAPIni->variable( 'LDAPSettings', 'LDAPEnabled' ) == "true" )
00167         {
00168             // read LDAP ini settings
00169             // and then try to bind to the ldap server
00170 
00171             $LDAPVersion    = $LDAPIni->variable( 'LDAPSettings', 'LDAPVersion' );
00172             $LDAPServer     = $LDAPIni->variable( 'LDAPSettings', 'LDAPServer' );
00173             $LDAPPort       = $LDAPIni->variable( 'LDAPSettings', 'LDAPPort' );
00174             $LDAPBaseDN     = $LDAPIni->variable( 'LDAPSettings', 'LDAPBaseDn' );
00175             $LDAPBindUser   = $LDAPIni->variable( 'LDAPSettings', 'LDAPBindUser' );
00176             $LDAPBindPassword       = $LDAPIni->variable( 'LDAPSettings', 'LDAPBindPassword' );
00177             $LDAPSearchScope        = $LDAPIni->variable( 'LDAPSettings', 'LDAPSearchScope' );
00178 
00179             $LDAPLoginAttribute     = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPLoginAttribute' ) );
00180             $LDAPFirstNameAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPFirstNameAttribute' ) );
00181             $LDAPLastNameAttribute  = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPLastNameAttribute' ) );
00182             $LDAPEmailAttribute     = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPEmailAttribute' ) );
00183 
00184             $defaultUserPlacement   = $ini->variable( "UserSettings", "DefaultUserPlacement" );
00185 
00186             $LDAPUserGroupAttributeType = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupAttributeType' ) );
00187             $LDAPUserGroupAttribute     = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupAttribute' ) );
00188 
00189             if ( $LDAPIni->hasVariable( 'LDAPSettings', 'Utf8Encoding' ) )
00190             {
00191                 $Utf8Encoding = $LDAPIni->variable( 'LDAPSettings', 'Utf8Encoding' );
00192                 if ( $Utf8Encoding == "true" )
00193                     $isUtf8Encoding = true;
00194                 else
00195                     $isUtf8Encoding = false;
00196             }
00197             else
00198             {
00199                 $isUtf8Encoding = false;
00200             }
00201 
00202             if ( $LDAPIni->hasVariable( 'LDAPSettings', 'LDAPSearchFilters' ) )
00203             {
00204                 $LDAPFilters = $LDAPIni->variable( 'LDAPSettings', 'LDAPSearchFilters' );
00205             }
00206             if ( $LDAPIni->hasVariable( 'LDAPSettings', 'LDAPUserGroupType' ) and  $LDAPIni->hasVariable( 'LDAPSettings', 'LDAPUserGroup' ) )
00207             {
00208                 $LDAPUserGroupType = $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupType' );
00209                 $LDAPUserGroup = $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroup' );
00210             }
00211 
00212             $LDAPFilter = "( &";
00213             if ( count( $LDAPFilters ) > 0 )
00214             {
00215                 foreach ( array_keys( $LDAPFilters ) as $key )
00216                 {
00217                     $LDAPFilter .= "(" . $LDAPFilters[$key] . ")";
00218                 }
00219             }
00220             $LDAPEqualSign = trim($LDAPIni->variable( 'LDAPSettings', "LDAPEqualSign" ) );
00221             $LDAPBaseDN = str_replace( $LDAPEqualSign, "=", $LDAPBaseDN );
00222             $LDAPFilter = str_replace( $LDAPEqualSign, "=", $LDAPFilter );
00223 
00224             $ds = ldap_connect( $LDAPServer, $LDAPPort );
00225 
00226             if ( $ds )
00227             {
00228                 ldap_set_option( $ds, LDAP_OPT_PROTOCOL_VERSION, $LDAPVersion );
00229                 if ( $LDAPBindUser == '' )
00230                 {
00231                     $r = ldap_bind( $ds );
00232                 }
00233                 else
00234                 {
00235                     $r = ldap_bind( $ds, $LDAPBindUser, $LDAPBindPassword );
00236                 }
00237                 if ( !$r )
00238                 {
00239                     // Increase number of failed login attempts.
00240                     if ( isset( $userID ) )
00241                         eZUser::setFailedLoginAttempts( $userID );
00242 
00243                     $user = false;
00244                     return $user;
00245                 }
00246 
00247                 $LDAPFilter .= "($LDAPLoginAttribute=$login)";
00248                 $LDAPFilter .= ")";
00249 
00250                 ldap_set_option( $ds, LDAP_OPT_SIZELIMIT, 0 );
00251                 ldap_set_option( $ds, LDAP_OPT_TIMELIMIT, 0 );
00252 
00253                 $retrieveAttributes = array( $LDAPLoginAttribute,
00254                                              $LDAPFirstNameAttribute,
00255                                              $LDAPLastNameAttribute,
00256                                              $LDAPEmailAttribute );
00257                 if ( $LDAPUserGroupAttributeType )
00258                     $retrieveAttributes[] = $LDAPUserGroupAttribute;
00259 
00260                 if ( $LDAPSearchScope == "one" )
00261                     $sr = ldap_list( $ds, $LDAPBaseDN, $LDAPFilter, $retrieveAttributes );
00262                 else if ( $LDAPSearchScope == "base" )
00263                     $sr = ldap_read( $ds, $LDAPBaseDN, $LDAPFilter, $retrieveAttributes );
00264                 else
00265                     $sr = ldap_search( $ds, $LDAPBaseDN, $LDAPFilter, $retrieveAttributes );
00266 
00267                 $info = ldap_get_entries( $ds, $sr ) ;
00268                 if ( $info['count'] > 1 )
00269                 {
00270                     // More than one user with same uid, not allow login.
00271                     $user = false;
00272                     return $user;
00273                 }
00274                 else if ( $info['count'] < 1 )
00275                 {
00276                     // Increase number of failed login attempts.
00277                     if ( isset( $userID ) )
00278                         eZUser::setFailedLoginAttempts( $userID );
00279 
00280                     // user DN was not found
00281                     $user = false;
00282                     return $user;
00283                 }
00284 
00285                 if( !$password )
00286                 {
00287                     $password = crypt( microtime() );
00288                 }
00289 
00290                 // is it real authenticated LDAP user?
00291                 if  ( !@ldap_bind( $ds, $info[0]['dn'], $password ) )
00292                 {
00293                     // Increase number of failed login attempts.
00294                     if ( isset( $userID ) )
00295                         eZUser::setFailedLoginAttempts( $userID );
00296 
00297                     $user = false;
00298                     return $user;
00299                 }
00300 
00301                 $extraNodeAssignments = array();
00302                 $userGroupClassID = $ini->variable( "UserSettings", "UserGroupClassID" );
00303 
00304                 // default user group assigning
00305                 if ( $LDAPUserGroupType != null )
00306                 {
00307                     if ( $LDAPUserGroupType == "name" )
00308                     {
00309                         if ( is_array( $LDAPUserGroup ) )
00310                         {
00311                             foreach ( array_keys( $LDAPUserGroup ) as $key )
00312                             {
00313                                 $groupName = $LDAPUserGroup[$key];
00314                                 $groupQuery = "SELECT ezcontentobject_tree.node_id
00315                                                  FROM ezcontentobject, ezcontentobject_tree
00316                                                 WHERE ezcontentobject.name like '$groupName'
00317                                                   AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00318                                                   AND ezcontentobject.contentclass_id=$userGroupClassID";
00319                                 $groupObject = $db->arrayQuery( $groupQuery );
00320                                 if ( count( $groupObject ) > 0 and $key == 0 )
00321                                 {
00322                                     $defaultUserPlacement = $groupObject[0]['node_id'];
00323                                 }
00324                                 else if ( count( $groupObject ) > 0 )
00325                                 {
00326                                     $extraNodeAssignments[] = $groupObject[0]['node_id'];
00327                                 }
00328                             }
00329                         }
00330                         else
00331                         {
00332                             $groupName = $LDAPUserGroup;
00333                             $groupQuery = "SELECT ezcontentobject_tree.node_id
00334                                              FROM ezcontentobject, ezcontentobject_tree
00335                                             WHERE ezcontentobject.name like '$groupName'
00336                                               AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00337                                               AND ezcontentobject.contentclass_id=$userGroupClassID";
00338                             $groupObject = $db->arrayQuery( $groupQuery );
00339 
00340                             if ( count( $groupObject ) > 0  )
00341                             {
00342                                 $defaultUserPlacement = $groupObject[0]['node_id'];
00343                             }
00344                         }
00345                     }
00346                     else if ( $LDAPUserGroupType == "id" )
00347                     {
00348                         if ( is_array( $LDAPUserGroup ) )
00349                         {
00350                             foreach ( array_keys( $LDAPUserGroup ) as $key )
00351                             {
00352                                 $groupID = $LDAPUserGroup[$key];
00353                                 $groupQuery = "SELECT ezcontentobject_tree.node_id
00354                                                  FROM ezcontentobject, ezcontentobject_tree
00355                                                 WHERE ezcontentobject.id='$groupID'
00356                                                   AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00357                                                   AND ezcontentobject.contentclass_id=$userGroupClassID";
00358                                 $groupObject = $db->arrayQuery( $groupQuery );
00359                                 if ( count( $groupObject ) > 0 and $key == 0 )
00360                                 {
00361                                     $defaultUserPlacement = $groupObject[0]['node_id'];
00362                                 }
00363                                 else if ( count( $groupObject ) > 0 )
00364                                 {
00365                                     $extraNodeAssignments[] = $groupObject[0]['node_id'];
00366                                 }
00367                             }
00368                         }
00369                         else
00370                         {
00371                             $groupID = $LDAPUserGroup;
00372                             $groupQuery = "SELECT ezcontentobject_tree.node_id
00373                                              FROM ezcontentobject, ezcontentobject_tree
00374                                             WHERE ezcontentobject.id='$groupID'
00375                                               AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00376                                               AND ezcontentobject.contentclass_id=$userGroupClassID";
00377                             $groupObject = $db->arrayQuery( $groupQuery );
00378 
00379                             if ( count( $groupObject ) > 0  )
00380                             {
00381                                 $defaultUserPlacement = $groupObject[0]['node_id'];
00382                             }
00383                         }
00384                     }
00385                 }
00386 
00387                 $adminUser = eZUser::fetchByName( 'admin' );
00388                 $adminUserContentObjectID = $adminUser->attribute( 'contentobject_id' );
00389 
00390                 // read group mapping LDAP settings
00391                 $LDAPGroupMappingType = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupMappingType' );
00392                 $LDAPUserGroupMap     = $LDAPIni->variable( 'LDAPSettings', 'LDAPUserGroupMap' );
00393 
00394                 if ( !is_array( $LDAPUserGroupMap ) )
00395                     $LDAPUserGroupMap = array();
00396 
00397                 // group mapping constants
00398                 $ByMemberAttribute             = 'SimpleMapping'; // by group's member attributes (with mapping)
00399                 $ByMemberAttributeHierarhicaly = 'GetGroupsTree'; // by group's member attributes hierarhically
00400                 $ByGroupAttribute              = 'UseGroupAttribute'; // by user's group attribute (old style)
00401                 $groupMappingTypes = array( $ByMemberAttribute,
00402                                             $ByMemberAttributeHierarhicaly,
00403                                             $ByGroupAttribute);
00404 
00405                 $userData =& $info[ 0 ];
00406 
00407                 // default mapping using old style
00408                 if ( !in_array( $LDAPGroupMappingType, $groupMappingTypes ) )
00409                 {
00410                     $LDAPGroupMappingType = $ByGroupAttribute;
00411                 }
00412 
00413                 if ( $LDAPGroupMappingType == $ByMemberAttribute or
00414                      $LDAPGroupMappingType == $ByMemberAttributeHierarhicaly )
00415                 {
00416                     $LDAPGroupBaseDN          = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupBaseDN' );
00417                     $LDAPGroupClass           = $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupClass' );
00418 
00419                     $LDAPGroupNameAttribute   = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupNameAttribute' ) );
00420                     $LDAPGroupMemberAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupMemberAttribute' ) );
00421                     $LDAPGroupDescriptionAttribute = strtolower( $LDAPIni->variable( 'LDAPSettings', 'LDAPGroupDescriptionAttribute' ) );
00422 
00423                     $groupSearchingDepth = ( $LDAPGroupMappingType == '1' ) ? 1 : 1000;
00424 
00425                     // now, get all parents for currently ldap authenticated user
00426                     $requiredParams = array();
00427                     $requiredParams[ 'LDAPLoginAttribute' ]       = $LDAPLoginAttribute;
00428                     $requiredParams[ 'LDAPGroupBaseDN' ]          = $LDAPGroupBaseDN;
00429                     $requiredParams[ 'LDAPGroupClass' ]           = $LDAPGroupClass;
00430                     $requiredParams[ 'LDAPGroupNameAttribute' ]   = $LDAPGroupNameAttribute;
00431                     $requiredParams[ 'LDAPGroupMemberAttribute' ] = $LDAPGroupMemberAttribute;
00432                     $requiredParams[ 'LDAPGroupDescriptionAttribute' ] = $LDAPGroupDescriptionAttribute;
00433                     $requiredParams[ 'ds' ] =& $ds;
00434                     $requiredParams[ 'TopUserGroupNodeID' ] = 5;
00435 
00436                     $groupsTree = array();
00437                     $stack = array();
00438                     $newfilter = '(&(objectClass=' . $LDAPGroupClass . ')(' . $LDAPGroupMemberAttribute . '=' . $userData['dn'] . '))';
00439 
00440                     $groupsTree[ $userData['dn'] ] = array( 'data' => & $userData,
00441                                                                 'parents' => array(),
00442                                                                 'children' => array() );
00443 
00444                     eZLDAPUser::getUserGroupsTree( $requiredParams, $newfilter, $userData['dn'], $groupsTree, $stack, $groupSearchingDepth );
00445                     $userRecord =& $groupsTree[ $userData['dn'] ];
00446 
00447                     if ( $LDAPGroupMappingType == $ByMemberAttribute )
00448                     {
00449                         if ( count( $userRecord[ 'parents' ] ) > 0 )
00450                         {
00451                             $remappedGroupNames = array();
00452                             foreach ( array_keys( $userRecord[ 'parents' ] ) as $key )
00453                             {
00454                                 $parentGroup =& $userRecord[ 'parents' ][ $key ];
00455                                 if ( isset( $parentGroup[ 'data' ][ $LDAPGroupNameAttribute ] ) )
00456                                 {
00457                                     $ldapGroupName = $parentGroup[ 'data' ][ $LDAPGroupNameAttribute ];
00458                                     if ( is_array( $ldapGroupName ) )
00459                                     {
00460                                         $ldapGroupName = ( $ldapGroupName[ 'count' ] > 0 ) ? $ldapGroupName[ 0 ] : '';
00461                                     }
00462 
00463                                     // remap group name and check that group exists
00464                                     if ( array_key_exists( $ldapGroupName, $LDAPUserGroupMap ) )
00465                                     {
00466                                         $remmapedGroupName = $LDAPUserGroupMap[ $ldapGroupName ];
00467                                         $groupQuery = "SELECT ezcontentobject_tree.node_id
00468                                                          FROM ezcontentobject, ezcontentobject_tree
00469                                                         WHERE ezcontentobject.name like '$remmapedGroupName'
00470                                                           AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00471                                                           AND ezcontentobject.contentclass_id=$userGroupClassID";
00472                                         $groupRow = $db->arrayQuery( $groupQuery );
00473 
00474                                         if ( count( $groupRow ) > 0 )
00475                                         {
00476                                             $userRecord['new_parents'][] = $groupRow[ 0 ][ 'node_id' ];
00477                                         }
00478                                     }
00479                                 }
00480                             }
00481                         }
00482                     }
00483                     else if ( $LDAPGroupMappingType == $ByMemberAttributeHierarhicaly )
00484                     {
00485                         eZUser::setCurrentlyLoggedInUser( $adminUser, $adminUserContentObjectID );
00486 
00487                         $stack = array();
00488                         self::goAndPublishGroups( $requiredParams, $userData['dn'], $groupsTree, $stack, $groupSearchingDepth, true );
00489                     }
00490                     if ( isset( $userRecord['new_parents'] ) and
00491                          count( $userRecord['new_parents'] ) > 0 )
00492                     {
00493                         $defaultUserPlacement = $userRecord['new_parents'][0];
00494                         $extraNodeAssignments = array_merge( $extraNodeAssignments, $userRecord['new_parents'] );
00495                     }
00496                 }
00497                 else if ( $LDAPGroupMappingType == $ByGroupAttribute ) // old style mapping by group (employeetype) attribute
00498                 {
00499                     if ( $LDAPUserGroupAttributeType )
00500                     {
00501                         $groupAttributeCount = $info[0][$LDAPUserGroupAttribute]['count'];
00502                         if ( $LDAPUserGroupAttributeType == "name" )
00503                         {
00504                             for ( $i = 0; $i < $groupAttributeCount; $i++ )
00505                             {
00506                                 if ( $isUtf8Encoding )
00507                                 {
00508                                     $groupName = utf8_decode( $info[0][$LDAPUserGroupAttribute][$i] );
00509                                 }
00510                                 else
00511                                 {
00512                                     $groupName = $info[0][$LDAPUserGroupAttribute][$i];
00513                                 }
00514                                 if ( $groupName != null )
00515                                 {
00516                                     $groupQuery = "SELECT ezcontentobject_tree.node_id
00517                                                      FROM ezcontentobject, ezcontentobject_tree
00518                                                     WHERE ezcontentobject.name like '$groupName'
00519                                                       AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00520                                                       AND ezcontentobject.contentclass_id=$userGroupClassID";
00521                                     $groupObject = $db->arrayQuery( $groupQuery );
00522 
00523                                     if ( count( $groupObject ) > 0 and $i == 0 )
00524                                     {
00525                                         $defaultUserPlacement = $groupObject[0]['node_id'];
00526                                     }
00527                                     else if ( count( $groupObject ) > 0 )
00528                                     {
00529                                         $extraNodeAssignments[] = $groupObject[0]['node_id'];
00530                                     }
00531                                 }
00532                             }
00533                         }
00534                         else if ( $LDAPUserGroupAttributeType == "id" )
00535                         {
00536                             for ( $i = 0; $i < $groupAttributeCount; $i++ )
00537                             {
00538                                 if ( $isUtf8Encoding )
00539                                 {
00540                                     $groupID = utf8_decode( $info[0][$LDAPUserGroupAttribute][$i] );
00541                                 }
00542                                 else
00543                                 {
00544                                     $groupID = $info[0][$LDAPUserGroupAttribute][$i];
00545                                 }
00546 
00547                                 if ( $groupID != null )
00548                                 {
00549                                     $groupName = "LDAP " . $groupID;
00550                                     $groupQuery = "SELECT ezcontentobject_tree.node_id
00551                                                      FROM ezcontentobject, ezcontentobject_tree
00552                                                     WHERE ezcontentobject.name like '$groupName'
00553                                                       AND ezcontentobject.id=ezcontentobject_tree.contentobject_id
00554                                                       AND ezcontentobject.contentclass_id=$userGroupClassID";
00555                                     $groupObject = $db->arrayQuery( $groupQuery );
00556 
00557                                     if ( count( $groupObject ) > 0 and $i == 0 )
00558                                     {
00559                                         $defaultUserPlacement = $groupObject[0]['node_id'];
00560                                     }
00561                                     else if ( count( $groupObject ) > 0 )
00562                                     {
00563                                         $extraNodeAssignments[] = $groupObject[0]['node_id'];
00564                                     }
00565                                 }
00566                             }
00567                         }
00568                     }
00569                 }
00570 
00571                 $userAttributes = array( 'login'      => $login,
00572                                          'first_name' => isset( $userData[ $LDAPFirstNameAttribute ] ) ? $userData[ $LDAPFirstNameAttribute ][0] : false,
00573                                          'last_name'  => isset( $userData[ $LDAPLastNameAttribute ] ) ? $userData[ $LDAPLastNameAttribute ][0] : false,
00574                                          'email'      => isset( $userData[ $LDAPEmailAttribute ] ) ? $userData[ $LDAPEmailAttribute ][0] : false );
00575 
00576                 $oldUser = clone eZUser::currentUser();
00577                 eZUser::setCurrentlyLoggedInUser( $adminUser, $adminUserContentObjectID );
00578                 $existingUser = eZLDAPUser::publishUpdateUser( $extraNodeAssignments, $defaultUserPlacement, $userAttributes, $isUtf8Encoding );
00579 
00580                 if ( is_object( $existingUser ) )
00581                 {
00582                     eZUser::setCurrentlyLoggedInUser( $existingUser, $existingUser->attribute( 'contentobject_id' ) );
00583                 }
00584                 else
00585                 {
00586                     eZUser::setCurrentlyLoggedInUser( $oldUser, $oldUser->attribute( 'contentobject_id' ) );
00587                 }
00588 
00589                 ldap_close( $ds );
00590                 return $existingUser;
00591             }
00592             else
00593             {
00594                 eZDebug::writeError( 'Cannot initialize connection for LDAP server', 'eZLDAPUser::loginUser()' );
00595                 $user = false;
00596                 return $user;
00597             }
00598         }
00599         else
00600         {
00601             // Increase number of failed login attempts.
00602             if ( isset( $userID ) )
00603                 eZUser::setFailedLoginAttempts( $userID );
00604 
00605             $user = false;
00606             return $user;
00607         }
00608     }
00609 
00610     /*
00611         Static method, for internal usage only.
00612         Publishes new or update existing user
00613     */
00614     static function publishUpdateUser( $parentNodeIDs, $defaultUserPlacement, $userAttributes, $isUtf8Encoding = false )
00615     {
00616         $thisFunctionErrorLabel = 'eZLDAPUser.php, function publishUpdateUser()';
00617 
00618         if ( !is_array( $userAttributes ) or
00619              !isset( $userAttributes[ 'login' ] ) or empty( $userAttributes[ 'login' ] ) )
00620         {
00621             eZDebug::writeWarning( 'Empty user login passed.',
00622                                    $thisFunctionErrorLabel );
00623             return false;
00624         }
00625 
00626         if ( ( !is_array( $parentNodeIDs ) or count( $parentNodeIDs ) < 1 ) and
00627              !is_numeric( $defaultUserPlacement ) )
00628         {
00629             eZDebug::writeWarning( 'No one parent node IDs was passed for publishing new user (login = "' .
00630                                    $userAttributes[ 'login' ] . '")',
00631                                    $thisFunctionErrorLabel );
00632             return false;
00633         }
00634         $parentNodeIDs[] = $defaultUserPlacement;
00635         $parentNodeIDs = array_unique( $parentNodeIDs );
00636 
00637 
00638         $login      = $userAttributes[ 'login' ];
00639         $first_name = $userAttributes[ 'first_name' ];
00640         $last_name  = $userAttributes[ 'last_name' ];
00641         $email      = $userAttributes[ 'email' ];
00642 
00643         if ( $isUtf8Encoding )
00644         {
00645             $first_name = utf8_decode( $first_name );
00646             $last_name = utf8_decode( $last_name );
00647         }
00648 
00649         $user = eZUser::fetchByName( $login );
00650         $createNewUser = ( is_object( $user ) ) ? false : true;
00651 
00652         if ( $createNewUser )
00653         {
00654             if ( !isset( $first_name ) or empty( $first_name ) or
00655                  !isset( $last_name ) or empty( $last_name ) or
00656                  !isset( $email ) or empty( $email ) )
00657             {
00658                 eZDebug::writeWarning( 'Cannot create user with empty first name (last name or email).',
00659                                        $thisFunctionErrorLabel );
00660                 return false;
00661             }
00662 
00663             $ini = eZINI::instance();
00664             $userClassID = $ini->variable( "UserSettings", "UserClassID" );
00665             $userCreatorID = $ini->variable( "UserSettings", "UserCreatorID" );
00666             $defaultSectionID = $ini->variable( "UserSettings", "DefaultSectionID" );
00667 
00668             $class = eZContentClass::fetch( $userClassID );
00669             $contentObject = $class->instantiate( $userCreatorID, $defaultSectionID );
00670 
00671             $contentObject->store();
00672 
00673             $userID = $contentObjectID = $contentObject->attribute( 'id' );
00674 
00675             $version = $contentObject->version( 1 );
00676             $version->setAttribute( 'modified', time() );
00677             $version->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
00678             $version->store();
00679 
00680             $user = eZLDAPUser::create( $userID );
00681             $user->setAttribute( 'login', $login );
00682         }
00683         else
00684         {
00685             $userID = $contentObjectID = $user->attribute( 'contentobject_id' );
00686             $contentObject = eZContentObject::fetch( $userID );
00687             $version = $contentObject->attribute( 'current' );
00688         }
00689 
00690         //================= common part 1: start ========================
00691         $contentObjectAttributes = $version->contentObjectAttributes();
00692 
00693         // find and set 'name' and 'description' attributes (as standard user group class)
00694         $firstNameIdentifier = 'first_name';
00695         $lastNameIdentifier = 'last_name';
00696         $firstNameAttribute = null;
00697         $lastNameAttribute = null;
00698 
00699         foreach ( $contentObjectAttributes as $attribute )
00700         {
00701             if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $firstNameIdentifier )
00702             {
00703                 $firstNameAttribute = $attribute;
00704             }
00705             else if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $lastNameIdentifier )
00706             {
00707                 $lastNameAttribute = $attribute;
00708             }
00709         }
00710         //================= common part 1: end ==========================
00711 
00712         // If we are updating an existing user, we must find out if some data should be changed.
00713         // In that case, we must create a new version and publish it.
00714         if ( !$createNewUser )
00715         {
00716             $userDataChanged = false;
00717             $firstNameChanged = false;
00718             $lastNameChanged = false;
00719             $emailChanged = false;
00720 
00721             if ( $firstNameAttribute and $firstNameAttribute->attribute( 'data_text' ) != $first_name )
00722             {
00723                 $firstNameChanged = true;
00724             }
00725             $firstNameAttribute = false; // We will load this again from the new version we will create, if it has changed
00726             if ( $lastNameAttribute and $lastNameAttribute->attribute( 'data_text' ) != $last_name )
00727             {
00728                 $lastNameChanged = true;
00729             }
00730             $lastNameAttribute = false; // We will load this again from the new version we will create, if it has changed
00731             if ( $user->attribute( 'email' ) != $email )
00732             {
00733                 $emailChanged = true;
00734             }
00735 
00736             if ( $firstNameChanged or $lastNameChanged or $emailChanged )
00737             {
00738                 $userDataChanged = true;
00739                 // Create new version
00740                 $version = $contentObject->createNewVersion();
00741                 $contentObjectAttributes = $version->contentObjectAttributes();
00742                 foreach ( $contentObjectAttributes as $attribute )
00743                 {
00744                     if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $firstNameIdentifier )
00745                     {
00746                         $firstNameAttribute = $attribute;
00747                     }
00748                     else if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $lastNameIdentifier )
00749                     {
00750                         $lastNameAttribute = $attribute;
00751                     }
00752                 }
00753             }
00754         }
00755 
00756         //================= common part 2: start ========================
00757         if ( $firstNameAttribute )
00758         {
00759             $firstNameAttribute->setAttribute( 'data_text', $first_name );
00760             $firstNameAttribute->store();
00761         }
00762         if ( $lastNameAttribute )
00763         {
00764             $lastNameAttribute->setAttribute( 'data_text', $last_name );
00765             $lastNameAttribute->store();
00766         }
00767 
00768         if ( !isset( $userDataChanged ) or $userDataChanged === true )
00769         {
00770             $contentClass = $contentObject->attribute( 'content_class' );
00771             $name = $contentClass->contentObjectName( $contentObject );
00772             $contentObject->setName( $name );
00773         }
00774 
00775         if ( !isset( $emailChanged ) or $emailChanged === true )
00776         {
00777             $user->setAttribute( 'email', $email );
00778         }
00779 
00780         $user->setAttribute( 'password_hash', "" );
00781         $user->setAttribute( 'password_hash_type', 0 );
00782         $user->store();
00783 
00784         $debugArray = array( 'Updating user data',
00785                              'createNewUser' => $createNewUser,
00786                              'userDataChanged' => isset( $userDataChanged ) ? $userDataChanged : null,
00787                              'login' => $login,
00788                              'first_name' => $first_name,
00789                              'last_name' => $last_name,
00790                              'email' => $email,
00791                              'firstNameAttribute is_object' => is_object( $firstNameAttribute ),
00792                              'lastNameAttribute is_object' => is_object( $lastNameAttribute ),
00793                              'content object id' => $contentObjectID,
00794                              'version id' => $version->attribute( 'version' )
00795         );
00796         eZDebug::writeNotice( var_export( $debugArray, true ), __METHOD__ );
00797         //================= common part 2: end ==========================
00798 
00799         if ( $createNewUser )
00800         {
00801             reset( $parentNodeIDs );
00802             // prepare node assignments for publishing new user
00803             foreach( $parentNodeIDs as $parentNodeID )
00804             {
00805                 $newNodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $contentObjectID,
00806                                                                       'contentobject_version' => 1,
00807                                                                       'parent_node' => $parentNodeID,
00808                                                                       'is_main' => ( $defaultUserPlacement == $parentNodeID ? 1 : 0 ) ) );
00809                 $newNodeAssignment->setAttribute( 'parent_remote_id', uniqid( 'LDAP_' ) );
00810                 $newNodeAssignment->store();
00811             }
00812 
00813             //include_once( 'lib/ezutils/classes/ezoperationhandler.php' );
00814             $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
00815                                                                                          'version' => 1 ) );
00816         }
00817         else
00818         {
00819             if ( $userDataChanged )
00820             {
00821                 // Publish object
00822                 $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
00823                                                                                              'version' => $version->attribute( 'version' ) ) );
00824             }
00825 
00826             $LDAPIni = eZINI::instance( 'ldap.ini' );
00827             $keepGroupAssignment = ( $LDAPIni->hasVariable( 'LDAPSettings', 'KeepGroupAssignment' ) ) ?
00828                 ( $LDAPIni->variable( 'LDAPSettings', 'KeepGroupAssignment' ) == "enabled" ) : false;
00829 
00830             if ( $keepGroupAssignment == false )
00831             {
00832                 $objectIsChanged = false;
00833 
00834                 $db = eZDB::instance();
00835                 $db->begin();
00836 
00837                 // First check existing assignments, remove any that should not exist
00838                 $assignedNodesList = $contentObject->assignedNodes();
00839                 $existingParentNodeIDs = array();
00840                 foreach ( $assignedNodesList as $node )
00841                 {
00842                     $parentNodeID = $node->attribute( 'parent_node_id' );
00843                     if ( !in_array( $parentNodeID, $parentNodeIDs ) )
00844                     {
00845                         $node->removeThis();
00846                         $objectIsChanged = true;
00847                     }
00848                     else
00849                     {
00850                         $existingParentNodeIDs[] = $parentNodeID;
00851                     }
00852                 }
00853 
00854                 // Then check assignments that should exist, add them if they are missing
00855                 foreach( $parentNodeIDs as $parentNodeID )
00856                 {
00857                     if ( !in_array( $parentNodeID, $existingParentNodeIDs ) )
00858                     {
00859                         $newNode = $contentObject->addLocation( $parentNodeID, true );
00860                         $newNode->updateSubTreePath();
00861                         $newNode->setAttribute( 'contentobject_is_published', 1 );
00862                         $newNode->sync();
00863                         $existingParentNodeIDs[] = $parentNodeID;
00864                         $objectIsChanged = true;
00865                     }
00866                 }
00867 
00868                 // Then ensure that the main node is correct
00869                 $currentMainParentNodeID = $contentObject->attribute( 'main_parent_node_id' );
00870                 if ( $currentMainParentNodeID != $defaultUserPlacement )
00871                 {
00872                     $existingNode = eZContentObjectTreeNode::fetchNode( $contentObjectID, $defaultUserPlacement );
00873                     if ( !is_object( $existingNode ) )
00874                     {
00875                         eZDebug::writeError( "Cannot find assigned node as $defaultUserPlacement's child.", __METHOD__ );
00876                     }
00877                     else
00878                     {
00879                         $existingNodeID = $existingNode->attribute( 'node_id' );
00880                         $versionNum = $version->attribute( 'version' );
00881                         eZContentObjectTreeNode::updateMainNodeID( $existingNodeID, $contentObjectID, $versionNum, $defaultUserPlacement );
00882                         $objectIsChanged = true;
00883                     }
00884                 }
00885 
00886                 $db->commit();
00887 
00888                 // Finally, clear object view cache if something was changed
00889                 if ( $objectIsChanged )
00890                 {
00891                     eZContentCacheManager::clearObjectViewCache( $contentObjectID, true );
00892                 }
00893             }
00894         }
00895 
00896         eZUser::updateLastVisit( $userID );
00897         //eZUser::setCurrentlyLoggedInUser( $user, $userID );
00898         // Reset number of failed login attempts
00899         eZUser::setFailedLoginAttempts( $userID, 0 );
00900         return $user;
00901     }
00902 
00903     /*
00904         Static method, for internal usage only.
00905         Note: used user group class (see 'UserGroupClassID' ini setting, in 'UserSettings' section)
00906               must have name attribute with indentifier equal 'name'
00907     */
00908     static function publishNewUserGroup( $parentNodeIDs, $newGroupAttributes, $isUtf8Encoding = false )
00909     {
00910         $thisFunctionErrorLabel = 'eZLDAPUser.php, function publishNewUserGroup()';
00911         $newNodeIDs = array();
00912 
00913         if ( !is_array( $newGroupAttributes ) or
00914              !isset( $newGroupAttributes[ 'name' ] ) or
00915              empty( $newGroupAttributes[ 'name' ] ) )
00916         {
00917             eZDebug::writeWarning( 'Cannot create user group with empty name.',
00918                                    $thisFunctionErrorLabel );
00919             return $newNodeIDs;
00920         }
00921         if ( !is_array( $parentNodeIDs ) or count( $parentNodeIDs ) < 1 )
00922         {
00923             eZDebug::writeWarning( 'No one parent node IDs was passed for publishing new group (group name = "' .
00924                                    $newGroupAttributes[ 'name' ] . '")',
00925                                    $thisFunctionErrorLabel );
00926             return $newNodeIDs;
00927         }
00928 
00929         $ini = eZINI::instance();
00930         $userGroupClassID = $ini->variable( "UserSettings", "UserGroupClassID" );
00931         $userCreatorID = $ini->variable( "UserSettings", "UserCreatorID" );
00932         $defaultSectionID = $ini->variable( "UserSettings", "DefaultSectionID" );
00933 
00934         $userGroupClass = eZContentClass::fetch( $userGroupClassID );
00935         $contentObject = $userGroupClass->instantiate( $userCreatorID, $defaultSectionID );
00936 
00937         $contentObject->store();
00938 
00939         $contentObjectID = $contentObject->attribute( 'id' );
00940 
00941         reset( $parentNodeIDs );
00942         $defaultPlacement = current( $parentNodeIDs );
00943         array_shift( $parentNodeIDs );
00944 
00945         $nodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $contentObjectID,
00946                                                            'contentobject_version' => 1,
00947                                                            'parent_node' => $defaultPlacement,
00948                                                            'is_main' => 1 ) );
00949         $nodeAssignment->setAttribute( 'parent_remote_id', uniqid( 'LDAP_' ) );
00950         $nodeAssignment->store();
00951 
00952         foreach( $parentNodeIDs as $parentNodeID )
00953         {
00954             $newNodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $contentObjectID,
00955                                                                   'contentobject_version' => 1,
00956                                                                   'parent_node' => $parentNodeID,
00957                                                                   'is_main' => 0 ) );
00958             $newNodeAssignment->setAttribute( 'parent_remote_id', uniqid( 'LDAP_' ) );
00959             $newNodeAssignment->store();
00960         }
00961 
00962         $version = $contentObject->version( 1 );
00963         $version->setAttribute( 'modified', time() );
00964         $version->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
00965         $version->store();
00966 
00967         $contentObjectAttributes = $version->contentObjectAttributes();
00968 
00969         // find ant set 'name' and 'description' attributes (as standard user group class)
00970         $nameIdentifier = 'name';
00971         $descIdentifier = 'description';
00972         $nameContentAttribute = null;
00973         $descContentAttribute = null;
00974         foreach( $contentObjectAttributes as $attribute )
00975         {
00976             if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $nameIdentifier )
00977             {
00978                 $nameContentAttribute = $attribute;
00979             }
00980             else if ( $attribute->attribute( 'contentclass_attribute_identifier' ) == $descIdentifier )
00981             {
00982                 $descContentAttribute = $attribute;
00983             }
00984         }
00985         if ( $nameContentAttribute )
00986         {
00987             if ( $isUtf8Encoding )
00988                 $newGroupAttributes[ 'name' ] = utf8_decode( $newGroupAttributes[ 'name' ] );
00989             $nameContentAttribute->setAttribute( 'data_text', $newGroupAttributes[ 'name' ] );
00990             $nameContentAttribute->store();
00991         }
00992         if ( $descContentAttribute and
00993              isset( $newGroupAttributes[ 'description' ] ) )
00994         {
00995             if ( $isUtf8Encoding )
00996                 $newGroupAttributes[ 'description' ] = utf8_decode( $newGroupAttributes[ 'description' ] );
00997             $descContentAttribute->setAttribute( 'data_text', $newGroupAttributes[ 'description' ] );
00998             $descContentAttribute->store();
00999         }
01000 
01001         //include_once( 'lib/ezutils/classes/ezoperationhandler.php' );
01002         $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
01003                                                                                      'version' => 1 ) );
01004         $newNodes = eZContentObjectTreeNode::fetchByContentObjectID( $contentObjectID, true, 1 );
01005         foreach ( $newNodes as $newNode )
01006         {
01007             $newNodeIDs[] = $newNode->attribute( 'node_id' );
01008         }
01009 
01010         return $newNodeIDs;
01011     }
01012 
01013     /*
01014         Static method, for internal usage only.
01015         Recursive, publishes groups by prepared tree of groups returned by getUserGroupsTree() method
01016     */
01017     static function goAndPublishGroups( &$requiredParams,
01018                                  $curDN,
01019                                  &$groupsTree,
01020                                  &$stack,
01021                                  $depth,
01022                                  $isUser = false )
01023     {
01024         $thisFunctionErrorLabel = 'eZLDAPUser.php, function goAndPublishGroups()';
01025         if ( !isset( $groupsTree[ $curDN ] ) )
01026         {
01027             eZDebug::writeError( 'Passed $curDN is not in result tree array.',
01028                                  $thisFunctionErrorLabel );
01029             return false;
01030         }
01031 
01032         array_push( $stack, $curDN );
01033         $current =& $groupsTree[ $curDN ];
01034 
01035         // check the name
01036         if ( $isUser )
01037         {
01038             $currentName = $current[ 'data' ][ $requiredParams[ 'LDAPLoginAttribute' ] ];
01039         }
01040         else
01041         {
01042             $currentName = $current[ 'data' ][ $requiredParams[ 'LDAPGroupNameAttribute' ] ];
01043         }
01044 
01045         if ( is_array( $currentName ) and //count( $currentName ) > 1 and
01046              isset( $currentName[ 'count' ] ) and $currentName[ 'count' ] > 0 )
01047         {
01048             $currentName = $currentName[ 0 ];
01049         }
01050 
01051         if ( empty( $currentName ) )
01052         {
01053             eZDebug::writeWarning( "Cannot create/use group with empty name (dn = $curDN)",
01054                                    $thisFunctionErrorLabel );
01055             return false;
01056         }
01057 
01058         // go through parents
01059         if ( is_array( $current['parents'] ) and count( $current['parents'] ) > 0 )
01060         {
01061             foreach( array_keys( $current['parents'] ) as $key )
01062             {
01063                 $parent =& $groupsTree[ $key ];
01064 
01065                 if ( in_array( $parent['data']['dn'], $stack ) )
01066                 {
01067                     $groupsTree[ '_recursion_detected_' ] = true;
01068                     eZDebug::writeError( 'Recursion is detected in the user-groups tree while getting parent groups for ' . $curDN,
01069                                          $thisFunctionErrorLabel );
01070                     return false;
01071                 }
01072                 if ( isset( $parent[ 'nodes' ] ) and count( $parent[ 'nodes' ] ) > 0 )
01073                 {
01074                     continue;
01075                 }
01076                 $ret = self::goAndPublishGroups( $requiredParams,
01077                                                  $parent['data']['dn'],
01078                                                  $groupsTree,
01079                                                  $stack,
01080                                                  $depth - 1 );
01081                 if ( isset( $groupsTree[ '_recursion_detected_' ] ) and $groupsTree[ '_recursion_detected_' ] )
01082                 {
01083                     return false;
01084                 }
01085             }
01086         }
01087         else
01088         {
01089             // We've reached a top node
01090             if ( !isset( $groupsTree[ 'root' ] ) )
01091             {
01092                 $groupsTree[ 'root' ] = array( 'data' => null,
01093                                                'parents' => null,
01094                                                'children' => array(),
01095                                                'nodes' => array( $requiredParams[ 'TopUserGroupNodeID' ] ) );
01096             }
01097             if ( !isset( $groupsTree[ 'root' ][ 'children' ][ $curDN ] ) )
01098                 $groupsTree[ 'root' ][ 'children' ][ $curDN ] =& $current;
01099             if ( !isset( $current[ 'parents' ][ 'root' ] ) )
01100                 $current[ 'parents' ][ 'root' ] =& $groupsTree[ 'root' ];
01101         }
01102 
01103         if ( !isset( $current[ 'nodes' ] ) )
01104             $current[ 'nodes' ] = array();
01105 
01106         $parentNodesForNew = array();
01107         foreach( array_keys( $current[ 'parents' ] ) as $key )
01108         {
01109             $parent =& $groupsTree[ $key ];
01110             if ( is_array( $parent[ 'nodes' ] ) and count( $parent[ 'nodes' ] ) > 0 )
01111             {
01112                 foreach ( $parent[ 'nodes' ] as $parentNodeID )
01113                 {
01114                     // fetch current parent node
01115                     $parentNode = eZContentObjectTreeNode::fetch( $parentNodeID );
01116                     if ( is_object( $parentNode ) )
01117                     {
01118                         $params = array( 'Depth' => 1,
01119                                          'AttributeFilter' => array( array( 'name', '=', $currentName ) ) );
01120                         $nodes = eZContentObjectTreeNode::subTreeByNodeID( $params, $parentNodeID );
01121 
01122                         if ( is_array( $nodes ) and count( $nodes ) > 0 and !$isUser )
01123                         {
01124                             // if group with given name already exist under $parentNode then get fetch
01125                             // group node and remember its ID
01126                             $node =& $nodes[ 0 ];
01127                             $nodeID = $node->attribute( 'node_id' );
01128                             $current[ 'nodes' ][] = $nodeID;
01129                         }
01130                         else
01131                         {
01132                             // if not exist then remember $parentNodeID to publish a new one
01133                             $parentNodesForNew[] = $parentNodeID;
01134                         }
01135                     }
01136                     else
01137                     {
01138                         eZDebug::writeError( 'Cannot fetch parent node for creating new user group ' . $parentNodeID,
01139                                              $thisFunctionErrorLabel );
01140                     }
01141                 }
01142             }
01143             else
01144             {
01145                 eZDebug::writeError( "Cannot get any published parent group for group/user with name = '$currentName'" .
01146                                      " (dn = '" . $current[ 'data' ]['dn'] . "')",
01147                                      $thisFunctionErrorLabel );
01148             }
01149         }
01150 
01151         if ( count( $parentNodesForNew ) > 0 )
01152         {
01153             if ( $isUser )
01154             {
01155                 $current[ 'new_parents' ] = $parentNodesForNew;
01156                 $newNodeIDs = array();
01157             }
01158             else
01159             {
01160                 $newNodeIDs = eZLDAPUser::publishNewUserGroup( $parentNodesForNew, array( 'name' => $currentName,
01161                                                                                           'description' => '' ) );
01162             }
01163             $current[ 'nodes' ] = array_merge( $current[ 'nodes' ], $newNodeIDs );
01164         }
01165 
01166         array_pop( $stack );
01167         return true;
01168     }
01169 
01170     /*
01171         Static method, for internal usage only
01172         Recursive method, which parses tree of groups from ldap server
01173     */
01174     static function getUserGroupsTree( &$requiredParams,
01175                                 $filter,
01176                                 $curDN,
01177                                 &$groupsTree,
01178                                 &$stack,            // stack for recursion checking
01179                                 $depth = 0 )
01180     {
01181         if ( $depth == 0 )
01182         {
01183             return false;
01184         }
01185         $thisFunctionErrorLabel = 'eZLDAPUser.php, function getUserGroupsTree()';
01186 
01187         if ( !isset( $requiredParams[ 'LDAPGroupBaseDN' ] ) or empty( $requiredParams[ 'LDAPGroupBaseDN' ] ) or
01188              !isset( $requiredParams[ 'LDAPGroupClass' ] ) or empty( $requiredParams[ 'LDAPGroupClass' ] ) or
01189              !isset( $requiredParams[ 'LDAPGroupNameAttribute' ] ) or empty( $requiredParams[ 'LDAPGroupNameAttribute' ] ) or
01190              !isset( $requiredParams[ 'LDAPGroupMemberAttribute' ] ) or empty( $requiredParams[ 'LDAPGroupMemberAttribute' ] ) or
01191              !isset( $requiredParams[ 'ds' ] ) or !$requiredParams[ 'ds' ] )
01192         {
01193             eZDebug::writeError( 'Missing one of required parameters.',
01194                                  $thisFunctionErrorLabel );
01195             return false;
01196         }
01197         if ( !isset( $groupsTree[ $curDN ] ) )
01198         {
01199             eZDebug::writeError( 'Passed $curDN is not in result tree array. Algorithm\'s usage error.',
01200                                  $thisFunctionErrorLabel );
01201             return false;
01202         }
01203         array_push( $stack, $curDN );
01204 
01205         $LDAPGroupBaseDN          =& $requiredParams[ 'LDAPGroupBaseDN' ];
01206         $LDAPGroupClass           =& $requiredParams[ 'LDAPGroupClass' ];
01207         $LDAPGroupNameAttribute   =& $requiredParams[ 'LDAPGroupNameAttribute' ];
01208         $LDAPGroupMemberAttribute =& $requiredParams[ 'LDAPGroupMemberAttribute' ];
01209         $LDAPGroupDescriptionAttribute =& $requiredParams[ 'LDAPGroupDescriptionAttribute' ];
01210         $ds                       =& $requiredParams[ 'ds' ];
01211 
01212         $current =& $groupsTree[ $curDN ];
01213 
01214         $retrieveAttributes = array( $LDAPGroupNameAttribute,
01215                                      $LDAPGroupMemberAttribute );
01216         $sr = ldap_search( $ds, $LDAPGroupBaseDN, $filter, $retrieveAttributes );
01217         $entries = ldap_get_entries( $ds, $sr );
01218 
01219         if ( is_array( $entries ) and
01220              isset( $entries[ 'count' ] ) and $entries[ 'count' ] > 0 )
01221         {
01222             $newfilter = '(&(objectClass=' . $LDAPGroupClass . ')';
01223 
01224             for ( $i = 0; $i < $entries[ 'count' ]; $i++ )
01225             {
01226                 $parent =& $entries[ $i ];
01227                 if ( is_null( $parent ) )
01228                    continue;
01229 
01230                 $parentDN =& $parent['dn'];
01231                 if ( in_array( $parentDN, $stack ) )
01232                 {
01233                     $requiredParams[ 'LDAPGroupNameAttribute' ];
01234 
01235                     eZDebug::writeError( 'Recursion is detected in the user-groups tree while getting parent groups for ' . $curDN,
01236                                          $thisFunctionErrorLabel );
01237                     $groupsTree[ '_recursion_detected_' ] = true;
01238                     return false;
01239                 }
01240 
01241                 if ( !isset( $groupsTree[ $parentDN ] ) )
01242                 {
01243                     $groupsTree[ $parentDN ] = array( 'data' => $parent,
01244                                                       'parents' => array(),
01245                                                       'children' => array() );
01246                 }
01247                 $groupsTree[ $parentDN ][ 'children' ][ $curDN ] =& $current;
01248                 $current[ 'parents' ][ $parentDN ] =& $groupsTree[ $parentDN ];
01249                 $newfilter1 = $newfilter . '(' . $LDAPGroupMemberAttribute . '=' . $parentDN . '))';
01250                 $ret = eZLDAPUser::getUserGroupsTree( $requiredParams,
01251                                                       $newfilter1,
01252                                                       $parentDN,
01253                                                       $groupsTree,
01254                                                       $stack,
01255                                                       $depth - 1 );
01256                 if ( isset( $groupsTree[ '_recursion_detected_' ] ) and
01257                      $groupsTree[ '_recursion_detected_' ] )
01258                 {
01259                     return false;
01260                 }
01261             }
01262         }
01263         else
01264         {
01265             // We've reached a top node
01266             if ( !isset( $groupsTree[ 'root' ] ) )
01267             {
01268                 $groupsTree[ 'root' ] = array( 'data' => null,
01269                                                'parents' => null,
01270                                                'children' => array(),
01271                                                'nodes' => array( $requiredParams[ 'TopUserGroupNodeID' ] ) );
01272             }
01273             if ( !isset( $groupsTree[ 'root' ][ 'children' ][ $curDN ] ) )
01274                 $groupsTree[ 'root' ][ 'children' ][ $curDN ] =& $current;
01275             if ( !isset( $current[ 'parents' ][ 'root' ] ) )
01276                 $current[ 'parents' ][ 'root' ] =& $groupsTree[ 'root' ];
01277         }
01278 
01279         array_pop( $stack );
01280         return true;
01281     }
01282 
01283 
01284 }
01285 
01286 ?>