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