added local filtering
This commit is contained in:
		
							parent
							
								
									dfc3dcb4c6
								
							
						
					
					
						commit
						e2e75ece20
					
				|  | @ -2,6 +2,7 @@ June 2018 6.4 | |||
|   - Imagick PHP extension required | ||||
|   - Passwords can be checked against external service (e.g. https://api.pwnedpasswords.com/range) | ||||
|   - Personal/Windows: image cropping support | ||||
|   - Better filtering of account lists | ||||
|   - Unix: Unix and group of names memberships can be synced in group selection | ||||
|   - IMAP: create mailbox via file upload | ||||
|   - PHP 7.2 support | ||||
|  |  | |||
|  | @ -174,7 +174,7 @@ $helpArray = array ( | |||
| 				"249" => array ("Headline" => _('External password check'), | ||||
| 					"Text" => _('Please specify the URL (e.g. "https://api.pwnedpasswords.com/range/{SHA1PREFIX}") of your external password check.')), | ||||
| 				"250" => array ("Headline" => _("Filter"), | ||||
| 					"Text" => _("Here you can input simple filter expressions (e.g. 'value' or 'v*'). The filter is case-sensitive.")), | ||||
| 					"Text" => _("Here you can input simple filter expressions (e.g. 'value' or 'v*'). The filter is case-insensitive.")), | ||||
| 				"260" => array ("Headline" => _("Additional LDAP filter"), | ||||
| 					"Text" => _('Use this to enter an additional LDAP filter (e.g. "(cn!=admin)") to reduce the number of visible elements for this account type.') | ||||
| 						. ' ' . _('You can use the wildcard @@LOGIN_DN@@ which will be substituted with the DN of the user who is currently logged in to LAM.') | ||||
|  |  | |||
|  | @ -108,8 +108,8 @@ class lamList { | |||
| 	const VIRTUAL_ATTRIBUTE_PREFIX = 'lam_virtual_'; | ||||
| 
 | ||||
| 	const SERVER_SIDE_FILTER_ATTRIBUTES = array( | ||||
| 		'cn', 'uid', 'memberuid', 'description', | ||||
| 		'sn', 'surname', 'gn', 'givenname' | ||||
| 		'cn', 'commonname', 'uid', 'memberuid', 'description', | ||||
| 		'sn', 'surname', 'gn', 'givenname', 'company', 'mail' | ||||
| 	); | ||||
| 
 | ||||
| 	/** | ||||
|  | @ -174,6 +174,8 @@ class lamList { | |||
| 		if ($this->refresh) { | ||||
| 			$this->listRefreshData(); | ||||
| 		} | ||||
| 		// local filtering
 | ||||
| 		$this->applyLocalFilters(); | ||||
| 		// sort rows by sort column
 | ||||
| 		if (isset($this->entries)) { | ||||
| 			$this->listCreateSortMapping($this->entries); | ||||
|  | @ -1033,6 +1035,55 @@ class lamList { | |||
| 		return in_array(strtolower($attrName), lamList::SERVER_SIDE_FILTER_ATTRIBUTES); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Applies any local filters for attributes that cannot be filtered server side. | ||||
| 	 */ | ||||
| 	protected function applyLocalFilters() { | ||||
| 		$this->entries = array(); | ||||
| 		foreach ($this->ldapEntries as $index => &$data) { | ||||
| 			$this->entries[$index] = &$data; | ||||
| 		} | ||||
| 		$toFilter = array(); | ||||
| 		foreach ($this->filters as $filterAttribute => $filterValue) { | ||||
| 			if ($this->isAttributeFilteredByServer($filterAttribute) || ($filterValue === '')) { | ||||
| 				continue; | ||||
| 			} | ||||
| 			foreach ($this->entries as $index => &$data) { | ||||
| 				if (in_array($index, $toFilter)) { | ||||
| 					continue; | ||||
| 				} | ||||
| 				$regex = str_replace(array('*'), array('.*'), $filterValue); | ||||
| 				$regex = '/^' . $regex . '$/i'; | ||||
| 				if (!$this->isFilterMatching($data, $filterAttribute, $regex)) { | ||||
| 					$toFilter[] = $index; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		foreach ($toFilter as $index) { | ||||
| 			unset($this->entries[$index]); | ||||
| 		} | ||||
| 		$this->entries = array_values($this->entries); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Checks if the given LDAP data matches the filter. | ||||
| 	 * | ||||
| 	 * @param array $data LDAP attributes | ||||
| 	 * @param string $filterAttribute filter attribute name | ||||
| 	 * @param string $regex filter attribute regex | ||||
| 	 */ | ||||
| 	protected function isFilterMatching(&$data, $filterAttribute, $regex) { | ||||
| 		if (!isset($data[$filterAttribute])) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		foreach ($data[$filterAttribute] as $value) { | ||||
| 			if (preg_match($regex, $value)) { | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Forces a refresh of the LDAP data. | ||||
| 	 * Function must be called before $this->refresh option is checked to load new LDAP data (e.g. in listGetParams). | ||||
|  |  | |||
|  | @ -694,7 +694,7 @@ class lamUserList extends lamList { | |||
| 		} | ||||
| 		// show account status
 | ||||
| 		if ($this->showAccountStatus) { | ||||
| 			$this->injectAccountStatusAttributeAndFilterByStatus(); | ||||
| 			$this->injectAccountStatusAttribute(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -968,7 +968,7 @@ class lamUserList extends lamList { | |||
| 	/** | ||||
| 	 * Injects values for the virtual account status attribute to make it sortable. | ||||
| 	 */ | ||||
| 	private function injectAccountStatusAttributeAndFilterByStatus() { | ||||
| 	private function injectAccountStatusAttribute() { | ||||
| 		$entryCount = sizeof($this->ldapEntries); | ||||
| 		for ($i = 0; $i < $entryCount; $i++) { | ||||
| 			$unixAvailable = self::isUnixAvailable($this->ldapEntries[$i]); | ||||
|  | @ -1007,17 +1007,29 @@ class lamUserList extends lamList { | |||
| 			elseif (!$hasUnlocked && $hasLocked) { | ||||
| 				$status = self::FILTER_LOCKED; | ||||
| 			} | ||||
| 			// filter accounts
 | ||||
| 			if (!empty($this->accountStatusFilter)) { | ||||
| 				if ($status != $this->accountStatusFilter) { | ||||
| 					unset($this->ldapEntries[$i]); | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
| 			// add virtual attribute
 | ||||
| 			$this->ldapEntries[$i][self::ATTR_ACCOUNT_STATUS][0] = $status; | ||||
| 		} | ||||
| 		$this->ldapEntries = array_values($this->ldapEntries); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * {@inheritDoc} | ||||
| 	 * @see lamList::isFilterMatching() | ||||
| 	 */ | ||||
| 	protected function isFilterMatching(&$data, $filterAttribute, $regex) { | ||||
| 		if ($filterAttribute == self::ATTR_ACCOUNT_STATUS) { | ||||
| 			return preg_match($regex, $data[self::ATTR_ACCOUNT_STATUS][0]); | ||||
| 		} | ||||
| 		if (($filterAttribute == 'gidnumber') && ($this->trans_primary == "on")) { | ||||
| 			if (!isset($data[$filterAttribute])) { | ||||
| 				return false; | ||||
| 			} | ||||
| 			if (!isset($this->trans_primary_hash[$data[$filterAttribute][0]])) { | ||||
| 				return false; | ||||
| 			} | ||||
| 			return preg_match($regex, $this->trans_primary_hash[$data[$filterAttribute][0]]); | ||||
| 		} | ||||
| 		return parent::isFilterMatching($data, $filterAttribute, $regex); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue