Merge branch '2013.10' into 2014.11
[tine20] / tine20 / Tinebase / Group / ActiveDirectory.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  Group
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Lars Kneschke <l.kneschke@metaways.de>
10  */
11
12 /**
13  * Group ldap backend
14  * 
15  * @package     Tinebase
16  * @subpackage  Group
17  */
18 class Tinebase_Group_ActiveDirectory extends Tinebase_Group_Ldap
19 {
20     /**
21      * the ldap backend
22      *
23      * @var Tinebase_Ldap
24      */
25     protected $_ldap;
26     
27     /**
28      * ldap config options
29      *
30      * @var array
31      */
32     protected $_options;
33     
34     /**
35      * list of plugins 
36      * 
37      * @var array
38      */
39     protected $_plugins = array();
40     
41     /**
42      * name of the ldap attribute which identifies a group uniquely
43      * for example gidNumber, entryUUID, objectGUID
44      * @var string
45      */
46     protected $_groupUUIDAttribute;
47     
48     /**
49      * name of the ldap attribute which identifies a user uniquely
50      * for example uidNumber, entryUUID, objectGUID
51      * @var string
52      */
53     protected $_userUUIDAttribute;
54     
55     /**
56      * the basic group ldap filter (for example the objectclass)
57      *
58      * @var string
59      */
60     protected $_groupBaseFilter      = 'objectclass=group';
61     
62     /**
63      * the basic user ldap filter (for example the objectclass)
64      *
65      * @var string
66      */
67     protected $_userBaseFilter      = 'objectclass=user';
68     
69     /**
70      * the basic user search scope
71      *
72      * @var integer
73      */
74     protected $_groupSearchScope     = Zend_Ldap::SEARCH_SCOPE_SUB;
75     
76     /**
77      * the basic user search scope
78      *
79      * @var integer
80      */
81     protected $_userSearchScope      = Zend_Ldap::SEARCH_SCOPE_SUB;
82     
83     protected $_isReadOnlyBackend    = false;
84     
85     /**
86      * the constructor
87      *
88      * @param  array $options Options used in connecting, binding, etc.
89      */
90     public function __construct(array $_options) 
91     {
92         if(empty($_options['userUUIDAttribute'])) {
93             $_options['userUUIDAttribute'] = 'objectGUID';
94         }
95         if(empty($_options['groupUUIDAttribute'])) {
96             $_options['groupUUIDAttribute'] = 'objectGUID';
97         }
98         if(empty($_options['baseDn'])) {
99             $_options['baseDn'] = $_options['userDn'];
100         }
101         if(empty($_options['userFilter'])) {
102             $_options['userFilter'] = 'objectclass=user';
103         }
104         if(empty($_options['userSearchScope'])) {
105             $_options['userSearchScope'] = Zend_Ldap::SEARCH_SCOPE_SUB;
106         }
107         if(empty($_options['groupFilter'])) {
108             $_options['groupFilter'] = 'objectclass=group';
109         }
110         
111         parent::__construct($_options);
112         
113         // get domain sid
114         $this->_domainConfig = $this->getLdap()->search(
115             'objectClass=domain',
116             $this->getLdap()->getFirstNamingContext(),
117             Zend_Ldap::SEARCH_SCOPE_BASE
118         )->getFirst();
119         
120         $this->_domainSidBinary = $this->_domainConfig['objectsid'][0];
121         $this->_domainSidPlain  = Tinebase_Ldap::decodeSid($this->_domainConfig['objectsid'][0]);
122         
123         $domanNameParts    = array();
124         Zend_Ldap_Dn::explodeDn($this->_domainConfig['distinguishedname'][0], $fooBar, $domanNameParts);
125         $this->_domainName = implode('.', $domanNameParts);
126     }
127     
128     /**
129      * create a new group in sync backend
130      *
131      * @param  Tinebase_Model_Group  $_group
132      * 
133      * @return Tinebase_Model_Group|NULL
134      */
135     public function addGroupInSyncBackend(Tinebase_Model_Group $_group) 
136     {
137         if ($this->_isReadOnlyBackend) {
138             return NULL;
139         }
140         
141         $dn = $this->_generateDn($_group);
142         $objectClass = array(
143             'top',
144             'group'
145         );
146         
147         $ldapData = array(
148             'objectclass'    => $objectClass,
149             'cn'             => $_group->name,
150             'description'    => $_group->description,
151             'samaccountname' => $_group->name,
152         );
153         
154         if ($this->_options['useRfc2307']) {
155             $ldapData['objectclass'][] = 'posixGroup';
156             $ldapData['gidnumber']     = $this->_generateGidNumber();
157             
158             $ldapData['msSFU30NisDomain'] = Tinebase_Helper::array_value(0, explode('.', $this->_domainName));
159         }
160         
161         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) 
162             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' add group $dn: ' . $dn);
163         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
164             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $ldapData: ' . print_r($ldapData, true));
165         
166         $this->getLdap()->add($dn, $ldapData);
167         
168         $groupId = $this->getLdap()->getEntry($dn, array($this->_groupUUIDAttribute));
169         
170         $groupId = $this->_decodeGroupId($groupId[$this->_groupUUIDAttribute][0]);
171         
172         $group = $this->getGroupByIdFromSyncBackend($groupId);
173         
174         return $group;
175     }
176     
177     /**
178      * add a new groupmember to group in sync backend
179      *
180      * @param  mixed  $_groupId
181      * @param  mixed  $_accountId string or user object
182      */
183     public function addGroupMemberInSyncBackend($_groupId, $_accountId) 
184     {
185         if ($this->_isReadOnlyBackend) {
186             return;
187         }
188         
189         $userId  = Tinebase_Model_User::convertUserIdToInt($_accountId);
190         $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
191         
192         $memberships = $this->getGroupMembershipsFromSyncBackend($userId);
193         if (in_array($groupId, $memberships)) {
194              if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
195                  Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . " skip adding group member, as $userId is already in group $groupId");
196              
197              return;
198         }
199         
200         $groupDn         = $this->_getDn($groupId);
201         $accountMetaData = $this->_getAccountMetaData($userId);
202         
203         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
204             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " account meta data: " . print_r($accountMetaData, true));
205         
206         $ldapData = array(
207             'member' => $accountMetaData['dn']
208         );
209         
210         $this->getLdap()->addProperty($groupDn, $ldapData);
211     }
212     
213     /**
214      * get groupmemberships of user from sync backend
215      * 
216      * @param   Tinebase_Model_User|string  $_userId
217      * @return  array  list of group ids
218      */
219     public function getGroupMembershipsFromSyncBackend($_userId)
220     {
221         $userId = $_userId instanceof Tinebase_Model_User ? $_userId->getId() : $_userId; 
222         
223         // find user in AD and retrieve memberOf attribute
224         $filter = Zend_Ldap_Filter::andFilter(
225             Zend_Ldap_Filter::string($this->_userBaseFilter),
226             Zend_Ldap_Filter::equals($this->_userUUIDAttribute, $this->_encodeAccountId($userId))
227         );
228         
229         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
230             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ .' ldap search filter: ' . $filter);
231         
232         $memberOfs = $this->getLdap()->search(
233             $filter, 
234             $this->_options['userDn'], 
235             $this->_userSearchScope, 
236             array('memberof', 'primarygroupid')
237         )->getFirst();
238         
239         if ($memberOfs === null) {
240             return array();
241         }
242         
243         // resolve primarygrouid to dn
244         $filter = Zend_Ldap_Filter::andFilter(
245             Zend_Ldap_Filter::string($this->_groupBaseFilter),
246             Zend_Ldap_Filter::equals('objectsid', Zend_Ldap::filterEscape($this->_domainSidPlain . '-' . $memberOfs['primarygroupid'][0]))
247         );
248         
249         $group = $this->getLdap()->search(
250             $filter, 
251             $this->_options['groupsDn'], 
252             $this->_groupSearchScope, 
253             array($this->_groupUUIDAttribute)
254         )->getFirst();
255         
256         $memberships = array(
257             $this->_decodeGroupId($group[$this->_groupUUIDAttribute][0])
258         );
259         
260         if (isset($memberOfs['memberof'])) {
261             // resolve $this->_groupUUIDAttribute attribute
262             $filter = new Zend_Ldap_Filter_Or(array());
263             foreach ($memberOfs['memberof'] as $memberOf) {
264                 $filter = $filter->addFilter(Zend_Ldap_Filter::equals('distinguishedName', Zend_Ldap::filterEscape($memberOf)));
265             }
266             
267             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
268                 Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ .' ldap search filter: ' . $filter);
269             
270             $groups = $this->getLdap()->search(
271                 $filter, 
272                 $this->_options['groupsDn'], 
273                 $this->_groupSearchScope, 
274                 array($this->_groupUUIDAttribute)
275             );
276             
277             foreach ($groups as $group) {
278                 $memberships[] = $this->_decodeGroupId($group[$this->_groupUUIDAttribute][0]);
279             }
280         }
281         
282         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
283             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .' group memberships: ' . print_r($memberships, TRUE));
284         
285         return array_unique($memberships);
286     }
287     
288     /**
289      * updates an existing group in sync backend
290      *
291      * @param  Tinebase_Model_Group  $_group
292      *
293      * @return Tinebase_Model_Group
294      */
295     public function updateGroupInSyncBackend(Tinebase_Model_Group $_group)
296     {
297         if ($this->isDisabledBackend() || $this->isReadOnlyBackend()) {
298             return $_group;
299         }
300         
301         $metaData = $this->_getMetaData($_group->getId());
302         $dn = $metaData['dn'];
303         
304         $ldapData = array(
305                 'cn'          => $_group->name,
306                 'description' => $_group->description,
307                 'objectclass' => $metaData['objectclass']
308         );
309         
310         foreach ($this->_plugins as $plugin) {
311             $plugin->inspectUpdateGroup($_group, $ldapData);
312         }
313         
314         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG))
315             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $dn: ' . $dn);
316         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE))
317             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  $ldapData: ' . print_r($ldapData, true));
318         
319         $this->getLdap()->update($dn, $ldapData);
320         
321         $newDn = "cn={$ldapData['cn']},{$this->_options['baseDn']}";
322         if ($newDn != $dn) {
323             $this->_ldap->rename($dn, $newDn);
324         }
325         
326         
327         $group = $this->getGroupByIdFromSyncBackend($_group);
328         
329         return $group;
330     }
331     
332     /**
333      * remove one member from the group in sync backend
334      *
335      * @param  mixed  $_groupId
336      * @param  mixed  $_accountId
337      */
338     public function removeGroupMemberInSyncBackend($_groupId, $_accountId) 
339     {
340         if ($this->_isReadOnlyBackend) {
341             return;
342         }
343         
344         $userId  = Tinebase_Model_User::convertUserIdToInt($_accountId);
345         $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
346         
347         $memberships = $this->getGroupMemberships($_accountId);
348         if (!in_array($groupId, $memberships)) {
349              if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) 
350                  Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " skip removing group member, as $userId is not in group $groupId " . print_r($memberships, true));
351              return;
352         }
353         
354         try {
355             $groupDn = $this->_getDn($_groupId);
356         } catch (Tinebase_Exception_NotFound $tenf) {
357             if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) 
358                 Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . " Failed to remove groupmember $_accountId from group $_groupId: " . $tenf->getMessage());
359             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
360                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $tenf->getTraceAsString());
361             return;
362         }
363         
364         try {
365             $accountMetaData = $this->_getAccountMetaData($_accountId);
366         } catch (Tinebase_Exception_NotFound $tenf) {
367             if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) 
368                 Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . ' user not found in sync backend: ' . $_accountId);
369             return;
370         }
371         
372         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
373             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " account meta data: " . print_r($accountMetaData, true));
374         
375         $memberUidNumbers = $this->getGroupMembers($_groupId);
376         
377         $ldapData = array(
378             'member' => $accountMetaData['dn']
379         );
380             
381         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
382             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $dn: ' . $groupDn);
383         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
384             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  $ldapData: ' . print_r($ldapData, true));
385         
386         try {
387             $this->getLdap()->deleteProperty($groupDn, $ldapData);
388         } catch (Zend_Ldap_Exception $zle) {
389             if (Tinebase_Core::isLogLevel(Zend_Log::CRIT)) 
390                 Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . " Failed to remove groupmember {$accountMetaData['dn']} from group $groupDn: " . $zle->getMessage());
391             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
392                 Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $zle->getTraceAsString());
393         }
394     }
395     
396     /**
397      * resolve gidnumber to UUID(for example entryUUID) attribute
398      * 
399      * @param int $_gidNumber the gidnumber
400      * @return string 
401      */
402     public function resolveGIdNumberToUUId($rid)
403     {
404         $groupSid = $this->_domainSidPlain . '-' .  $rid;
405         
406         $filter = Zend_Ldap_Filter::andFilter(
407             Zend_Ldap_Filter::string($this->_groupBaseFilter),
408             Zend_Ldap_Filter::equals('objectsid', $groupSid)
409         );
410         
411         $groupId = $this->getLdap()->search(
412             $filter, 
413             $this->_options['groupsDn'], 
414             $this->_groupSearchScope, 
415             array($this->_groupUUIDAttribute)
416         )->getFirst();
417         
418         if ($groupId == null) {
419             throw new Tinebase_Exception_NotFound('LDAP group with (objectsid=' . $groupSid . ') not found');
420         }
421         
422         return $this->_decodeGroupId($groupId[$this->_groupUUIDAttribute][0]);
423     }
424     
425     /**
426      * resolve UUID(for example entryUUID) to gidnumber
427      * 
428      * @param string $_uuid
429      * @return string
430      */
431     public function resolveUUIdToGIdNumber($_uuid)
432     {
433         $filter = Zend_Ldap_Filter::andFilter(
434             Zend_Ldap_Filter::string($this->_groupBaseFilter),
435             Zend_Ldap_Filter::equals($this->_groupUUIDAttribute, $this->_encodeGroupId($_uuid))
436         );
437         
438         $groupData = $this->getLdap()->search(
439             $filter, 
440             $this->_options['groupsDn'], 
441             $this->_groupSearchScope, 
442             array('objectsid')
443         )->getFirst();
444
445         $sidParts = explode('-', Tinebase_Ldap::decodeSid($groupData['objectsid'][0]));
446         
447         return array_pop($sidParts);
448     }
449     
450     /**
451      * return gidnumber of group
452      * 
453      * @param string $_uuid
454      * @return string
455      */
456     public function resolveGidNumber($_uuid)
457     {
458         $filter = Zend_Ldap_Filter::andFilter(
459             Zend_Ldap_Filter::string($this->_groupBaseFilter),
460             Zend_Ldap_Filter::equals($this->_groupUUIDAttribute, $this->_encodeGroupId($_uuid))
461         );
462         
463         $groupData = $this->getLdap()->search(
464             $filter, 
465             $this->_options['groupsDn'], 
466             $this->_groupSearchScope, 
467             array('gidnumber')
468         )->getFirst();
469
470         return $groupData['gidnumber'][0];
471         
472     }
473     
474     /**
475      * replace all current groupmembers with the new groupmembers list in sync backend
476      *
477      * @param  string  $_groupId
478      * @param  array   $_groupMembers array of ids
479      * @return array with current group memberships (account ids)
480      */
481     public function setGroupMembersInSyncBackend($_groupId, $_groupMembers) 
482     {
483         if ($this->_isReadOnlyBackend) {
484             return;
485         }
486         
487         $groupMetaData = $this->_getMetaData($_groupId);
488         
489         $membersMetaDatas = $this->_getAccountsMetaData((array)$_groupMembers, FALSE);
490         if (count($_groupMembers) !== count($membersMetaDatas)) {
491             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
492                 . ' Removing ' . (count($_groupMembers) - count($membersMetaDatas)) . ' no longer existing group members from group ' . $_groupId);
493             
494             $_groupMembers = array();
495             foreach ($membersMetaDatas as $account) {
496                 $_groupMembers[] = $account[$this->_userUUIDAttribute];
497             }
498         }
499         
500         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
501             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  $group data: ' . print_r($groupMetaData, true));
502         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
503             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  $memebers: ' . print_r($membersMetaDatas, true));
504         
505         $groupDn = $this->_getDn($_groupId);
506         
507         $memberDn = array();
508         foreach ($membersMetaDatas as $memberMetadata) {
509             if ($this->_domainSidPlain . '-' . $memberMetadata['primarygroupid'] == $groupMetaData['objectsid']) {
510                 // skip this user => is already meber because of his primary group
511                 continue;
512             }
513             $memberDn[]  = $memberMetadata['dn'];
514         }
515         
516         $ldapData = array(
517             'member' => $memberDn
518         );
519         
520         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
521             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $dn: ' . $groupMetaData['dn']);
522         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) 
523             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . '  $ldapData: ' . print_r($ldapData, true));
524         
525         $this->getLdap()->update($groupMetaData['dn'], $ldapData);
526         
527         return $_groupMembers;
528     }
529     
530     /**
531      * convert binary id to plain text id
532      * 
533      * @param  string  $groupId
534      * @return string
535      */
536     protected function _decodeGroupId($groupId)
537     {
538         switch ($this->_groupUUIDAttribute) {
539             case 'objectguid':
540                 return Tinebase_Ldap::decodeGuid($groupId);
541                 break;
542                 
543             case 'objectsid':
544                 return Tinebase_Ldap::decodeSid($groupId);
545                 break;
546                 
547             default:
548                 return $groupId;
549                 break;
550         }
551     }
552     
553     /**
554      * convert plain text id to binary id
555      * 
556      * @param  string  $accountId
557      * @return string
558      */
559     protected function _encodeAccountId($accountId)
560     {
561         switch ($this->_userUUIDAttribute) {
562             case 'objectguid':
563                 return Tinebase_Ldap::encodeGuid($accountId);
564                 break;
565                 
566             default:
567                 return $accountId;
568                 break;
569         }
570         
571     }
572     
573     /**
574      * convert plain text id to binary id
575      * 
576      * @param  string  $groupId
577      * @return string
578      */
579     protected function _encodeGroupId($groupId)
580     {
581         switch ($this->_groupUUIDAttribute) {
582             case 'objectguid':
583                 return Tinebase_Ldap::encodeGuid($groupId);
584                 break;
585                 
586             default:
587                 return $groupId;
588                 break;
589         }
590     }
591     
592     /**
593      * returns arrays of metainfo from given accountIds
594      *
595      * @param array $_accountIds
596      * @param boolean $throwExceptionOnMissingAccounts
597      * @return array of strings
598      */
599     protected function _getAccountsMetaData(array $_accountIds, $throwExceptionOnMissingAccounts = TRUE)
600     {
601         $filterArray = array();
602         foreach ($_accountIds as $accountId) {
603             $accountId = Tinebase_Model_User::convertUserIdToInt($accountId);
604             $filterArray[] = Zend_Ldap_Filter::equals($this->_userUUIDAttribute, $this->_encodeAccountId($accountId));
605         }
606         $filter = new Zend_Ldap_Filter_Or($filterArray);
607         
608         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) 
609             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $filter: ' . $filter . ' count: ' . count($filterArray));
610         
611         // fetch all dns at once
612         $accounts = $this->getLdap()->search(
613             $filter, 
614             $this->_options['userDn'], 
615             $this->_userSearchScope, 
616             array($this->_userUUIDAttribute, 'objectclass', 'primarygroupid')
617         );
618         
619         if (count($_accountIds) != count($accounts)) {
620             $wantedAccountIds    = array();
621             $retrievedAccountIds = array();
622             
623             foreach ($_accountIds as $accountId) {
624                 $wantedAccountIds[] = Tinebase_Model_User::convertUserIdToInt($accountId);
625             }
626             foreach ($accounts as $account) {
627                 $retrievedAccountIds[] = $account[$this->_userUUIDAttribute][0];
628             }
629             
630             $message = "Some dn's are missing. "  . print_r(array_diff($wantedAccountIds, $retrievedAccountIds), true);
631             if ($throwExceptionOnMissingAccounts) {
632                 throw new Tinebase_Exception_NotFound($message);
633             } else {
634                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN)) Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $message);
635             }
636         }
637         
638         $result = array();
639         foreach ($accounts as $account) {
640             $result[] = array(
641                 'dn'                        => $account['dn'],
642                 'objectclass'               => $account['objectclass'],
643                 $this->_userUUIDAttribute   => $this->_decodeGroupId($account[$this->_userUUIDAttribute][0]),
644                 'primarygroupid'            => $account['primarygroupid'][0]
645             );
646         }
647
648         return $result;
649     }
650     
651     /**
652      * returns ldap metadata of given group
653      *
654      * @param  string $_groupId
655      * @return array
656      * @throws Tinebase_Exception_NotFound
657      * 
658      * @todo remove obsolete code
659      */
660     protected function _getMetaData($_groupId)
661     {
662         $groupId = Tinebase_Model_Group::convertGroupIdToInt($_groupId);
663         
664         $filter = Zend_Ldap_Filter::equals(
665             $this->_groupUUIDAttribute, $this->_encodeGroupId($groupId)
666         );
667         
668         $result = $this->getLdap()->search(
669             $filter, 
670             $this->_options['groupsDn'], 
671             $this->_groupSearchScope, 
672             array('objectclass', 'objectsid')
673         );
674         
675         if (count($result) !== 1) {
676             throw new Tinebase_Exception_NotFound("Group with id $_groupId not found.");
677         }
678         
679         $group = $result->getFirst();
680         
681         return array(
682             'dn'          => $group['dn'],
683             'objectclass' => $group['objectclass'],
684             'objectsid'   => Tinebase_Ldap::decodeSid($group['objectsid'][0])
685         );
686     }
687 }