Blame view

sources/apps/user_ldap/group_ldap.php 10.2 KB
03e52840d   Kload   Init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  <?php
  
  /**
   * ownCloud – LDAP group backend
   *
   * @author Arthur Schiwon
   * @copyright 2012 Arthur Schiwon blizzz@owncloud.com
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
   * License as published by the Free Software Foundation; either
   * version 3 of the License, or any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
   *
   * You should have received a copy of the GNU Affero General Public
   * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  namespace OCA\user_ldap;
31b7f2792   Kload   Upgrade to ownclo...
25
26
27
28
  use OCA\user_ldap\lib\Access;
  use OCA\user_ldap\lib\BackendUtility;
  
  class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
03e52840d   Kload   Init
29
  	protected $enabled = false;
31b7f2792   Kload   Upgrade to ownclo...
30
31
32
33
  	public function __construct(Access $access) {
  		parent::__construct($access);
  		$filter = $this->access->connection->ldapGroupFilter;
  		$gassoc = $this->access->connection->ldapGroupMemberAssocAttr;
03e52840d   Kload   Init
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  		if(!empty($filter) && !empty($gassoc)) {
  			$this->enabled = true;
  		}
  	}
  
  	/**
  	 * @brief is user in group?
  	 * @param $uid uid of the user
  	 * @param $gid gid of the group
  	 * @returns true/false
  	 *
  	 * Checks whether the user is member of a group or not.
  	 */
  	public function inGroup($uid, $gid) {
  		if(!$this->enabled) {
  			return false;
  		}
31b7f2792   Kload   Upgrade to ownclo...
51
52
  		if($this->access->connection->isCached('inGroup'.$uid.':'.$gid)) {
  			return $this->access->connection->getFromCache('inGroup'.$uid.':'.$gid);
03e52840d   Kload   Init
53
  		}
31b7f2792   Kload   Upgrade to ownclo...
54
55
  		$dn_user = $this->access->username2dn($uid);
  		$dn_group = $this->access->groupname2dn($gid);
03e52840d   Kload   Init
56
57
  		// just in case
  		if(!$dn_group || !$dn_user) {
31b7f2792   Kload   Upgrade to ownclo...
58
  			$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
03e52840d   Kload   Init
59
60
61
  			return false;
  		}
  		//usually, LDAP attributes are said to be case insensitive. But there are exceptions of course.
31b7f2792   Kload   Upgrade to ownclo...
62
63
  		$members = $this->access->readAttribute($dn_group,
  						$this->access->connection->ldapGroupMemberAssocAttr);
03e52840d   Kload   Init
64
  		if(!$members) {
31b7f2792   Kload   Upgrade to ownclo...
65
  			$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, false);
03e52840d   Kload   Init
66
67
68
69
70
  			return false;
  		}
  
  		//extra work if we don't get back user DNs
  		//TODO: this can be done with one LDAP query
31b7f2792   Kload   Upgrade to ownclo...
71
  		if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
03e52840d   Kload   Init
72
73
  			$dns = array();
  			foreach($members as $mid) {
31b7f2792   Kload   Upgrade to ownclo...
74
75
  				$filter = str_replace('%uid', $mid, $this->access->connection->ldapLoginFilter);
  				$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
03e52840d   Kload   Init
76
77
78
79
80
81
82
83
84
  				if(count($ldap_users) < 1) {
  					continue;
  				}
  				$dns[] = $ldap_users[0];
  			}
  			$members = $dns;
  		}
  
  		$isInGroup = in_array($dn_user, $members);
31b7f2792   Kload   Upgrade to ownclo...
85
  		$this->access->connection->writeToCache('inGroup'.$uid.':'.$gid, $isInGroup);
03e52840d   Kload   Init
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  
  		return $isInGroup;
  	}
  
  	/**
  	 * @brief Get all groups a user belongs to
  	 * @param $uid Name of the user
  	 * @returns array with group names
  	 *
  	 * This function fetches all groups a user belongs to. It does not check
  	 * if the user exists at all.
  	 */
  	public function getUserGroups($uid) {
  		if(!$this->enabled) {
  			return array();
  		}
  		$cacheKey = 'getUserGroups'.$uid;
31b7f2792   Kload   Upgrade to ownclo...
103
104
  		if($this->access->connection->isCached($cacheKey)) {
  			return $this->access->connection->getFromCache($cacheKey);
03e52840d   Kload   Init
105
  		}
31b7f2792   Kload   Upgrade to ownclo...
106
  		$userDN = $this->access->username2dn($uid);
03e52840d   Kload   Init
107
  		if(!$userDN) {
31b7f2792   Kload   Upgrade to ownclo...
108
  			$this->access->connection->writeToCache($cacheKey, array());
03e52840d   Kload   Init
109
110
111
112
  			return array();
  		}
  
  		//uniqueMember takes DN, memberuid the uid, so we need to distinguish
31b7f2792   Kload   Upgrade to ownclo...
113
114
  		if((strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'uniquemember')
  			|| (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'member')
03e52840d   Kload   Init
115
116
  		) {
  			$uid = $userDN;
31b7f2792   Kload   Upgrade to ownclo...
117
118
  		} else if(strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid') {
  			$result = $this->access->readAttribute($userDN, 'uid');
03e52840d   Kload   Init
119
120
121
122
123
  			$uid = $result[0];
  		} else {
  			// just in case
  			$uid = $userDN;
  		}
31b7f2792   Kload   Upgrade to ownclo...
124
125
126
  		$filter = $this->access->combineFilterWithAnd(array(
  			$this->access->connection->ldapGroupFilter,
  			$this->access->connection->ldapGroupMemberAssocAttr.'='.$uid
03e52840d   Kload   Init
127
  		));
31b7f2792   Kload   Upgrade to ownclo...
128
129
130
131
  		$groups = $this->access->fetchListOfGroups($filter,
  				array($this->access->connection->ldapGroupDisplayName, 'dn'));
  		$groups = array_unique($this->access->ownCloudGroupNames($groups), SORT_LOCALE_STRING);
  		$this->access->connection->writeToCache($cacheKey, $groups);
03e52840d   Kload   Init
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  
  		return $groups;
  	}
  
  	/**
  	 * @brief get a list of all users in a group
  	 * @returns array with user ids
  	 */
  	public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
  		if(!$this->enabled) {
  			return array();
  		}
  		if(!$this->groupExists($gid)) {
  			return array();
  		}
  		$cachekey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
  		// check for cache of the exact query
31b7f2792   Kload   Upgrade to ownclo...
149
  		$groupUsers = $this->access->connection->getFromCache($cachekey);
03e52840d   Kload   Init
150
151
152
153
154
  		if(!is_null($groupUsers)) {
  			return $groupUsers;
  		}
  
  		// check for cache of the query without limit and offset
31b7f2792   Kload   Upgrade to ownclo...
155
  		$groupUsers = $this->access->connection->getFromCache('usersInGroup-'.$gid.'-'.$search);
03e52840d   Kload   Init
156
157
  		if(!is_null($groupUsers)) {
  			$groupUsers = array_slice($groupUsers, $offset, $limit);
31b7f2792   Kload   Upgrade to ownclo...
158
  			$this->access->connection->writeToCache($cachekey, $groupUsers);
03e52840d   Kload   Init
159
160
  			return $groupUsers;
  		}
31b7f2792   Kload   Upgrade to ownclo...
161
  		if($limit === -1) {
03e52840d   Kload   Init
162
163
  			$limit = null;
  		}
31b7f2792   Kload   Upgrade to ownclo...
164
  		$groupDN = $this->access->groupname2dn($gid);
03e52840d   Kload   Init
165
166
  		if(!$groupDN) {
  			// group couldn't be found, return empty resultset
31b7f2792   Kload   Upgrade to ownclo...
167
  			$this->access->connection->writeToCache($cachekey, array());
03e52840d   Kload   Init
168
169
  			return array();
  		}
31b7f2792   Kload   Upgrade to ownclo...
170
171
  		$members = $this->access->readAttribute($groupDN,
  						$this->access->connection->ldapGroupMemberAssocAttr);
03e52840d   Kload   Init
172
173
  		if(!$members) {
  			//in case users could not be retrieved, return empty resultset
31b7f2792   Kload   Upgrade to ownclo...
174
  			$this->access->connection->writeToCache($cachekey, array());
03e52840d   Kload   Init
175
176
177
178
  			return array();
  		}
  
  		$groupUsers = array();
31b7f2792   Kload   Upgrade to ownclo...
179
  		$isMemberUid = (strtolower($this->access->connection->ldapGroupMemberAssocAttr) === 'memberuid');
03e52840d   Kload   Init
180
181
182
  		foreach($members as $member) {
  			if($isMemberUid) {
  				//we got uids, need to get their DNs to 'tranlsate' them to usernames
31b7f2792   Kload   Upgrade to ownclo...
183
  				$filter = $this->access->combineFilterWithAnd(array(
03e52840d   Kload   Init
184
  					\OCP\Util::mb_str_replace('%uid', $member,
31b7f2792   Kload   Upgrade to ownclo...
185
186
  						$this->access->connection->ldapLoginFilter, 'UTF-8'),
  					$this->access->getFilterPartForUserSearch($search)
03e52840d   Kload   Init
187
  				));
31b7f2792   Kload   Upgrade to ownclo...
188
  				$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
03e52840d   Kload   Init
189
190
191
  				if(count($ldap_users) < 1) {
  					continue;
  				}
31b7f2792   Kload   Upgrade to ownclo...
192
  				$groupUsers[] = $this->access->dn2username($ldap_users[0]);
03e52840d   Kload   Init
193
194
195
  			} else {
  				//we got DNs, check if we need to filter by search or we can give back all of them
  				if(!empty($search)) {
31b7f2792   Kload   Upgrade to ownclo...
196
197
198
  					if(!$this->access->readAttribute($member,
  						$this->access->connection->ldapUserDisplayName,
  						$this->access->getFilterPartForUserSearch($search))) {
03e52840d   Kload   Init
199
200
201
202
  						continue;
  					}
  				}
  				// dn2username will also check if the users belong to the allowed base
31b7f2792   Kload   Upgrade to ownclo...
203
  				if($ocname = $this->access->dn2username($member)) {
03e52840d   Kload   Init
204
205
206
207
208
  					$groupUsers[] = $ocname;
  				}
  			}
  		}
  		natsort($groupUsers);
31b7f2792   Kload   Upgrade to ownclo...
209
  		$this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
03e52840d   Kload   Init
210
  		$groupUsers = array_slice($groupUsers, $offset, $limit);
31b7f2792   Kload   Upgrade to ownclo...
211
  		$this->access->connection->writeToCache($cachekey, $groupUsers);
03e52840d   Kload   Init
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  
  		return $groupUsers;
  	}
  
  	/**
  	 * @brief get a list of all display names in a group
  	 * @returns array with display names (value) and user ids(key)
  	 */
  	public function displayNamesInGroup($gid, $search, $limit, $offset) {
  		if(!$this->enabled) {
  			return array();
  		}
  		if(!$this->groupExists($gid)) {
  			return array();
  		}
  		$users = $this->usersInGroup($gid, $search, $limit, $offset);
  		$displayNames = array();
  		foreach($users as $user) {
  			$displayNames[$user] = \OC_User::getDisplayName($user);
  		}
  		return $displayNames;
  	}
  
  	/**
  	 * @brief get a list of all groups
  	 * @returns array with group names
  	 *
  	 * Returns a list with all groups
  	 */
  	public function getGroups($search = '', $limit = -1, $offset = 0) {
  		if(!$this->enabled) {
  			return array();
  		}
  		$cachekey = 'getGroups-'.$search.'-'.$limit.'-'.$offset;
  
  		//Check cache before driving unnecessary searches
  		\OCP\Util::writeLog('user_ldap', 'getGroups '.$cachekey, \OCP\Util::DEBUG);
31b7f2792   Kload   Upgrade to ownclo...
249
  		$ldap_groups = $this->access->connection->getFromCache($cachekey);
03e52840d   Kload   Init
250
251
252
253
254
255
256
257
258
  		if(!is_null($ldap_groups)) {
  			return $ldap_groups;
  		}
  
  		// if we'd pass -1 to LDAP search, we'd end up in a Protocol
  		// error. With a limit of 0, we get 0 results. So we pass null.
  		if($limit <= 0) {
  			$limit = null;
  		}
31b7f2792   Kload   Upgrade to ownclo...
259
260
261
  		$filter = $this->access->combineFilterWithAnd(array(
  			$this->access->connection->ldapGroupFilter,
  			$this->access->getFilterPartForGroupSearch($search)
03e52840d   Kload   Init
262
263
  		));
  		\OCP\Util::writeLog('user_ldap', 'getGroups Filter '.$filter, \OCP\Util::DEBUG);
31b7f2792   Kload   Upgrade to ownclo...
264
265
266
267
268
  		$ldap_groups = $this->access->fetchListOfGroups($filter,
  				array($this->access->connection->ldapGroupDisplayName, 'dn'),
  				$limit,
  				$offset);
  		$ldap_groups = $this->access->ownCloudGroupNames($ldap_groups);
03e52840d   Kload   Init
269

31b7f2792   Kload   Upgrade to ownclo...
270
  		$this->access->connection->writeToCache($cachekey, $ldap_groups);
03e52840d   Kload   Init
271
272
273
274
275
276
277
278
279
280
281
282
283
  		return $ldap_groups;
  	}
  
  	public function groupMatchesFilter($group) {
  		return (strripos($group, $this->groupSearch) !== false);
  	}
  
  	/**
  	 * check if a group exists
  	 * @param string $gid
  	 * @return bool
  	 */
  	public function groupExists($gid) {
31b7f2792   Kload   Upgrade to ownclo...
284
285
  		if($this->access->connection->isCached('groupExists'.$gid)) {
  			return $this->access->connection->getFromCache('groupExists'.$gid);
03e52840d   Kload   Init
286
  		}
31b7f2792   Kload   Upgrade to ownclo...
287
288
289
  		//getting dn, if false the group does not exist. If dn, it may be mapped
  		//only, requires more checking.
  		$dn = $this->access->groupname2dn($gid);
03e52840d   Kload   Init
290
  		if(!$dn) {
31b7f2792   Kload   Upgrade to ownclo...
291
  			$this->access->connection->writeToCache('groupExists'.$gid, false);
03e52840d   Kload   Init
292
293
294
295
  			return false;
  		}
  
  		//if group really still exists, we will be able to read its objectclass
31b7f2792   Kload   Upgrade to ownclo...
296
  		$objcs = $this->access->readAttribute($dn, 'objectclass');
03e52840d   Kload   Init
297
  		if(!$objcs || empty($objcs)) {
31b7f2792   Kload   Upgrade to ownclo...
298
  			$this->access->connection->writeToCache('groupExists'.$gid, false);
03e52840d   Kload   Init
299
300
  			return false;
  		}
31b7f2792   Kload   Upgrade to ownclo...
301
  		$this->access->connection->writeToCache('groupExists'.$gid, true);
03e52840d   Kload   Init
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  		return true;
  	}
  
  	/**
  	* @brief Check if backend implements actions
  	* @param $actions bitwise-or'ed actions
  	* @returns boolean
  	*
  	* Returns the supported actions as int to be
  	* compared with OC_USER_BACKEND_CREATE_USER etc.
  	*/
  	public function implementsActions($actions) {
  		return (bool)(OC_GROUP_BACKEND_GET_DISPLAYNAME	& $actions);
  	}
  }