xref: /dokuwiki/lib/plugins/auth.php (revision 7840324d1522858cf4a504321e3a341cd35e44b6)
1<?php
2// must be run within Dokuwiki
3if(!defined('DOKU_INC')) die();
4
5/**
6 * Auth Plugin Prototype
7 *
8 * foundation authorisation class
9 * all auth classes should inherit from this class
10 *
11 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
12 * @author    Chris Smith <chris@jalakai.co.uk>
13 * @author    Jan Schumann <js@jschumann-it.com>
14 */
15class DokuWiki_Auth_Plugin extends DokuWiki_Plugin {
16    var $success = true;
17
18    /**
19     * Posible things an auth backend module may be able to
20     * do. The things a backend can do need to be set to true
21     * in the constructor.
22     */
23    var $cando = array (
24        'addUser'     => false, // can Users be created?
25        'delUser'     => false, // can Users be deleted?
26        'modLogin'    => false, // can login names be changed?
27        'modPass'     => false, // can passwords be changed?
28        'modName'     => false, // can real names be changed?
29        'modMail'     => false, // can emails be changed?
30        'modGroups'   => false, // can groups be changed?
31        'getUsers'    => false, // can a (filtered) list of users be retrieved?
32        'getUserCount'=> false, // can the number of users be retrieved?
33        'getGroups'   => false, // can a list of available groups be retrieved?
34        'external'    => false, // does the module do external auth checking?
35        'logout'      => true,  // can the user logout again? (eg. not possible with HTTP auth)
36    );
37
38    /**
39     * Constructor.
40     *
41     * Carry out sanity checks to ensure the object is
42     * able to operate. Set capabilities in $this->cando
43     * array here
44     *
45     * Set $this->success to false if checks fail
46     *
47     * @author  Christopher Smith <chris@jalakai.co.uk>
48     */
49    function __construct() {
50        // the base class constructor does nothing, derived class
51        // constructors do the real work
52    }
53
54    /**
55     * Capability check. [ DO NOT OVERRIDE ]
56     *
57     * Checks the capabilities set in the $this->cando array and
58     * some pseudo capabilities (shortcutting access to multiple
59     * ones)
60     *
61     * ususal capabilities start with lowercase letter
62     * shortcut capabilities start with uppercase letter
63     *
64     * @author  Andreas Gohr <andi@splitbrain.org>
65     * @return  bool
66     */
67    function canDo($cap) {
68        switch($cap){
69            case 'Profile':
70                // can at least one of the user's properties be changed?
71                return ( $this->cando['modPass']  ||
72                        $this->cando['modName']  ||
73                        $this->cando['modMail'] );
74                break;
75            case 'UserMod':
76                // can at least anything be changed?
77                return ( $this->cando['modPass']   ||
78                        $this->cando['modName']   ||
79                        $this->cando['modMail']   ||
80                        $this->cando['modLogin']  ||
81                        $this->cando['modGroups'] ||
82                        $this->cando['modMail'] );
83                break;
84            default:
85                // print a helping message for developers
86                if(!isset($this->cando[$cap])){
87                    msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?",-1);
88                }
89                return $this->cando[$cap];
90        }
91    }
92
93    /**
94     * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ]
95     *
96     * You should use this function instead of calling createUser, modifyUser or
97     * deleteUsers directly. The event handlers can prevent the modification, for
98     * example for enforcing a user name schema.
99     *
100     * @author Gabriel Birke <birke@d-scribe.de>
101     * @param string $type Modification type ('create', 'modify', 'delete')
102     * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. The content of this array depends on the modification type
103     * @return mixed Result from the modification function or false if an event handler has canceled the action
104     */
105    function triggerUserMod($type, $params) {
106        $validTypes = array(
107            'create' => 'createUser',
108            'modify' => 'modifyUser',
109            'delete' => 'deleteUsers'
110        );
111        if(empty($validTypes[$type]))
112            return false;
113        $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null);
114        $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata);
115        if ($evt->advise_before(true)) {
116            $result = call_user_func_array(array($this, $validTypes[$type]), $params);
117            $evt->data['modification_result'] = $result;
118        }
119        $evt->advise_after();
120        unset($evt);
121        return $result;
122    }
123
124    /**
125     * Log off the current user [ OPTIONAL ]
126     *
127     * Is run in addition to the ususal logoff method. Should
128     * only be needed when trustExternal is implemented.
129     *
130     * @see     auth_logoff()
131     * @author  Andreas Gohr <andi@splitbrain.org>
132     */
133    function logOff(){
134    }
135
136    /**
137     * Do all authentication [ OPTIONAL ]
138     *
139     * Set $this->cando['external'] = true when implemented
140     *
141     * If this function is implemented it will be used to
142     * authenticate a user - all other DokuWiki internals
143     * will not be used for authenticating, thus
144     * implementing the checkPass() function is not needed
145     * anymore.
146     *
147     * The function can be used to authenticate against third
148     * party cookies or Apache auth mechanisms and replaces
149     * the auth_login() function
150     *
151     * The function will be called with or without a set
152     * username. If the Username is given it was called
153     * from the login form and the given credentials might
154     * need to be checked. If no username was given it
155     * the function needs to check if the user is logged in
156     * by other means (cookie, environment).
157     *
158     * The function needs to set some globals needed by
159     * DokuWiki like auth_login() does.
160     *
161     * @see auth_login()
162     * @author  Andreas Gohr <andi@splitbrain.org>
163     *
164     * @param   string  $user    Username
165     * @param   string  $pass    Cleartext Password
166     * @param   bool    $sticky  Cookie should not expire
167     * @return  bool             true on successful auth
168     */
169    function trustExternal($user,$pass,$sticky=false){
170        /* some example:
171
172        global $USERINFO;
173        global $conf;
174        $sticky ? $sticky = true : $sticky = false; //sanity check
175
176        // do the checking here
177
178        // set the globals if authed
179        $USERINFO['name'] = 'FIXME';
180        $USERINFO['mail'] = 'FIXME';
181        $USERINFO['grps'] = array('FIXME');
182        $_SERVER['REMOTE_USER'] = $user;
183        $_SESSION[DOKU_COOKIE]['auth']['user'] = $user;
184        $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass;
185        $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
186        return true;
187
188        */
189    }
190
191    /**
192     * Check user+password [ MUST BE OVERRIDDEN ]
193     *
194     * Checks if the given user exists and the given
195     * plaintext password is correct
196     *
197     * May be ommited if trustExternal is used.
198     *
199     * @author  Andreas Gohr <andi@splitbrain.org>
200     * @return  bool
201     */
202    function checkPass($user,$pass){
203        msg("no valid authorisation system in use", -1);
204        return false;
205    }
206
207    /**
208     * Return user info [ MUST BE OVERRIDDEN ]
209     *
210     * Returns info about the given user needs to contain
211     * at least these fields:
212     *
213     * name string  full name of the user
214     * mail string  email addres of the user
215     * grps array   list of groups the user is in
216     *
217     * @author  Andreas Gohr <andi@splitbrain.org>
218     * @return  array containing user data or false
219     */
220    function getUserData($user) {
221        if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
222        return false;
223    }
224
225    /**
226     * Create a new User [implement only where required/possible]
227     *
228     * Returns false if the user already exists, null when an error
229     * occurred and true if everything went well.
230     *
231     * The new user HAS TO be added to the default group by this
232     * function!
233     *
234     * Set addUser capability when implemented
235     *
236     * @author  Andreas Gohr <andi@splitbrain.org>
237     */
238    function createUser($user,$pass,$name,$mail,$grps=null){
239        msg("authorisation method does not allow creation of new users", -1);
240        return null;
241    }
242
243    /**
244     * Modify user data [implement only where required/possible]
245     *
246     * Set the mod* capabilities according to the implemented features
247     *
248     * @author  Chris Smith <chris@jalakai.co.uk>
249     * @param   $user      nick of the user to be changed
250     * @param   $changes   array of field/value pairs to be changed (password will be clear text)
251     * @return  bool
252     */
253    function modifyUser($user, $changes) {
254        msg("authorisation method does not allow modifying of user data", -1);
255        return false;
256    }
257
258    /**
259     * Delete one or more users [implement only where required/possible]
260     *
261     * Set delUser capability when implemented
262     *
263     * @author  Chris Smith <chris@jalakai.co.uk>
264     * @param   array  $users
265     * @return  int    number of users deleted
266     */
267    function deleteUsers($users) {
268        msg("authorisation method does not allow deleting of users", -1);
269        return false;
270    }
271
272    /**
273     * Return a count of the number of user which meet $filter criteria
274     * [should be implemented whenever retrieveUsers is implemented]
275     *
276     * Set getUserCount capability when implemented
277     *
278     * @author  Chris Smith <chris@jalakai.co.uk>
279     */
280    function getUserCount($filter=array()) {
281        msg("authorisation method does not provide user counts", -1);
282        return 0;
283    }
284
285    /**
286     * Bulk retrieval of user data [implement only where required/possible]
287     *
288     * Set getUsers capability when implemented
289     *
290     * @author  Chris Smith <chris@jalakai.co.uk>
291     * @param   start     index of first user to be returned
292     * @param   limit     max number of users to be returned
293     * @param   filter    array of field/pattern pairs, null for no filter
294     * @return  array of userinfo (refer getUserData for internal userinfo details)
295     */
296    function retrieveUsers($start=0,$limit=-1,$filter=null) {
297        msg("authorisation method does not support mass retrieval of user data", -1);
298        return array();
299    }
300
301    /**
302     * Define a group [implement only where required/possible]
303     *
304     * Set addGroup capability when implemented
305     *
306     * @author  Chris Smith <chris@jalakai.co.uk>
307     * @return  bool
308     */
309    function addGroup($group) {
310        msg("authorisation method does not support independent group creation", -1);
311        return false;
312    }
313
314    /**
315     * Retrieve groups [implement only where required/possible]
316     *
317     * Set getGroups capability when implemented
318     *
319     * @author  Chris Smith <chris@jalakai.co.uk>
320     * @return  array
321     */
322    function retrieveGroups($start=0,$limit=0) {
323        msg("authorisation method does not support group list retrieval", -1);
324        return array();
325    }
326
327    /**
328     * Return case sensitivity of the backend [OPTIONAL]
329     *
330     * When your backend is caseinsensitive (eg. you can login with USER and
331     * user) then you need to overwrite this method and return false
332     */
333    function isCaseSensitive(){
334        return true;
335    }
336
337    /**
338     * Sanitize a given username [OPTIONAL]
339     *
340     * This function is applied to any user name that is given to
341     * the backend and should also be applied to any user name within
342     * the backend before returning it somewhere.
343     *
344     * This should be used to enforce username restrictions.
345     *
346     * @author Andreas Gohr <andi@splitbrain.org>
347     * @param string $user - username
348     * @param string - the cleaned username
349     */
350    function cleanUser($user){
351        return $user;
352    }
353
354    /**
355     * Sanitize a given groupname [OPTIONAL]
356     *
357     * This function is applied to any groupname that is given to
358     * the backend and should also be applied to any groupname within
359     * the backend before returning it somewhere.
360     *
361     * This should be used to enforce groupname restrictions.
362     *
363     * Groupnames are to be passed without a leading '@' here.
364     *
365     * @author Andreas Gohr <andi@splitbrain.org>
366     * @param string $group - groupname
367     * @param string - the cleaned groupname
368     */
369    function cleanGroup($group){
370        return $group;
371    }
372
373
374    /**
375     * Check Session Cache validity [implement only where required/possible]
376     *
377     * DokuWiki caches user info in the user's session for the timespan defined
378     * in $conf['auth_security_timeout'].
379     *
380     * This makes sure slow authentication backends do not slow down DokuWiki.
381     * This also means that changes to the user database will not be reflected
382     * on currently logged in users.
383     *
384     * To accommodate for this, the user manager plugin will touch a reference
385     * file whenever a change is submitted. This function compares the filetime
386     * of this reference file with the time stored in the session.
387     *
388     * This reference file mechanism does not reflect changes done directly in
389     * the backend's database through other means than the user manager plugin.
390     *
391     * Fast backends might want to return always false, to force rechecks on
392     * each page load. Others might want to use their own checking here. If
393     * unsure, do not override.
394     *
395     * @param  string $user - The username
396     * @author Andreas Gohr <andi@splitbrain.org>
397     * @return bool
398     */
399    function useSessionCache($user){
400        global $conf;
401        return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge'));
402    }
403
404
405  /**
406   * loadConfig()
407   * merges the plugin's default settings with any local settings
408   * this function is automatically called through getConf()
409   */
410    function loadConfig(){
411      global $conf;
412
413      parent::loadConfig();
414
415      $this->conf['debug'] = $conf['debug'];
416      $this->conf['useacl'] = $conf['useacl'];
417      $this->conf['disableactions'] = $conf['disableactions'];
418      $this->conf['autopasswd'] = $conf['autopasswd'];
419      $this->conf['passcrypt'] = $conf['ssha'];
420  }
421
422}
423