xref: /plugin/authchained/auth.php (revision a015b7336312e0d49e4dd988e5fa36c642c8d93e)
1<?php
2// must be run within Dokuwiki
3if(!defined('DOKU_INC')) die();
4
5/**
6* Chained authentication backend
7*
8* @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
9* @author     Philipp Neuser <pneuser@physik.fu-berlin.de>
10* @author     Christian Marg <marg@rz.tu-clausthal.de>
11*
12* Based on "Chained authentication backend"
13* by Grant Gardner <grant@lastweekend.com.au>
14* see https://www.dokuwiki.org/auth:ggauth
15*
16*/
17class auth_plugin_authchained extends DokuWiki_Auth_Plugin {
18    public $success = true;
19    //array with authentication plugins
20    protected $chained_plugins = array();
21    protected $chained_auth = NULL;
22    protected $usermanager_auth = NULL;
23    protected $any_external = false;
24
25    /**
26    * Constructor.
27    *
28    * Loads all configured plugins or the authentication plugin of the
29    * logged in user.
30    *
31    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
32    * @author  Christian Marg <marg@rz.tu-clausthal.de>
33    */
34    public function __construct() {
35        global $conf;
36        // call parent
37        #      parent::__constructor();
38
39        //check if there is already an authentication plugin selected
40        if(     isset($_SESSION[DOKU_COOKIE]['plugin']['authchained']['module']) &&
41                !empty($_SESSION[DOKU_COOKIE]['plugin']['authchained']['module']) ) {
42
43            //get previously selected authentication plugin
44            $this->chained_auth =& plugin_load('auth',$_SESSION[DOKU_COOKIE]['plugin']['authchained']['module']);
45            if ( is_null($this->chained_auth) || !$this->chained_auth->success ) {
46                $this->success = false;
47            }
48        }
49
50        //get authentication plugins
51        if($this->getConf('authtypes')){
52            foreach(explode(":",$this->getConf('authtypes')) as $tmp_plugin){
53                $tmp_class =& plugin_load('auth',$tmp_plugin);
54
55                if ( !is_null($tmp_class) || $tmp_class->success ) {
56                    $tmp_module = array($tmp_plugin,$tmp_class);
57                    array_push($this->chained_plugins, $tmp_module);
58                    $this->any_external |= $tmp_class->canDo('external');
59                } else {
60                    msg("Problem constructing $tmp_plugin",-1);
61                    $this->success = false;
62                }
63            }
64        } else {
65            $success = false;
66        }
67
68        // If defined, instantiate usermanager authtype.
69        // No need to check for duplicates, "plugin_load" does that for us.
70        if($this->getConf('usermanager_authtype')){
71            $this->usermanager_auth =& plugin_load('auth',$this->getConf('usermanager_authtype'));
72            if(is_null($this->usermanager_auth) || !$this->usermanager_auth->success ) {
73                    msg("Problem constructing usermanager authtype: ".$this->getConf('usermanager_authtype'),-1);
74                    $this->success = false;
75            }
76        } else {
77            $this->usermanager_auth =& $this->chained_auth;
78        }
79
80        //debug
81        // print_r($chained_plugins);
82    }
83
84    /**
85    * Forwards the authentication to configured authplugins.
86    * Returns true, if the usermanager authtype has the capability and no user
87    * is logged in.
88    *
89    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
90    * @author  Christian Marg <marg@rz.tu-clausthal.de>
91    * @param   string $cap the capability to check
92    * @return  bool
93    */
94    public function canDo($cap) {
95        global $ACT;
96        #      print_r($cap);
97        if(is_null($this->chained_auth)) {
98            if ($cap == "external") {
99                return $this->any_external;
100            }
101            if (!is_null($this->usermanager_auth)) {
102                return $this->usermanager_auth->canDo($cap);
103            } else {
104                return parent::canDo($cap);
105            }
106        } else {
107            switch($cap) {
108                case 'Profile':
109                case 'logout':
110                    //Depends on current user.
111                    return $this->chained_auth->canDo($cap);
112                case 'UserMod':
113                case 'addUser':
114                case 'delUser':
115                case 'getUsers':
116                case 'getUserCount':
117                case 'getGroups':
118                    //Depends on the auth for use with user manager
119                    return $this->usermanager_auth->canDo($cap);
120                case 'modPass':
121                case 'modName':
122                case 'modLogin':
123                case 'modGroups':
124                case 'modMail':
125                    /**
126                    * Use request attributes to guess whether we are in the Profile or UserManager
127                    * and return the appropriate auth capabilities
128                    */
129                    if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
130                        return $this->usermanager_auth->canDo($cap);
131                    } else {
132                        // assume we want profile info.
133                        return $this->chained_auth->canDo($cap);
134                    }
135                case 'external':
136                    return $this->chained_auth->canDo($cap);
137                default:
138                    //Everything else (false)
139                    return parent::canDo($cap);
140            }
141            #echo "canDo $cap ".$this->chained_auth->canDo($cap)."\n";
142        }
143    }
144
145    /**
146    * Forwards the result of the auth plugin of the logged in user and
147    * unsets our session variable.
148    * @see     auth_logoff()
149    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de
150    * @author  Christian Marg <marg@rz.tu-clausthal.de>
151    */
152    public function logOff() {
153        if(!is_null($this->chained_auth))
154            $this->chained_auth->logOff();
155        unset($_SESSION[DOKU_COOKIE]['plugin']['authchained']['module']);
156    }
157
158    /**
159    * Do all authentication [ OPTIONAL ]
160    * If the current plugin is external, be external.
161    *
162    * @see     auth_login()
163    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
164    * @author  Christian Marg <marg@rz.tu-clausthal.de>
165    *
166    * @param   string  $user    Username
167    * @param   string  $pass    Cleartext Password
168    * @param   bool    $sticky  Cookie should not expire
169    * @return  bool             true on successful auth
170    */
171    public function trustExternal($user, $pass, $sticky = false) {
172        foreach($this->chained_plugins as $module) {
173            if($module[1]->canDo('external') && $module[1]->trustExternal($user, $pass)) {
174                $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0];
175                $this->chained_auth = $module[1];
176                return true;
177            }
178        }
179        return false;
180    }
181
182    /**
183    * Check user+password [ MUST BE OVERRIDDEN ]
184    *
185    * Checks if the given user exists in one of the plugins and checks
186    * against the given password. The first plugin returning true becomes
187    * auth plugin of the user session.
188    *
189    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de
190    * @author  Christian Marg <marg@rz.tu-clausthal.de>
191    * @param   string $user the user name
192    * @param   string $pass the clear text password
193    * @return  bool
194    */
195    public function checkPass($user, $pass) {
196        //debug
197        // print_r($this->chained_plugins);
198        if(!is_null($this->chained_auth))
199            return $this->chained_auth->checkPass($user, $pass);
200        foreach($this->chained_plugins as $module) {
201            if($module[1]->canDo('external') && $module[1]->trustExternal($user, $pass)) {
202                $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0];
203                $this->chained_auth = $module[1];
204                return true;
205            }
206            if($module[1]->checkPass($user, $pass)) {
207                $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0];
208                $this->chained_auth = $module[1];
209                return true;
210            }
211        }
212        return false;
213    }
214
215    /**
216    * Forwards the result of the auth plugin of the logged in user or
217    * checks all plugins if the users exists. The first plugin returning
218    * data is used.
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  Philipp Neuser <pneuser@physik.fu-berlin.de>
225    * @author  Christian Marg <marg@rz.tu-clausthal.de>
226    * @param   string $user the user name
227    * @return  array containing user data or false
228    */
229    public function getUserData($user, $requireGroups=true) {
230        global $ACT, $INPUT;
231
232        //if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
233        //       echo "TESTSETEST";
234
235        //print_r($this->chained_auth);
236        if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
237            if(!is_null($this->usermanager_auth))
238                return $this->usermanager_auth->getUserData($user);
239	}
240
241        if(is_null($this->chained_auth)||(!is_null($INPUT->server) && $user != $INPUT->server->str('REMOTE_USER'))) {
242            foreach($this->chained_plugins as $module) {
243                $tmp_array = $module[1]->getUserData($user);
244                if(!is_bool($tmp_array))
245                    $tmp_chk_arr =array_filter($tmp_array);
246                if(!empty($tmp_chk_arr) && $tmp_array)
247                    return $tmp_array;
248            }
249            return false;
250        } else {
251            return $this->chained_auth->getUserData($user);
252        }
253    }
254
255    /**
256    * Forwards the result of the auth plugin of the logged in user or
257    * returns null.
258    *
259    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
260    * @author  Christian Marg <marg@rz.tu-clausthal.de>
261    * @param   string     $user
262    * @param   string     $pass
263    * @param   string     $name
264    * @param   string     $mail
265    * @param   null|array $grps
266    * @return  bool|null
267    */
268    public function createUser($user, $pass, $name, $mail, $grps = null) {
269        if(!is_null($this->usermanager_auth) && $this->canDo('addUser')) {
270            return $this->usermanager_auth->createUser($user, $pass, $name, $mail, $grps);
271        } else {
272            msg("authorisation method does not allow creation of new users", -1);
273            return null;
274        }
275    }
276
277    /**
278    * Forwards the result of the auth plugin of the logged in user or
279    * returns false
280    *
281    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
282    * @author  Christian Marg <marg@rz.tu-clausthal.de>
283    * @param   string $user    nick of the user to be changed
284    * @param   array  $changes array of field/value pairs to be changed (password will be clear text)
285    * @return  bool
286    */
287    public function modifyUser($user, $changes) {
288        if(!is_null($this->usermanager_auth) && $this->canDo('UserMod') ) {
289            return $this->usermanager_auth->modifyUser($user, $changes);
290        } else {
291            msg("authorisation method does not allow modifying of user data", -1);
292            return null;
293        }
294    }
295
296    /**
297    * Forwards the result of the auth plugin of the logged in user or
298    * returns false
299    *
300    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
301    * @author  Christian Marg <marg@rz.tu-clausthal.de>
302    * @param   array  $users
303    * @return  int    number of users deleted
304    */
305    public function deleteUsers($users) {
306        if(!is_null($this->usermanager_auth) && $this->canDo('delUser') ) {
307            return $this->usermanager_auth->deleteUsers($users);
308        }else{
309            msg("authorisation method does not allow deleting of users", -1);
310            return false;
311        }
312    }
313
314    /**
315    * Forwards the result of the auth plugin of the logged in user or
316    * returns 0
317    *
318    * @author Philipp Neuser <pneuser@physik.fu-berlin.de>
319    * @author Christian Marg <marg@rz.tu-clausthal.de>
320    * @param  array $filter array of field/pattern pairs, empty array for no filter
321    * @return int
322    */
323    public function getUserCount($filter = array()) {
324        if(!is_null($this->usermanager_auth) && $this->canDo('getUserCount') ){
325            return $this->usermanager_auth->getUserCount($filter);
326        } else {
327            msg("authorisation method does not provide user counts", -1);
328            return 0;
329        }
330    }
331
332    /**
333    * Forwards the result of the auth plugin of the logged in user or
334    * returns empty array
335    *
336    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
337    * @author  Christian Marg <marg@rz.tu-clausthal.de>
338    * @param   int   $start     index of first user to be returned
339    * @param   int   $limit     max number of users to be returned
340    * @param   array $filter    array of field/pattern pairs, null for no filter
341    * @return  array list of userinfo (refer getUserData for internal userinfo details)
342    */
343    public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
344        if(!is_null($this->usermanager_auth) && $this->canDo('getUsers') ) {
345            //msg("RetrieveUsers is using ".get_class($this->usermanager_auth));
346            return $this->usermanager_auth->retrieveUsers($start, $limit, $filter);
347        } else {
348            msg("authorisation method does not support mass retrievals", -1);
349            return array();
350        }
351    }
352
353    /**
354    * Forwards the result of the auth plugin of the logged in user or
355    * returns false
356    *
357    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
358    * @author  Christian Marg <marg@rz.tu-clausthal.de>
359    * @param   string $group
360    * @return  bool
361    */
362    public function addGroup($group) {
363        if(!is_null($this->usermanager_auth) && $this->canDo('addGroup') ) {
364            return $this->usermanager_auth->addGroup($group);
365        } else {
366            msg("authorisation method does not support independent group creation", -1);
367            return false;
368        }
369    }
370
371    /**
372    * Forwards the result of the auth plugin of the logged in user or
373    * returns empty array
374    *
375    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
376    * @author  Christian Marg <marg@rz.tu-clausthal.de>
377    * @param   int $start
378    * @param   int $limit
379    * @return  array
380    */
381    public function retrieveGroups($start = 0, $limit = 0) {
382        if(!is_null($this->usermanager_auth) && $this->canDo('getGroups') ) {
383                return $this->usermanager_auth->retrieveGroups($start,$limit);
384        } else {
385            msg("authorisation method does not support group list retrieval", -1);
386            return array();
387        }
388    }
389
390    /**
391    * Forwards the result of the auth plugin of the logged in user or
392    * returns true
393    *
394    * @return bool
395    */
396    public function isCaseSensitive() {
397        if(is_null($this->chained_auth))
398            return parent::isCaseSensitive();
399        else
400            return $this->chained_auth->isCaseSensitive();
401    }
402
403    /**
404    * Sanitize a given username [OPTIONAL]
405    * Forwards the result of the auth plugin of the logged in user or
406    * returns false
407    *
408    *
409    * @author Philipp Neuser <pneuser@physik.fu-berlin.de>
410    * @author Christian Marg <marg@rz.tu-clausthal.de>
411    * @param  string $user username
412    * @return string the cleaned username
413    */
414    public function cleanUser($user) {
415        global $ACT;
416        //print_r($this->chained_auth);
417        if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
418            if(!is_null($this->usermanager_auth))
419                return $this->usermanager_auth->cleanUser($user);
420        } else {
421            if(!is_null($this->chained_auth))
422                return $this->chained_auth->cleanUser($user);
423        }
424        return parent::cleanUser($user);
425    }
426
427    /**
428    * Sanitize a given groupname [OPTIONAL]
429    * Forwards the result of the auth plugin of the logged in user or
430    * returns false
431    *
432    * @author Philipp Neuser <pneuser@physik.fu-berlin.de>
433    * @author Christian Marg <marg@rz.tu-clausthal.de>
434    * @param  string $group groupname
435    * @return string the cleaned groupname
436    */
437    public function cleanGroup($group) {
438        global $ACT;
439        if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
440            if(!is_null($this->usermanager_auth))
441                return $this->usermanager_auth->cleanGroup($group);
442        } else {
443            if(!is_null($this->chained_auth))
444                return $this->chained_auth->cleanGroup($group);
445        }
446        return parent::cleanGroup($group);
447    }
448
449
450    public function useSessionCache($user) {
451        global $conf;
452        if(is_null($this->chained_auth))
453            return parent::useSessionCache($user);
454        else
455            return $this->chained_auth->useSessionCache($user);
456    }
457
458}
459