Просмотр исходного кода

Fix Sync Users: cleanup user uid's from groups, dont update blocked users

Piotr Labudda 10 лет назад
Родитель
Сommit
0dfd4bfe21

+ 28 - 4
SE/se-lib/ObjectGroup.php

@@ -20,17 +20,41 @@ class ObjectGroup {
 	public $zasobID;// (optional)
 	public $zasobDESC;// (optional)
 
-	protected $_storage;
+	protected $_storageName;
 
-	public function __construct($storage) {
-		$this->_storage = $storage;
+	public function __construct($storageName) {
+		// TODO: only storage name (clientType) 'DB', 'MacOSX'
+		//  $usrStorageDB = UserStorageFactory::getStorage('DB');
+		//  $usrStorageLdap = UserStorageFactory::getStorage('MacOSX');
+
+		$this->_storageName = $storageName;
 	}
 
 	public function getParentGroups() {
 		if (null === $this->parentGroups) {
-			$this->parentGroups = $this->_storage->getParentGroups($this);
+			$this->parentGroups = $this->getStorage()->getParentGroups($this);
 		}
 		return $this->parentGroups;
 	}
 
+	public function getStorage() {
+		$storage = UserStorageFactory::getStorage($this->_storageName);
+		if (!$storage) {
+			throw new Exception("Storage '{$this->_storageName}' not exists!");
+		}
+		return $storage;
+	}
+
+	public function exportData() {
+		$data = new stdClass();
+		$data->primaryKey = $this->primaryKey;
+		$data->realName = $this->realName;
+		$data->type = $this->type;
+		$data->nestedGroups = $this->nestedGroups;
+		$data->parentGroups = $this->parentGroups;
+		$data->zasobID = $this->zasobID;
+		$data->zasobDESC = $this->zasobDESC;
+		return $data;
+	}
+
 }

+ 15 - 0
SE/se-lib/ObjectUser.php

@@ -19,4 +19,19 @@ class ObjectUser {
 		$this->_storage = $storage;
 	}
 
+	public function exportData() {
+		$data = new stdClass();
+		$data->primaryKey = $this->primaryKey;
+		$data->login = $this->login;
+		$data->password = $this->password;
+		$data->name = $this->name;
+		$data->email = $this->email;
+		$data->phone = $this->phone;
+		$data->homeEmail = $this->homeEmail;
+		$data->homePhone = $this->homePhone;
+		$data->employeeType = $this->employeeType;
+		$data->isDisabled = $this->isDisabled;
+		return $data;
+	}
+
 }

+ 68 - 10
SE/se-lib/SyncUsers.php

@@ -39,7 +39,7 @@ class SyncUsers {
 			if (!$usrTo) throw new Exception("Nie udało się utworzyć użytkownika '{$usrLogin}' w bazie LDAP");
 			$this->syncExistingUser($usrLogin, $usrFrom, $usrTo);
 		}
-		else {// $usrFrom && $usrTo
+		else if (true !== $usrFromDisabled) {
 			$this->syncExistingUser($usrLogin, $usrFrom, $usrTo);
 		}
 
@@ -76,16 +76,31 @@ class SyncUsers {
 					}
 				}
 			}
+		}
 
-			if ($this->hasErrors()) {
-				return false;
+		{// clean up members by apple-generateduid
+			$groupsTo = $this->_toStorage->getGroupsByUserUid($usrLogin);
+			$groupsTodo = $this->getCleanupSyncUserGroupsByUidTodoList($usrLogin);
+			DBG::_('DBG_SU', '>0', "groupsTodo Cleanup member uid's usrFromDisabeld(" . (($usrFromDisabled)? 'true' : 'false') . ")", $groupsTodo, __CLASS__, __FUNCTION__, __LINE__);
+
+			if (!empty($groupsTodo)) {
+				foreach ($groupsTodo as $kGroupID => $vBool) {
+					if ($vBool) {
+						//$syncTodoList[] = "Dodaj '{$usrLogin}' do grupy {$kGroupID}";
+					}
+					else {
+						$this->_toStorage->removeUserUidFromGroup($usrLogin, $groupsTo[$kGroupID]);
+					}
+				}
 			}
-			return true;
 		}
 
 		$this->_fromStorage->setSyncUserDate($usrLogin);
 		$this->_toStorage->setSyncUserDate($usrLogin);
 
+		if ($this->hasErrors()) {
+			return false;
+		}
 		return true;
 	}
 
@@ -119,8 +134,8 @@ class SyncUsers {
 		$syncTodoList = array();
 		$usrFrom = $this->_fromStorage->getUser($usrLogin);
 		$usrTo = $this->_toStorage->getUser($usrLogin);
-		DBG::_('DBG_SU', true, 'usrFrom', $usrFrom, __CLASS__, __FUNCTION__, __LINE__);
-		DBG::_('DBG_SU', true, 'usrTo', $usrTo, __CLASS__, __FUNCTION__, __LINE__);
+		DBG::_('DBG_SU', true, 'usrFrom', ($usrFrom)? $usrFrom->exportData() : null, __CLASS__, __FUNCTION__, __LINE__);
+		DBG::_('DBG_SU', true, 'usrTo', ($usrTo)? $usrTo->exportData() : null, __CLASS__, __FUNCTION__, __LINE__);
 
 		if (!$usrFrom) {
 			$syncTodoList[] = "Użytkownik {$usrLogin} nie istnieje w bazie danych";
@@ -136,8 +151,8 @@ class SyncUsers {
 			$syncDisabled = false;
 			$syncTodoList[] = "Utwórz użytkownika '{$usrLogin}' w bazie LDAP";
 		}
-		else {// $usrFrom && $usrTo
-
+		else if (true !== $usrFromDisabled) {
+			//throw new Exception("Użytkownik '{$usrLogin}' jest zablokowany bazie danych, więc nie ma potrzeby aktualizacji jego danych w bazie LDAP.");
 			$updateData = array();
 			if ($usrFrom->name != $usrTo->name) $updateData['name'] = $usrFrom->name;
 			if ($usrFrom->email != $usrTo->email) $updateData['email'] = $usrFrom->email;
@@ -152,8 +167,8 @@ class SyncUsers {
 			}
 		}
 
-		$usrToDisabeld = $this->_toStorage->isDisabled($usrTo);
-		if ($syncDisabled) {
+		if ($syncDisabled && $usrTo && $usrFrom) {
+			$usrToDisabeld = $this->_toStorage->isDisabled($usrTo);
 
 			if ($usrFromDisabled === null || $usrToDisabeld === null) {
 				$syncTodoList[] = "Status blokady '{$usrLogin}' nieznany w bazie danych lub LDAP";
@@ -180,6 +195,22 @@ class SyncUsers {
 				}
 			}
 		}
+
+		{// clean up members by apple-generateduid
+			$groupsTodo = $this->getCleanupSyncUserGroupsByUidTodoList($usrLogin);
+			DBG::_('DBG_SU', '>0', "groupsTodo Cleanup member uid's usrFromDisabeld(" . (($usrFromDisabled)? 'true' : 'false') . ")", $groupsTodo, __CLASS__, __FUNCTION__, __LINE__);
+
+			if (!empty($groupsTodo)) {
+				foreach ($groupsTodo as $kGroupID => $vBool) {
+					if ($vBool) {
+						//$syncTodoList[] = "Dodaj '{$usrLogin}' do grupy {$kGroupID}";
+					}
+					else {
+						$syncTodoList[] = "Usuń `uid` usera '{$usrLogin}' z grupy {$kGroupID}";
+					}
+				}
+			}
+		}
 		return $syncTodoList;
 	}
 
@@ -212,6 +243,33 @@ class SyncUsers {
 		return $groupsTodo;
 	}
 
+	public function getCleanupSyncUserGroupsByUidTodoList($usrLogin) {
+		$groupsTodo = array();// `guid` => true (add), false (remove)
+		$groupsTo = $this->_toStorage->getGroupsByUserUid($usrLogin);
+		DBG::_('DBG_SU', '>0', "CleanupAppleMemberUidTodoList user groups by apple-generateduid({$usrAppleUid})", $userGroupsLdap, __CLASS__, __FUNCTION__, __LINE__);
+
+		$usrFrom = $this->_fromStorage->getUser($usrLogin);
+		$usrFromDisabled = $this->_fromStorage->isDisabled($usrFrom);
+		$groupsFrom = $this->_fromStorage->getUserGroups($usrLogin);
+		foreach ($groupsTo as $kUid => $vName) {
+			$groupsTodo[$kUid] = false;
+		}
+
+		if (true === $usrFromDisabled) {
+			// remove all groups
+		} else {
+			foreach ($groupsFrom as $kUid => $vGroup) {
+				if (isset($groupsTodo[$kUid])) {
+					unset($groupsTodo[$kUid]);
+				} else {
+					$groupsTodo[$kUid] = true;
+				}
+			}
+		}
+		DBG::_('DBG_SU', '>0', "CleanupAppleMemberUidTodoList groupsTodo apple-generateduid({$usrAppleUid})", $groupsTodo, __CLASS__, __FUNCTION__, __LINE__);
+		return $groupsTodo;
+	}
+
 	public function getSyncGroupTodoList($idGroup, $syncNestedGroups = false) {
 		$syncTodoList = array();
 		$groupFrom = $this->_fromStorage->getGroup($idGroup);

+ 1 - 1
SE/se-lib/UserStorageDB.php

@@ -396,7 +396,7 @@ class UserStorageDB extends UserStorageBase {
 	 * Example: _buildGroupFromRow($r) => {@see group}
 	 */
 	private function _buildGroupFromRow($groupDB, $fetchNested = false) {
-		$group = new ObjectGroupDB($this);
+		$group = new ObjectGroupDB('DB');
 		$group->primaryKey = $groupDB->ID;
 		$group->type = $groupDB->TYPE;
 		$group->realName = $this->_buildRealNameFromZasob($groupDB);

+ 49 - 3
SE/se-lib/UserStorageMacOSX.php

@@ -96,6 +96,7 @@ class UserStorageMacOSX extends UserStorageBase {
 	 * @return bool
 	 */
 	public function isDisabled($usr) {
+		if (!$usr) throw new Exception("Błąd podczas sprawdzania statusu blokady - nie podano użytkownika!");
 		if (null === $usr->isDisabled) {
 			$allGroups = $this->_fetchAllUserGroups($usr->login);
 			$usr->isDisabled = in_array('com.apple.access_disabled', $allGroups);
@@ -326,8 +327,8 @@ class UserStorageMacOSX extends UserStorageBase {
 			}
 		}
 
-		DBG::_('DBG_SU', '>2', "groupsNetwork", $groupsNetwork, __CLASS__, __FUNCTION__, __LINE__);
-		DBG::_('DBG_SU', '>2', "groupsLocal", $groupsLocal, __CLASS__, __FUNCTION__, __LINE__);
+		DBG::_('DBG_SU', '>2', "groupsNetwork", array_keys($groupsNetwork), __CLASS__, __FUNCTION__, __LINE__);
+		DBG::_('DBG_SU', '>2', "groupsLocal", array_keys($groupsLocal), __CLASS__, __FUNCTION__, __LINE__);
 		return $groups;
 	}
 
@@ -340,7 +341,7 @@ class UserStorageMacOSX extends UserStorageBase {
 	 * Example: _buildGroupFromLdap($groupLdap) => {@see getGroup}
 	 */
 	private function _buildGroupFromLdap($groupLdap, $fetchNested = false) {
-		$group = new ObjectGroupLdap($this);
+		$group = new ObjectGroupLdap('MacOSX');
 		$group->primaryKey = $groupLdap->cn;
 		$group->realName = V::get('realName', '', $groupLdap);
 		$group->zasobID = $this->_getGroupIdFromUid($groupLdap->cn);
@@ -353,6 +354,24 @@ class UserStorageMacOSX extends UserStorageBase {
 		return $group;
 	}
 
+	public function getGroupsByUserUid($usrLogin) {
+		$groups = array();
+		$rawUsrLdap = UsersLdapHelper::getUser($usrLogin, true);
+		$rawUsrLdap = (!empty($rawUsrLdap))? $rawUsrLdap[0] : null;
+		if (!$rawUsrLdap) return $groups;
+		$usrAppleUid = V::get('apple-generateduid', '', $rawUsrLdap);
+		DBG::_('DBG_SU', '>0', "CleanupAppleMemberUidTodoList user apple-generateduid({$usrAppleUid})", $rawUsrLdap, __CLASS__, __FUNCTION__, __LINE__);
+		if (empty($usrAppleUid)) return $groups;
+		$groupsLdap = UsersLdapHelper::getUserGroupsByAppleUid($usrAppleUid, 0);
+		foreach ($groupsLdap as $groupLdap) {
+			$group = $this->_buildGroupFromLdap($groupLdap);
+			if ($group->zasobID > 0) {
+				$groups[$group->zasobID] = $group;
+			}
+		}
+		return $groups;
+	}
+
 	private function _fetchNestedGroupsByAppleUids($appleUids) {
 		$groups = array();
 		if (!is_array($appleUids)) $appleUids = array($appleUids);
@@ -690,6 +709,19 @@ class UserStorageMacOSX extends UserStorageBase {
 		}
 	}
 
+	private function _removeUserUidFromGroupNetwork($usrAppleUid, $group) {
+		if (!$group || empty($group->primaryKey) || empty($usrAppleUid)) return false;
+		$groupUid = $group->primaryKey;
+		$cmdDsclAuth = "dscl -u {$this->_rootUser} -P {$this->_rootPass} /LDAPv3/127.0.0.1 ";
+		$cmd = "{$cmdDsclAuth} -delete /Groups/{$groupUid} GroupMembers {$usrAppleUid} ";
+		$cmdOut = null; $cmdRet = null;
+		exec($cmd, $cmdOut, $cmdRet);
+		DBG::_('DBG_SU', '>1', "cmd({$cmd}) ret({$cmdRet})", $cmdOut, __CLASS__, __FUNCTION__, __LINE__);
+		if ($cmdRet != 0) {
+			throw new Exception("Nie udało się usunąć uid '{$usrAppleUid}' z grupy sieciowej '{$groupUid}'");
+		}
+	}
+
 	/**
 	 * Add group member.
 	 * 
@@ -721,6 +753,20 @@ class UserStorageMacOSX extends UserStorageBase {
 		}
 	}
 
+	public function removeUserUidFromGroup($usrLogin, $group) {
+		$rawUsrLdap = UsersLdapHelper::getUser($usrLogin, true);
+		$rawUsrLdap = (!empty($rawUsrLdap))? $rawUsrLdap[0] : null;
+		if (!$rawUsrLdap) throw new Exception("Cannot find user '{$usrLogin}'");
+		$usrAppleUid = V::get('apple-generateduid', '', $rawUsrLdap);
+		if (empty($usrAppleUid)) throw new Exception("Cannot find uid for user '{$usrLogin}'");
+		DBG::_('DBG_SU', '>0', "CleanupAppleMemberUidTodoList user apple-generateduid({$usrAppleUid})", $group, __CLASS__, __FUNCTION__, __LINE__);
+		if ($group->type == 'local') {
+			//return $this->_removeUserGroupLocal($usrLogin, $group);
+		} else {
+			return $this->_removeUserUidFromGroupNetwork($usrAppleUid, $group);
+		}
+	}
+
 	public function addNestedGroup($groupID, $nestedGroupID) {
 		if ($groupID <= 0) return false;
 		if ($nestedGroupID <= 0) return false;

+ 71 - 0
SE/se-lib/UsersLdapHelper.php

@@ -162,6 +162,77 @@ class UsersLdapHelper {
 		return $userLdapGroups;
 	}
 
+	public static function getUserGroupsByAppleUid($userUid, $authLDAPSubGroupDepth = 3) {
+		$userLdapGroups = array();
+
+		$attrMap = array('apple-generateduid'=>'appleUID', 'gidNumber'=>'gidNumber', 'cn'=>'cn');// (givenName, sn) = cn
+
+		Lib::loadClass('LDAP');
+		$ldap = LDAP::getInstance();
+
+		$lastLoopFound = array();
+		for ($i = 0; $i <= $authLDAPSubGroupDepth; $i++) {
+			$userLdapGroupsAdd = array();
+
+			if ($i == 0) {
+				$filter = "(&(objectClass=apple-group)(apple-group-memberguid={$userUid}))";
+			} else {
+				$queryOrArr = array();
+				foreach ($lastLoopFound as $vAppleUid) {
+					$queryOrArr[] = "apple-group-nestedgroup={$vAppleUid}";
+				}
+				if (!empty($queryOrArr)) {
+					$queryOr = '(|(' . implode(')(', $queryOrArr) . '))';
+					$filter = "(&(objectClass=apple-group){$queryOr})";
+				} else {
+					break;
+				}
+			}
+
+			//if($DBG){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">ldap_search (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array('ldaprdn'=>'cn=groups,' . $ldap->getBaseDN(), 'filter'=>$filter, 'attributes'=>$attributes));echo'</pre>';}
+
+			$attributes = array();
+			$res = $ldap->search($filter, 'cn=groups', $attributes);
+			if(V::get('DBG_L', '', $_GET) > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">search(' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($filter);echo'</pre>';}
+			$entry = $ldap->first_entry($res);
+			while ($entry) {
+				$attrs = $ldap->get_attributes($entry);
+				if(V::get('DBG_L', '', $_GET) > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">user('.$userUid.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($attrs);echo'</pre>';}
+
+				$groupObj = new stdClass();
+				foreach ($attrMap as $kAttrName => $vField) {
+					$vAttrVal = V::get($kAttrName, '', $attrs);
+					if (is_array($vAttrVal) && !empty($vAttrVal)) {
+						$groupObj->{$vField} = $vAttrVal[0];
+					}
+				}
+
+				if ($groupObj->cn && $groupObj->gidNumber) {
+					$userLdapGroupsAdd[$groupObj->gidNumber] = $groupObj;
+				} else {
+					echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Error: brak cn lub apple-generateduid (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($attrs);echo'</pre>';
+				}
+
+				$entry = $ldap->next_entry($entry);
+			}
+			$ldap->free_result($res);
+
+			if (empty($userLdapGroupsAdd)) {
+				break;
+			} else {
+				if(V::get('DBG_L', '', $_GET) > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">userLdapGroupsAdd('.count($userLdapGroupsAdd).') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($userLdapGroupsAdd);echo'</pre>';}
+				$lastLoopFound = array();
+				foreach ($userLdapGroupsAdd as $kAppleID => $vGroup) {
+					$userLdapGroups[$kAppleID] = $vGroup;
+					$lastLoopFound[] = $vGroup->appleUID;
+				}
+				//$lastLoopFound = array_keys($userLdapGroupsAdd);
+			}
+		}
+
+		return $userLdapGroups;
+	}
+
 	public static function getGroupsByAppleUids($appleUids, $allAttrs = false) {
 		$allLdapGroups = array();
 		if (empty($appleUids)) return $allLdapGroups;