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