]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiGroup.php
LDAP cleanup, start of new Pref classes
[SourceForge/phpwiki.git] / lib / WikiGroup.php
1 <?php
2 rcs_id('$Id: WikiGroup.php,v 1.10 2004-02-03 09:45:39 rurban Exp $');
3 /*
4  Copyright 2003, 2004 $ThePhpWikiProgrammingTeam
5
6  This file is part of PhpWiki.
7
8  PhpWiki is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  PhpWiki is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 // for now we provide no default memberhsip method. this might change.
24 // (!defined('GROUP_METHOD')) define('GROUP_METHOD', "WIKIPAGE");
25
26 if (!defined('GROUP_METHOD') or !in_array(GROUP_METHOD,array('NONE','WIKIPAGE','DB','FILE','LDAP')))
27     trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
28
29 /**
30  * WikiGroup is an abstract class to provide the base functions for determining
31  * group membership.
32  * 
33  * WikiGroup is an abstract class with three functions:
34  * <ol><li />Provide the static method getGroup with will return the proper
35  *         subclass.
36  *     <li />Provide an interface for subclasses to implement.
37  *     <li />Provide fallover methods (with error msgs) if not impemented in subclass.
38  * </ol>
39  * Do not ever instantiate this class use: $group = &WikiGroup::getGroup($request);
40  * This will instantiate the proper subclass.
41  * @author Joby Walker <zorloc@imperium.org>
42  */ 
43 class WikiGroup{
44     /** User name */
45     var $username;
46     /** The global WikiRequest object */
47     var $request;
48     /** Array of groups $username is confirmed to belong to */
49     var $membership;
50     
51     /**
52      * Initializes a WikiGroup object which should never happen.  Use:
53      * $group = &WikiGroup::getGroup($request);
54      * @param object $request The global WikiRequest object -- ignored.
55      */ 
56     function WikiGroup(&$request){    
57         return;
58     }
59
60     /**
61      * Gets the current username and erases $this->membership if is different than
62      * the stored $this->username
63      * @return string Current username.
64      */ 
65     function _getUserName(){
66         $request = &$this->request;
67         $user = $request->getUser();
68         $username = $user->getID();
69         if ($username != $this->username) {
70             $this->membership = array();
71             $this->username = $username;
72         }
73         return $username;
74     }
75     
76     /**
77      * Static method to return the WikiGroup subclass used in this wiki.  Controlled
78      * by the constant GROUP_METHOD.
79      * @param object $request The global WikiRequest object.
80      * @return object Subclass of WikiGroup selected via GROUP_METHOD.
81      */ 
82     function getGroup($request){
83         switch (GROUP_METHOD){
84             case "NONE": 
85                 return new GroupNone($request);
86                 break;
87             case "WIKIPAGE":
88                 return new GroupWikiPage($request);
89                 break;
90             case "DB":
91                 return new GroupDB($request);
92                 break;
93             case "FILE": 
94                 return new GroupFile($request);
95                 break;
96             /*
97             case "LDAP": 
98                 return new GroupLDAP($request);
99                 break;
100             */
101             default:
102                 trigger_error(_("No or unsupported GROUP_METHOD defined"), E_USER_WARNING);
103                 return new WikiGroup($request);
104         }
105     }
106
107     /**
108      * Determines if the current user is a member of a group.
109      * 
110      * This method is an abstraction.  The group is ignored, an error is sent, and
111      * false (not a member of the group) is returned.
112      * @param string $group Name of the group to check for membership (ignored).
113      * @return boolean True if user is a member, else false (always false).
114      */ 
115     function isMember($group){
116         trigger_error("Method 'isMember' not implemented in this GROUP_METHOD", 
117                       E_USER_WARNING);
118         return false;
119     }
120     
121     /**
122      * Determines all of the groups of which the current user is a member.
123      * 
124      * This method is an abstraction.  An error is sent and an empty 
125      * array is returned.
126      * @return array Array of groups to which the user belongs (always empty).
127      */ 
128     function getAllGroupsIn(){
129         trigger_error("Method 'getAllGroupsIn' not implemented in this GROUP_METHOD",
130                       E_USER_WARNING);
131         return array();
132     }
133
134     /**
135      * Determines all of the members of a particular group.
136      * 
137      * This method is an abstraction.  The group is ignored, an error is sent, 
138      * and an empty array is returned
139      * @param string $group Name of the group to get the full membership list of.
140      * @return array Array of usernames that have joined the group (always empty).
141      */ 
142     function getMembersOf($group){
143         trigger_error("Method 'getMembersof' not implemented in this GROUP_METHOD", 
144                       E_USER_WARNING);
145         return array();
146     }
147
148     /**
149      * Add the current or specified user to a group.
150      * 
151      * This method is an abstraction.  The group and user are ignored, an error 
152      * is sent, and false (not added) is always returned.
153      * @param string $group User added to this group.
154      * @param string $user Username to add to the group (default = current user).
155      * @return bool On true user was added, false if not.
156      */ 
157     function setMemberOf($group, $user = false){
158         trigger_error("Method 'setMemberOf' not implemented in this GROUP_METHOD", 
159                       E_USER_WARNING);
160         return false;
161     }
162     
163     /**
164      * Remove the current or specified user to a group.
165      * 
166      * This method is an abstraction.  The group and user are ignored, and error
167      * is sent, and false (not removed) is always returned.
168      * @param string $group User removed from this group.
169      * @param string $user Username to remove from the group (default = current user).
170      * @return bool On true user was removed, false if not.
171      */ 
172     function removeMemberOf($group, $user = false){
173         trigger_error("Method 'removeMemberOf' not implemented in this GROUP_METHOD", 
174                       E_USER_WARNING);
175         return false;
176     }
177 }
178
179 /**
180  * GroupNone disables all Group funtionality
181  * 
182  * All of the GroupNone functions return false or empty values to indicate failure or 
183  * no results.  Use GroupNone if group controls are not desired.
184  * @author Joby Walker <zorloc@imperium.org>
185  */ 
186 class GroupNone extends WikiGroup{
187
188     /**
189      * Constructor
190      * 
191      * Ignores the parameter provided.
192      * @param object $request The global WikiRequest object - ignored.
193      */ 
194     function GroupNone(&$request){
195         return;
196     }    
197
198     /**
199      * Determines if the current user is a member of a group.
200      * 
201      * The group is ignored and false (not a member of the group) is returned.
202      * @param string $group Name of the group to check for membership (ignored).
203      * @return boolean True if user is a member, else false (always false).
204      */ 
205     function isMember($group){
206         return false;
207     }
208     
209     /**
210      * Determines all of the groups of which the current user is a member.
211      * 
212      * The group is ignored and an empty array (a member of no groups) is returned.
213      * @param string $group Name of the group to check for membership (ignored).
214      * @return array Array of groups to which the user belongs (always empty).
215      */ 
216     function getAllGroupsIn(){
217         return array();
218     }
219
220     /**
221      * Determines all of the members of a particular group.
222      * 
223      * The group is ignored and an empty array (a member of no groups) is returned.
224      * @param string $group Name of the group to check for membership (ignored).
225      * @return array Array of groups user belongs to (always empty).
226      */ 
227     function getMembersOf($group){
228         return array();
229     }
230
231 }
232
233 /**
234  * GroupWikiPage provides group functionality via pages within the Wiki.
235  * 
236  * GroupWikiPage is the Wiki way of managing a group.  Every group will have 
237  * a page. To modify the membership of the group, one only needs to edit the 
238  * membership list on the page.
239  * @author Joby Walker <zorloc@imperium.org>
240  */ 
241 class GroupWikiPage extends WikiGroup{
242     
243     /**
244      * Constructor
245      * 
246      * Initiallizes the three superclass instance variables
247      * @param object $request The global WikiRequest object.
248      */ 
249     function GroupWikiPage(&$request){
250         $this->request = &$request;
251         $this->username = null;
252         $this->membership = array();
253     }
254
255     /**
256      * Determines if the current user is a member of a group.
257      * 
258      * To determine membership in a particular group, this method checks the 
259      * superclass instance variable $membership to see if membership has 
260      * already been determined.  If not, then the group page is parsed to 
261      * determine membership.
262      * @param string $group Name of the group to check for membership.
263      * @return boolean True if user is a member, else false.
264      */ 
265     function isMember($group){
266         $request = $this->request;
267         $username = $this->_getUserName();
268         if (isset($this->membership[$group])) {
269             return $this->membership[$group];
270         }
271         $group_page = $request->getPage($group);
272         if ($this->_inGroupPage($group_page)) {
273             $this->membership[$group] = true;
274             return true;
275         }
276         $this->membership[$group] = false;
277         return false;
278     }
279     
280     /**
281     * Private method to take a WikiDB_Page and parse to determine if the
282     * current_user is a member of the group.
283     * @param object $group_page WikiDB_Page object for the group's page
284     * @return boolean True if user is a member, else false.
285     * @access private
286     */
287     function _inGroupPage($group_page){
288         $group_revision = $group_page->getCurrentRevision();
289         if ($group_revision->hasDefaultContents()) {
290             $group = $group_page->getName();
291             trigger_error(sprintf(_("Group %s does not exist"),$group), E_USER_WARNING);
292             return false;
293         }
294         $contents = $group_revision->getContent();
295         $match = '/^\s*[\*\#]+\s*' . $username . '\s*$/';
296         foreach($contents as $line){
297             if (preg_match($match, $line)) {
298                 return true;
299             }
300         }
301         return false;
302     }
303     
304     /**
305      * Determines all of the groups of which the current user is a member.
306      * 
307      * Checks the root Group page ('CategoryGroup') for the list of all groups, 
308      * then checks each group to see if the current user is a member.
309      * @param string $group Name of the group to check for membership.
310      * @return array Array of groups to which the user belongs.
311      */ 
312     function getAllGroupsIn(){
313         $request = &$this->request;
314         $username = $this->_getUserName();
315         $membership = array();
316         $dbh = &$request->getDbh();
317         $master_page = $request->getPage('CategoryGroup');
318         $master_list = $master_page->getLinks(true);
319         while($group_page = $master_list->next()){
320             if ($this->_inGroupPage($group_page)) {
321                 $group = $group_page->getName();
322                 $membership[$group] = true;
323             } else {
324                 $membership[$group] = false;
325             }
326         }
327         $this->membership = $membership;
328         return $membership;
329     }
330
331     /**
332      * Determines all of the members of a particular group.
333      * 
334      * Checks a group's page to return all the current members.  Currently this
335      * method is disabled and triggers an error and returns an empty array.
336      * @param string $group Name of the group to get the full membership list of.
337      * @return array Array of usernames that have joined the group (always empty).
338      */ 
339     function getMembersOf($group){
340         trigger_error("GroupWikiPage::getMembersof is not yet implimented",
341                       E_USER_WARNING);
342         return array();
343         /*
344         * Waiting for a reliable way to check if a string is a username.
345         $request = $this->request;
346         $user = $this->user;
347         $group_page = $request->getPage($group);
348         $group_revision = $group_page->getCurrentRevision();
349         if ($group_revision->hasDefaultContents()) {
350             trigger_error("Group $group does not exist", E_USER_WARNING);
351             return false;
352         }
353         $contents = $group_revision->getContent();
354         $match = '/^(\s*[\*\#]+\s*)(\w+)(\s*)$/';
355         $members = array();
356         foreach($contents as $line){
357             $matches = array();
358             if(preg_match($match, $line, $matches)){
359                 $members[] = $matches[2];
360             }
361         }
362         return $members;
363         */
364     }
365 }
366
367 /**
368  * GroupDb is configured by $DbAuthParams[] statements
369  * 
370  * @author ReiniUrban
371  */ 
372 class GroupDb extends WikiGroup {
373     
374     /**
375      * Constructor
376      * 
377      * @param object $request The global WikiRequest object.
378      */ 
379     function GroupDb(&$request){
380         $this->request = &$request;
381         $this->username = null;
382         $this->membership = array();
383
384         if (empty($DBAuthParams['group_members']) or 
385             empty($DBAuthParams['user_groups']) or
386             empty($DBAuthParams['is_member'])) {
387             trigger_error(_("No GROUP_DB SQL statements defined"), E_USER_WARNING);
388             return false;
389         }
390         $dbh = _PassUser::getAuthDbh();
391         $this->_is_member = $dbh->prepare(preg_replace(array('"$userid"','"$groupname"'),array('?','?'),$DBAuthParams['is_member']));
392         $this->_group_members = $dbh->prepare(preg_replace('"$groupname"','?',$DBAuthParams['group_members']));
393         $this->_user_groups = $dbh->prepare(preg_replace('"$userid"','?',$DBAuthParams['user_groups']));
394     }
395
396     /**
397      * Determines if the current user is a member of a group.
398      * 
399      * To determine membership in a particular group, this method checks the 
400      * superclass instance variable $membership to see if membership has 
401      * already been determined.  If not, then the group page is parsed to 
402      * determine membership.
403      * @param string $group Name of the group to check for membership.
404      * @return boolean True if user is a member, else false.
405      */ 
406     function isMember($group) {
407         $request = $this->request;
408         $username = $this->_getUserName();
409         if (isset($this->membership[$group])) {
410             return $this->membership[$group];
411         }
412         $dbh = _PassUser::getAuthDbh();
413         $db_result = $dbh->execute($this->_is_member,$username,$group);
414         if ($db_result->numRows() > 0) {
415             $this->membership[$group] = true;
416             return true;
417         }
418         $this->membership[$group] = false;
419         return false;
420     }
421     
422     /**
423      * Determines all of the groups of which the current user is a member.
424      * 
425      * then checks each group to see if the current user is a member.
426      * @param string $group Name of the group to check for membership.
427      * @return array Array of groups to which the user belongs.
428      */ 
429     function getAllGroupsIn(){
430         $request = &$this->request;
431         $username = $this->_getUserName();
432         $membership = array();
433
434         $dbh = _PassUser::getAuthDbh();
435         $db_result = $dbh->execute($this->_user_groups,$username);
436         if ($db_result->numRows() > 0) {
437             while (list($group) = $db_result->fetchRow()) {
438                 $membership[] = $group;
439             }
440         }
441         $this->membership = $membership;
442         return $membership;
443     }
444
445     /**
446      * Determines all of the members of a particular group.
447      * 
448      * Checks a group's page to return all the current members.  Currently this
449      * method is disabled and triggers an error and returns an empty array.
450      * @param string $group Name of the group to get the full membership list of.
451      * @return array Array of usernames that have joined the group.
452      */ 
453     function getMembersOf($group){
454         $request = &$this->request;
455         $username = $this->_getUserName();
456         $members = array();
457
458         $dbh = _PassUser::getAuthDbh();
459         $db_result = $dbh->execute($this->_group_members,$group);
460         if ($db_result->numRows() > 0) {
461             while (list($userid) = $db_result->fetchRow()) {
462                 $members[] = $userid;
463             }
464         }
465         return $members;
466     }
467 }
468
469 /**
470  * GroupFile is configured by AUTH_GROUP_FILE
471  * groupname: user1 user2 ...
472  * 
473  * @author ReiniUrban
474  */ 
475 class GroupFile extends WikiGroup {
476     
477     /**
478      * Constructor
479      * 
480      * @param object $request The global WikiRequest object.
481      */ 
482     function GroupFile(&$request){
483         $this->request = &$request;
484         $this->username = null;
485         $this->membership = array();
486
487         if (!defined('AUTH_GROUP_FILE')) {
488             trigger_error(_("AUTH_GROUP_FILE not defined"), E_USER_WARNING);
489             return false;
490         }
491         if (!file_exists(AUTH_GROUP_FILE)) {
492             trigger_error(sprintf(_("Cannot open AUTH_GROUP_FILE %s"), AUTH_GROUP_FILE), E_USER_WARNING);
493             return false;
494         }
495         require 'lib/pear/File_Passwd.php';
496         $this->_file = File_Passwd($file);
497     }
498
499     /**
500      * Determines if the current user is a member of a group.
501      * 
502      * To determine membership in a particular group, this method checks the 
503      * superclass instance variable $membership to see if membership has 
504      * already been determined.  If not, then the group file is parsed to 
505      * determine membership.
506      * @param string $group Name of the group to check for membership.
507      * @return boolean True if user is a member, else false.
508      */ 
509     function isMember($group) {
510         $request = $this->request;
511         $username = $this->_getUserName();
512         if (isset($this->membership[$group])) {
513             return $this->membership[$group];
514         }
515
516         foreach ($this->_file->users[] as $g => $u) {
517             $users = explode(' ',$u);
518             if (in_array($username,$users)) {
519                 $this->membership[$group] = true;
520                 return true;
521             }
522         }
523         $this->membership[$group] = false;
524         return false;
525     }
526     
527     /**
528      * Determines all of the groups of which the current user is a member.
529      * 
530      * then checks each group to see if the current user is a member.
531      * @param string $group Name of the group to check for membership.
532      * @return array Array of groups to which the user belongs.
533      */ 
534     function getAllGroupsIn(){
535         $request = &$this->request;
536         $username = $this->_getUserName();
537         $membership = array();
538
539         foreach ($this->_file->users[] as $group => $u) {
540             $users = explode(' ',$u);
541             if (in_array($username,$users)) {
542                 $this->membership[$group] = true;
543                 $membership[] = $group;
544             }
545         }
546         $this->membership = $membership;
547         return $membership;
548     }
549
550     /**
551      * Determines all of the members of a particular group.
552      * 
553      * Checks a group's page to return all the current members.  Currently this
554      * method is disabled and triggers an error and returns an empty array.
555      * @param string $group Name of the group to get the full membership list of.
556      * @return array Array of usernames that have joined the group.
557      */ 
558     function getMembersOf($group){
559         $request = &$this->request;
560         $username = $this->_getUserName();
561         $members = array();
562
563         if (!empty($this->_file->users[$group])) {
564             return explode(' ',$this->_file->users[$group]);
565         }
566         return $members;
567     }
568 }
569
570 /**
571  * Ldap is configured in index.php
572  * 
573  * @author ReiniUrban
574  */ 
575 class GroupLdap extends WikiGroup {
576     
577     /**
578      * Constructor
579      * 
580      * @param object $request The global WikiRequest object.
581      */ 
582     function GroupLdap(&$request){
583         $this->request = &$request;
584         $this->username = null;
585         $this->membership = array();
586
587         if (!defined("LDAP_AUTH_HOST")) {
588             trigger_error(_("LDAP_AUTH_HOST not defined"), E_USER_WARNING);
589             return false;
590         }
591         if (! function_exists('ldap_open')) {
592             dl("ldap".DLL_EXT);
593             if (! function_exists('ldap_open')) {
594                 trigger_error(_("No LDAP in this PHP version"), E_USER_WARNING);
595                 return false;
596             }
597         }
598     }
599
600     /**
601      * Determines if the current user is a member of a group.
602      * Not ready yet!
603      * 
604      * @param string $group Name of the group to check for membership.
605      * @return boolean True if user is a member, else false.
606      */ 
607     function isMember($group) {
608         if (isset($this->membership[$group])) {
609             return $this->membership[$group];
610         }
611         $request = $this->request;
612         $username = $this->_getUserName();
613         if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
614             $r = @ldap_bind($ldap);                 // this is an anonymous bind
615             $st_search = "uid=$username member=$group";
616             $sr = ldap_search($ldap, LDAP_BASE_DN,
617                               "$st_search");
618             $info = ldap_get_entries($ldap, $sr);
619             if ($info["count"] > 0) {
620                 ldap_close($ldap);
621                 $this->membership[$group] = true;
622                 return true;
623             }
624         }
625         $this->membership[$group] = false;
626         return false;
627     }
628     
629     /**
630      * Determines all of the groups of which the current user is a member.
631      * Not ready yet!
632      *
633      * @param string $group Name of the group to check for membership.
634      * @return array Array of groups to which the user belongs.
635      */ 
636     function getAllGroupsIn(){
637         $request = &$this->request;
638         $username = $this->_getUserName();
639         $membership = array();
640
641         if ($ldap = ldap_connect(LDAP_AUTH_HOST)) { // must be a valid LDAP server!
642             $r = @ldap_bind($ldap);                 // this is an anonymous bind
643             $st_search = "uid=$username";
644             $sr = ldap_search($ldap, LDAP_BASE_DN,
645                               "$st_search");
646             $info = ldap_get_entries($ldap, $sr); // there may be more hits with this userid. try every
647             for ($i = 0; $i < $info["count"]; $i++) {
648                 $dn = $info[$i]["member"];
649                 if ($r = @ldap_bind($ldap, $dn, $group)) {
650                     $membership[] = $group;
651                 }
652             }
653         }
654         ldap_close($ldap);
655         $this->membership = $membership;
656         return $membership;
657     }
658
659     /**
660      * Determines all of the members of a particular group.
661      * 
662      * Checks a group's page to return all the current members.  Currently this
663      * method is disabled and triggers an error and returns an empty array.
664      * @param string $group Name of the group to get the full membership list of.
665      * @return array Array of usernames that have joined the group.
666      */ 
667     function getMembersOf($group){
668         $request = &$this->request;
669         $username = $this->_getUserName();
670         $members = array();
671         /*
672         $dbh = _PassUser::getAuthDbh();
673         $db_result = $dbh->execute($this->_group_members,$group);
674         if ($db_result->numRows() > 0) {
675             while (list($userid) = $db_result->fetchRow()) {
676                 $members[] = $userid;
677             }
678         }
679         */
680         return $members;
681     }
682 }
683
684 // $Log: not supported by cvs2svn $
685 // Revision 1.9  2004/02/01 09:14:11  rurban
686 // Started with Group_Ldap (not yet ready)
687 // added new _AuthInfo plugin to help in auth problems (warning: may display passwords)
688 // fixed some configurator vars
689 // renamed LDAP_AUTH_SEARCH to LDAP_BASE_DN
690 // changed PHPWIKI_VERSION from 1.3.8a to 1.3.8pre
691 // USE_DB_SESSION defaults to true on SQL
692 // changed GROUP_METHOD definition to string, not constants
693 // changed sample user DBAuthParams from UPDATE to REPLACE to be able to
694 //   create users. (Not to be used with external databases generally, but
695 //   with the default internal user table)
696 //
697 // fixed the IndexAsConfigProblem logic. this was flawed:
698 //   scripts which are the same virtual path defined their own lib/main call
699 //   (hmm, have to test this better, phpwiki.sf.net/demo works again)
700 //
701 // Revision 1.8  2004/01/27 23:23:39  rurban
702 // renamed ->Username => _userid for consistency
703 // renamed mayCheckPassword => mayCheckPass
704 // fixed recursion problem in WikiUserNew
705 // fixed bogo login (but not quite 100% ready yet, password storage)
706 //
707 // Revision 1.7  2004/01/26 16:52:40  rurban
708 // added GroupDB and GroupFile classes
709 //
710 // Revision 1.6  2003/12/07 19:29:11  carstenklapp
711 // Code Housecleaning: fixed syntax errors. (php -l *.php)
712 //
713 // Revision 1.5  2003/02/22 20:49:55  dairiki
714 // Fixes for "Call-time pass by reference has been deprecated" errors.
715 //
716 // Revision 1.4  2003/01/21 04:02:39  zorloc
717 // Added Log entry and page footer.
718 //
719
720 // Local Variables:
721 // mode: php
722 // tab-width: 8
723 // c-basic-offset: 4
724 // c-hanging-comment-ender-p: nil
725 // indent-tabs-mode: nil
726 // End:
727 ?>