source: sandbox/workflow/branches/993/inc/class.WorkflowLDAP.inc.php @ 2492

Revision 2492, 21.2 KB checked in by pedroerp, 14 years ago (diff)

Ticket #993 - Trocando acessos à GLOBALS por acessos à Settings.

Line 
1<?php
2/**************************************************************************\
3* eGroupWare                                                               *
4* http://www.egroupware.org                                                *
5* --------------------------------------------                             *
6*  This program is free software; you can redistribute it and/or modify it *
7*  under the terms of the GNU General Public License as published by the   *
8*  Free Software Foundation; either version 2 of the License, or (at your  *
9*  option) any later version.                                              *
10\**************************************************************************/
11
12/**
13 * Implements common LDAP methods
14 * @author Sidnei Augusto Drovetto Jr. - drovetto@gmail.com
15 * @version 1.0
16 * @package Workflow
17 * @license http://www.gnu.org/copyleft/gpl.html GPL
18 */
19class WorkflowLDAP
20{
21        /**
22         * @var resource $dataSource Recurso de conexão com o LDAP
23         * @access private
24         */
25        private $dataSource;
26
27        /**
28         * @var string $userContext Contexto do usuário
29         * @access private
30         */
31        private $userContext;
32
33        /**
34         * @var string $groupContext Contexto do grupo
35         * @access private
36         */
37        private $groupContext;
38
39        /**
40         * @var string $ldapContext Contexto do LDAP
41         * @access private
42         */
43        private $ldapContext;
44
45        /**
46         * Construtor da classe
47         * @return object
48         * @access public
49         */
50        function WorkflowLDAP()
51        {
52                $this->dataSource =& Factory::getInstance('WorkflowObjects')->getLDAP();
53
54                /* get the required parameters */
55                $ldapUserContext = Settings::get('workflow', 'ldap', 'user_context');
56                $ldapGroupContext = Settings::get('workflow', 'ldap', 'group_context');
57
58                if (empty($ldapUserContext))
59                        $ldapUserContext = Settings::get('expresso', 'ldap', 'user_context');
60
61                if (empty($ldapGroupContext))
62                        $ldapGroupContext = Settings::get('expresso', 'ldap', 'group_context');
63
64                $this->userContext = $ldapUserContext;
65                $this->groupContext = $ldapGroupContext;
66                $this->ldapContext = $ldapUserContext;
67
68                $this->cache = array(
69                        'getEntities' => array(),
70                        'getUserGroups' => array(),
71                        'getGroupUsers' => array(),
72                        'getOrganizations' => array(),
73                        'getNames' => array()
74                );
75        }
76
77        /**
78         * Checa se um método, e seus parâmetros, já estãoe em cache
79         * @param string $methodName O nome do método que se quer verificar
80         * @param string $parameters Parâmetros passados para o método (serializados)
81         * @return bool true se foi encontrada uma versão em cache dos dados solicitados e false caso contrário
82         * @access private
83         */
84        private function checkCache($methodName, $parameters)
85        {
86                return isset($this->cache[$methodName][$parameters]);
87        }
88
89        /**
90         * Pega a informação, em cache, de um método e seus parâmetros
91         * @param string $methodName O nome do método que está em cache
92         * @param string $parameters Parâmetros passados para o método (serializados)
93         * @return mixed O retorno do método usando os parâmetros passados
94         * @access private
95         */
96        private function getCache($methodName, $parameters)
97        {
98                return $this->cache[$methodName][$parameters];
99        }
100
101        /**
102         * Coloca em cache um método e seus parâmetros
103         * @param string $methodName O nome do método
104         * @param string $parameters Parâmetros passados para o método (serializados)
105         * @param mixed $output Saída do método usando os parâmetros passados
106         * @return mixed A saída igual ao parâmetro $output
107         * @access private
108         */
109        private function setCache($methodName, $parameters, $output)
110        {
111                $this->cache[$methodName][$parameters] = $output;
112                return $output;
113        }
114
115        /**
116         * Faz consultas ao LDAP
117         * @param string $context Contexto das entidades
118         * @param string $filter Filtro utilizado para selecionar as entidades desejadas
119         * @param array $elements Array dos campos que se deseja obter
120         * @param bool $depthSearch Indica se a busca deve incluir sub-árvores ou não
121         * @param string $elementSort O elemento pelo qual se quer ordenar o resultado
122         * @return mixed Array do resultado. Ou false em caso de erro
123         * @access private
124         */
125        private function runLDAP($context, $filter, $elements, $depthSearch = false, $elementSort = null)
126        {
127                if ($depthSearch)
128                        $resourceIdentifier = ldap_search($this->dataSource, $context, $filter, $elements);
129                else
130                        $resourceIdentifier = ldap_list($this->dataSource, $context, $filter, $elements);
131
132                if (!$resourceIdentifier)
133                        return false;
134
135                if (!is_null($elementSort))
136                        ldap_sort($this->dataSource, $resourceIdentifier, $elementSort);
137
138                $output = ldap_get_entries($this->dataSource, $resourceIdentifier);
139                return $output;
140        }
141
142        /**
143         * Faz consultas ao LDAP (inclusive com campos binários)
144         * @param string $context Contexto das entidades
145         * @param string $filter Filtro utilizado para selecionar as entidades desejadas
146         * @param array $elements Array dos campos que se deseja obter
147         * @param bool $depthSearch Indica se a busca deve incluir sub-árvores ou não
148         * @param string $elementSort O elemento pelo qual se quer ordenar o resultado
149         * @return mixed Array do resultado. Ou false em caso de erro
150         * @access private
151         */
152        private function runBinaryLDAP($context, $filter, $elements, $depthSearch = false, $elementSort = null)
153        {
154                if ($depthSearch)
155                        $resourceIdentifier = ldap_search($this->dataSource, $context, $filter, $elements);
156                else
157                        $resourceIdentifier = ldap_list($this->dataSource, $context, $filter, $elements);
158
159                if (!$resourceIdentifier)
160                        return false;
161
162                if (!is_null($elementSort))
163                        ldap_sort($this->dataSource, $resourceIdentifier, $elementSort);
164
165                $entry = ldap_first_entry($this->dataSource, $resourceIdentifier);
166                if (!$entry)
167                        return array();
168
169                $output = array();
170                $counter = 0;
171                do
172                {
173                        $attributes = ldap_get_attributes($this->dataSource, $entry);
174                        for ($i = 0; $i < $attributes['count']; $i++)
175                                $output[$counter][$attributes[$i]] = ldap_get_values_len($this->dataSource, $entry, $attributes[$i]);
176
177                        $counter++;
178                } while ($entry = ldap_next_entry($this->dataSource, $entry));
179
180                return $output;
181        }
182
183        /**
184         * Busca entidades (usuários, grupos ou listas públicas) do LDAP
185         * @param string $context Contexto das entidades
186         * @param string $filter Filtro utilizado para selecionar as entidades desejadas
187         * @param array $elements Array dos campos que representa, nesta ordem: o ID, o nome e o e-mail da entidade
188         * @param char $type O tipo da entidade: 'u' para usuários; 'g' para grupos; e 'l' para listas públicas
189         * @param bool $depthSearch Indica se a busca deve incluir sub-árvores ou não
190         * @return array Array das entidades
191         * @access private
192         */
193        private function getEntities($context, $filter, $elements, $type, $depthSearch = false)
194        {
195                /* check if the required information is in cache */
196                $methodName = 'getEntities';
197                $parameters = serialize(func_get_args());
198                if ($this->checkCache($methodName, $parameters))
199                        return $this->getCache($methodName, $parameters);
200
201                $result = $this->runLDAP($context, $filter, $elements, $depthSearch, $elements[1]);
202
203                $output = array();
204                for ($i = 0; $i < $result['count']; $i++)
205                {
206                        $output[] = array(
207                                'id' => $result[$i][$elements[0]][0],
208                                'name' => $result[$i][$elements[1]][0],
209                                'type' => $type,
210                                'mail' => $result[$i][$elements[2]][0]);
211                }
212
213                /* store the information in cache and return the output */
214                return $this->setCache($methodName, $parameters, $output);
215        }
216
217        /**
218         * Retorna os grupos de um usuário
219         * @param int $userID O ID do usuário
220         * @return array Array dos grupos
221         * @access public
222         */
223        function getUserGroups($userID)
224        {
225                /* do not perform any search if the user is '*' */
226                if ($userID == '*')
227                        return array();
228
229                /* check if the required information is in cache */
230                $methodName = 'getUserGroups';
231                $parameters = serialize(func_get_args());
232                if ($this->checkCache($methodName, $parameters))
233                        return $this->getCache($methodName, $parameters);
234
235                /* check for error in connection */
236                if (!$this->dataSource)
237                        return false;
238
239                /* first, get the UID */
240                $resourceIdentifier = ldap_search($this->dataSource, $this->userContext, "(&(phpgwaccounttype=u)(uidnumber={$userID}))", array('uid'));
241                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
242                if (!isset($result[0]['uid'][0]))
243                        return false;
244                $userLogin = $result[0]['uid'][0];
245
246                /* initialize some variables */
247                $output = array();
248
249                /* search the LDAP tree */
250                $resourceIdentifier = ldap_search($this->dataSource, $this->groupContext, "(&(phpgwaccounttype=g)(memberuid={$userLogin}))", array('gidnumber'));
251                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
252                for ($i = 0; $i < $result['count']; $i++)
253                        $output[] = $result[$i]['gidnumber'][0];
254
255                /* store the information in cache and return the output */
256                return $this->setCache($methodName, $parameters, $output);
257        }
258
259        /**
260         * Retorna os usuários de um grupo
261         * @param int $groupID O ID do grupo
262         * @return array Array dos usuários
263         * @access public
264         */
265        function getGroupUsers($groupID)
266        {
267                /* check if the required information is in cache */
268                $methodName = 'getGroupUsers';
269                $parameters = serialize(func_get_args());
270                if ($this->checkCache($methodName, $parameters))
271                        return $this->getCache($methodName, $parameters);
272
273                /* check for error in connection */
274                if (!$this->dataSource)
275                        return false;
276
277                /* first, we get the UIDs that are members of the group */
278                $resourceIdentifier = ldap_search($this->dataSource, $this->ldapContext, "(&(phpgwaccounttype=g)(gidnumber={$groupID}))", array('memberuid'));
279                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
280                if (!isset($result[0]['memberuid'][0]))
281                        return false;
282
283                $userLogins = $result[0]['memberuid'];
284                unset($userLogins['count']);
285
286                /* load the user information ten users at a time. This approach was proven to be faster on some systems */
287                $result = array();
288                while (count($userLogins) > 0)
289                {
290                        $selectedUserLogins = array_splice($userLogins, 0, 10);
291                        $resourceIdentifier = ldap_search($this->dataSource, $this->ldapContext, "(&(phpgwaccounttype=u)(|" . implode('', array_map(create_function('$a', 'return "(uid={$a})";'), $selectedUserLogins)) . "))", array('cn', 'uidnumber'));
292                        $result = array_merge($result, ldap_get_entries($this->dataSource, $resourceIdentifier));
293                        unset($result['count']);
294                }
295
296                $output = array();
297                $userCount = count($result);
298                for ($i = 0; $i < $userCount; $i++)
299                        $output[] = array(
300                                'account_id' => $result[$i]['uidnumber'][0],
301                                'account_name' => $result[$i]['cn'][0]);
302
303                /* sort the result */
304                usort($output, create_function('$a,$b', 'return strcasecmp($a[\'account_name\'],$b[\'account_name\']);'));
305
306                /* store the information in cache and return the output */
307                return $this->setCache($methodName, $parameters, $output);
308        }
309
310        /**
311         * Retorna as organizações do nível raiz
312         * @return array Array de organizações
313         * @access public
314         */
315        function getOrganizations()
316        {
317                /* check if the required information is in cache */
318                $methodName = 'getOrganizations';
319                $parameters = serialize(func_get_args());
320                if ($this->checkCache($methodName, $parameters))
321                        return $this->getCache($methodName, $parameters);
322
323                /* check for error in connection */
324                if (!$this->dataSource)
325                        return false;
326
327                /* load the sectors of level 0 as organizations, then format the data */
328                $output = array_map(create_function('$a', 'return $a[\'ou\'];'), $this->getSectors());
329
330                /* store the information in cache and return the output */
331                return $this->setCache($methodName, $parameters, $output);
332        }
333
334        /**
335         * Retorna os setores de um determinado contexto
336         * @param string $organization A organização a partir da qual a busca deve inciar. Utilize null para o nível raiz
337         * @param bool $recursive Indica se a busca deve ser recursiva ou não. true indica que deve ser recursiva e false que não deve ser recursiva
338         * @param string $contextBase A base do contexto. Utilize null para o contexto padrão
339         * @param int $level Indica o nível atual de recursão
340         * @return array Array de setores
341         * @access public
342         */
343        function getSectors($organization = null, $recursive = false, $contextBase = null, $level = 0)
344        {
345                /* determines the context in which the search will be performed */
346                $context = (!is_null($contextBase) ? $contextBase : $this->ldapContext);
347                $context = (!is_null($organization) ? 'ou=' . $organization . ',' : '') . $context;
348
349                /* search for the sectors */
350                $resourceIdentifier = @ldap_list($this->dataSource, $context, '(objectClass=organizationalUnit)', array('ou'));
351                if ($resourceIdentifier === false)
352                        return false;
353
354                ldap_sort($this->dataSource, $resourceIdentifier, 'ou');
355                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
356
357                /* collect the data */
358                $output = array();
359                for ($i = 0; $i < $result['count']; $i++)
360                {
361                        $output[] = array(
362                                'dn' => $result[$i]['dn'],
363                                'ou' => $result[$i]['ou'][0],
364                                'level' => $level);
365
366                        /* if requested, perform a recursive search */
367                        if ($recursive)
368                                $output = array_merge($output, $this->getSectors($result[$i]['ou'][0], $recursive, $context, $level + 1));
369                }
370
371                return $output;
372        }
373
374        /**
375         * Retorna os usuários de um determinado contexto
376         * @param string $context O contexto a partir do qual a busca deve começar
377         * @return array Array dos usuários encontrados
378         * @access public
379         */
380        function getUsers($context)
381        {
382                $filter = '(&(phpgwaccounttype=u)(!(phpgwAccountVisible=-1)))';
383                $elements = array('uidnumber', 'cn', 'mail');
384                return $this->getEntities($context, $filter, $elements, 'u', false);
385        }
386
387        /**
388         * Retorna os grupos de um determinado contexto
389         * @param string $context O contexto a partir do qual a busca deve começar
390         * @return array Array dos grupos encontrados
391         * @access public
392         */
393        function getGroups($context)
394        {
395                $filter = '(phpgwaccounttype=g)';
396                $elements = array('gidnumber', 'cn', 'mail');
397                return $this->getEntities($context, $filter, $elements, 'g', false);
398        }
399
400        /**
401         * Retorna listas públicas de um determinado contexto
402         * @param string $context O contexto a partir do qual a busca deve começar
403         * @return array Array das listas públicas encontradas
404         * @access public
405         */
406        function getPublicLists($context)
407        {
408                $filter = '(phpgwaccounttype=l)';
409                $elements = array('uidnumber', 'cn', 'mail');
410                return $this->getEntities($context, $filter, $elements, 'l', false);
411        }
412
413        /**
414         * Retornar informação sobre um usuário
415         * @param int $userID O ID do usuário
416         * @return mixed Array contento informação sobre um usuário ou false se o usuário não for encontrado
417         * @access public
418         */
419        function getUserInfo($userID)
420        {
421                $filter = '(&(phpgwaccounttype=u)(uidnumber=' . $userID . '))';
422                $elements = array('uidnumber', 'cn', 'mail');
423                $output = $this->getEntities($this->ldapContext, $filter, $elements, 'u', true);
424                if (count($output) == 1)
425                        return $output[0];
426                else
427                        return false;
428        }
429
430        function getUserPicture($userID)
431        {
432                $userID = (int) $userID;
433                $filter = '(&(phpgwaccounttype=u)(uidnumber=' . $userID . '))';
434                $elements = array('jpegPhoto');
435                $result = $this->runBinaryLDAP($this->ldapContext, $filter, $elements, true);
436
437                if (isset($result[0]['jpegPhoto'][0]))
438                        return $result[0]['jpegPhoto'][0];
439
440                return false;
441        }
442
443        /**
444         * Retrieves information about a group
445         * @param int $userID The ID of the group
446         * @return mixed Array containing information about a group or false if the group is not found
447         * @access public
448         */
449        function getGroupInfo($groupID)
450        {
451                $filter = '(&(phpgwaccounttype=g)(gidnumber=' . $groupID . '))';
452                $elements = array('gidnumber', 'cn', 'mail');
453                $output = $this->getEntities($this->ldapContext, $filter, $elements, 'g', true);
454                if (count($output) == 1)
455                        return $output[0];
456                else
457                        return false;
458        }
459
460        /**
461         * Retorna o tipo de uma entidade
462         * @param int $entityID O ID da entidade
463         * @return string O tipo da entidade ('g' para grupo e 'u' para usuário)
464         * @access public
465         */
466        function getEntityType($entityID)
467        {
468                if ($entityID == '*')
469                        return false;
470
471                $output = $this->getUserInfo($entityID);
472                if (is_array($output))
473                        return 'u';
474                else
475                {
476                        $output = $this->getGroupInfo($entityID);
477                        if (is_array($output))
478                                return 'g';
479                }
480
481                return false;
482        }
483
484        /**
485         * Retorna o nome de uma entidade
486         * @param int $entityID O ID da entidade
487         * @return string O nome da entidade
488         * @access public
489         */
490        function getName($entityID)
491        {
492                if ($entityID == '*')
493                        return '*';
494                $output = $this->getUserInfo($entityID);
495                if (is_array($output))
496                        return $output['name'];
497                else
498                {
499                        $output = $this->getGroupInfo($entityID);
500                        if (is_array($output))
501                                return $output['name'];
502                }
503        }
504
505        /**
506         * Retorna os nomes de uma entidade
507         * @param array $entitiesID Os IDs das entidades
508         * @return string Os nomes das entidades
509         * @access public
510         */
511        function getNames($entitiesID)
512        {
513                /* check if the required information is in cache */
514                $methodName = 'getNames';
515                $parameters = serialize(func_get_args());
516                if ($this->checkCache($methodName, $parameters))
517                        return $this->getCache($methodName, $parameters);
518
519                /* check for error in connection */
520                if (!$this->dataSource)
521                        return false;
522
523                /* check for '*' */
524                $asteriskIndex = array_search('*', $entitiesID);
525                if ($asteriskIndex !== false)
526                        unset($entitiesID[$asteriskIndex]);
527
528                /* load the entity information ten entities at a time. This approach was proven to be faster on some systems */
529                $result = array();
530                while (count($entitiesID) > 0)
531                {
532                        $selectedEntitiesID = array_splice($entitiesID, 0, 10);
533                        $resourceIdentifier = ldap_search($this->dataSource, $this->ldapContext, "(|" . implode('', array_map(create_function('$a', 'return "(|(&(uidnumber={$a})(|(phpgwaccounttype=u)(phpgwaccounttype=l)))(&(gidnumber={$a})(phpgwaccounttype=g)))";'), array_unique($selectedEntitiesID))) . ')', array('cn', 'uidnumber', 'gidnumber', 'phpgwaccounttype'));
534                        $result = array_merge($result, ldap_get_entries($this->dataSource, $resourceIdentifier));
535                        unset($result['count']);
536                }
537
538                $output = array();
539                $entityCount = count($result);
540                for ($i = 0; $i < $entityCount; $i++)
541                        $output[] = array(
542                                'id' => ($result[$i]['phpgwaccounttype'][0] == 'g') ? $result[$i]['gidnumber'][0] : $result[$i]['uidnumber'][0],
543                                'name' => $result[$i]['cn'][0]);
544
545                if ($asteriskIndex !== false)
546                        $output[] = array('id' => '*', 'name' => '*');
547
548                /* sort the result */
549                usort($output, create_function('$a,$b', 'return strcasecmp($a[\'name\'],$b[\'name\']);'));
550
551                /* store the information in cache and return the output */
552                return $this->setCache($methodName, $parameters, $output);
553        }
554
555        /**
556         * Faz uma busca (em todo o catálogo) por um nome
557         * @param string $searchTerm O termo que está sendo procurado (pode conter '*')
558         * @param bool $includeUsers Indica se na busca devem ser incluídos os registros referentes a usuários (true por padrão)
559         * @param bool $includeGroups Indica se na busca devem ser incluídos os registros referentes a grupos (false por padrão)
560         * @param bool $includeLists Indica se na busca devem ser incluídos os registros referentes a listas (false por padrão)
561         * @return array Uma array contendo os registros encontrados
562         * @access public
563         */
564        function search($searchTerm, $includeUsers = true, $includeGroups = false, $includeLists = false, $context = null)
565        {
566                if (!($includeUsers || $includeGroups || $includeLists))
567                        return false;
568
569                if (is_null($context))
570                        $context = $this->ldapContext;
571
572                /* check for error in connection */
573                if (!$this->dataSource)
574                        return false;
575
576                $entityFilter = array();
577                if ($includeUsers)
578                        $entityFilter[] = '(phpgwaccounttype=u)';
579                if ($includeGroups)
580                        $entityFilter[] = '(phpgwaccounttype=g)';
581                if ($includeLists)
582                        $entityFilter[] = '(phpgwaccounttype=l)';
583
584                if (count($entityFilter) > 1)
585                        $entityFilter = '(|' . implode('', $entityFilter) . ')';
586                else
587                        $entityFilter = $entityFilter[0];
588
589                $filter = "(&{$entityFilter}(cn={$searchTerm})(!(phpgwAccountVisible=-1)))";
590                $resourceIdentifier = ldap_search($this->dataSource, $context, $filter, array('cn', 'uidnumber', 'gidnumber', 'phpgwaccounttype', 'mail'));
591                ldap_sort($this->dataSource, $resourceIdentifier, 'cn');
592                $result = ldap_get_entries($this->dataSource, $resourceIdentifier);
593
594                $output = array();
595                for ($i = 0; $i < $result['count']; $i++)
596                        $output[] = array(
597                                'id' => ($result[$i]['phpgwaccounttype'][0] == 'g') ? $result[$i]['gidnumber'][0] : $result[$i]['uidnumber'][0],
598                                'name' => $result[$i]['cn'][0],
599                                'mail' => $result[$i]['mail'][0],
600                                'type' => $result[$i]['phpgwaccounttype'][0],
601                                'dn' => $result[$i]['dn']
602                        );
603
604                /* store the information in cache and return the output */
605                return $output;
606        }
607
608        /**
609         * Retorna o contexto de usuários do LDAP
610         * @return string O contexto de usuários do LDAP
611         * @access public
612         */
613        function getUserContext()
614        {
615                return $this->userContext;
616        }
617
618        /**
619         * Retorna o contexto de grupos do LDAP
620         * @return string O contexto de grupos do LDAP
621         * @access public
622         */
623        function getGroupContext()
624        {
625                return $this->groupContext;
626        }
627
628        /**
629         * Retorna o contexto do LDAP
630         * @return string O contexto do LDAP
631         * @access public
632         */
633        function getLDAPContext()
634        {
635                return $this->ldapContext;
636        }
637
638        /**
639         * Retorna a organização de um DN
640         * @param mixed $DN O DN do usuário
641         * @return mixed Uma string contendo a organização ou false caso não seja achada a organização
642         * @access public
643         */
644        public function getOrganizationFromDN($DN)
645        {
646                $userContext = str_replace(' ', '', $this->userContext);
647                $DN = str_replace(' ', '', $DN);
648                $userInfo = array_reverse(explode(',', substr($DN, 0, - (strlen($userContext) + 1))));
649                foreach ($userInfo as $attributePair)
650                {
651                        list($name, $value) = explode('=', $attributePair, 2);
652                        if ($name === 'ou')
653                                return $value;
654                }
655
656                return false;
657        }
658}
659?>
Note: See TracBrowser for help on using the repository browser.