xref: /plugin/authchained/auth.php (revision 5db6eafad4e6eb64b87c674e09099fb1d1d972ad)
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                case 'external':
111                    //Depends on current user.
112                    return $this->chained_auth->canDo($cap);
113                case 'UserMod':
114                case 'addUser':
115                case 'delUser':
116                case 'getUsers':
117                case 'getUserCount':
118                case 'getGroups':
119                    //Depends on the auth for use with user manager
120                    return $this->usermanager_auth->canDo($cap);
121                case 'modPass':
122                case 'modName':
123                case 'modLogin':
124                case 'modGroups':
125                case 'modMail':
126                    /**
127                    * Use request attributes to guess whether we are in the Profile or UserManager
128                    * and return the appropriate auth capabilities
129                    */
130                    if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
131                        return $this->usermanager_auth->canDo($cap);
132                    } else {
133                        // assume we want profile info.
134                        return $this->chained_auth->canDo($cap);
135                    }
136                default:
137                    //Everything else (false)
138                    return parent::canDo($cap);
139            }
140            #echo "canDo $cap ".$this->chained_auth->canDo($cap)."\n";
141        }
142    }
143
144    /**
145    * Forwards the result of the auth plugin of the logged in user and
146    * unsets our session variable.
147    * @see     auth_logoff()
148    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de
149    * @author  Christian Marg <marg@rz.tu-clausthal.de>
150    */
151    public function logOff() {
152        if(!is_null($this->chained_auth))
153            $this->chained_auth->logOff();
154        unset($_SESSION[DOKU_COOKIE]['plugin']['authchained']['module']);
155    }
156
157    /**
158    * Do all authentication [ OPTIONAL ]
159    * If the current plugin is external, be external.
160    *
161    * @see     auth_login()
162    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
163    * @author  Christian Marg <marg@rz.tu-clausthal.de>
164    *
165    * @param   string  $user    Username
166    * @param   string  $pass    Cleartext Password
167    * @param   bool    $sticky  Cookie should not expire
168    * @return  bool             true on successful auth
169    */
170    public function trustExternal($user, $pass, $sticky = false) {
171        foreach($this->chained_plugins as $module) {
172            if($module[1]->canDo('external') && $module[1]->trustExternal($user, $pass, $sticky)) {
173                $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0];
174                $this->chained_auth = $module[1];
175                return true;
176            }
177        }
178        return false;
179    }
180
181    /**
182    * Check user+password [ MUST BE OVERRIDDEN ]
183    *
184    * Checks if the given user exists in one of the plugins and checks
185    * against the given password. The first plugin returning true becomes
186    * auth plugin of the user session.
187    *
188    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de
189    * @author  Christian Marg <marg@rz.tu-clausthal.de>
190    * @param   string $user the user name
191    * @param   string $pass the clear text password
192    * @return  bool
193    */
194    public function checkPass($user, $pass) {
195        //debug
196        // print_r($this->chained_plugins);
197        if(!is_null($this->chained_auth))
198            return $this->chained_auth->checkPass($user, $pass);
199        foreach($this->chained_plugins as $module) {
200            if($module[1]->canDo('external') && $module[1]->trustExternal($user, $pass)) {
201                $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0];
202                $this->chained_auth = $module[1];
203                return true;
204            }
205            if($module[1]->checkPass($user, $pass)) {
206                $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0];
207                $this->chained_auth = $module[1];
208                return true;
209            }
210        }
211        return false;
212    }
213
214    /**
215    * Forwards the result of the auth plugin of the logged in user or
216    * checks all plugins if the users exists. The first plugin returning
217    * data is used.
218    *
219    * name string  full name of the user
220    * mail string  email addres of the user
221    * grps array   list of groups the user is in
222    *
223    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
224    * @author  Christian Marg <marg@rz.tu-clausthal.de>
225    * @param   string $user the user name
226    * @return  array containing user data or false
227    */
228    public function getUserData($user, $requireGroups=true) {
229        global $ACT, $INPUT;
230
231        //if(!$this->cando['external']) msg("no valid authorisation system in use", -1);
232        //       echo "TESTSETEST";
233
234        //print_r($this->chained_auth);
235        if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
236            if(!is_null($this->usermanager_auth))
237                return $this->usermanager_auth->getUserData($user);
238	}
239
240        if(is_null($this->chained_auth)||(!is_null($INPUT->server) && $user != $INPUT->server->str('REMOTE_USER'))) {
241            foreach($this->chained_plugins as $module) {
242                $tmp_array = $module[1]->getUserData($user);
243                if(!is_bool($tmp_array))
244                    $tmp_chk_arr =array_filter($tmp_array);
245                if(!empty($tmp_chk_arr) && $tmp_array)
246                    return $tmp_array;
247            }
248            return false;
249        } else {
250            return $this->chained_auth->getUserData($user);
251        }
252    }
253
254    /**
255    * Forwards the result of the auth plugin of the logged in user or
256    * returns null.
257    *
258    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
259    * @author  Christian Marg <marg@rz.tu-clausthal.de>
260    * @param   string     $user
261    * @param   string     $pass
262    * @param   string     $name
263    * @param   string     $mail
264    * @param   null|array $grps
265    * @return  bool|null
266    */
267    public function createUser($user, $pass, $name, $mail, $grps = null) {
268        if(!is_null($this->usermanager_auth) && $this->canDo('addUser')) {
269            return $this->usermanager_auth->createUser($user, $pass, $name, $mail, $grps);
270        } else {
271            msg("authorisation method does not allow creation of new users", -1);
272            return null;
273        }
274    }
275
276    /**
277    * Forwards the result of the auth plugin of the logged in user or
278    * returns false
279    *
280    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
281    * @author  Christian Marg <marg@rz.tu-clausthal.de>
282    * @param   string $user    nick of the user to be changed
283    * @param   array  $changes array of field/value pairs to be changed (password will be clear text)
284    * @return  bool
285    */
286    public function modifyUser($user, $changes) {
287        if(!is_null($this->usermanager_auth) && $this->canDo('UserMod') ) {
288            return $this->usermanager_auth->modifyUser($user, $changes);
289        } else {
290            msg("authorisation method does not allow modifying of user data", -1);
291            return null;
292        }
293    }
294
295    /**
296    * Forwards the result of the auth plugin of the logged in user or
297    * returns false
298    *
299    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
300    * @author  Christian Marg <marg@rz.tu-clausthal.de>
301    * @param   array  $users
302    * @return  int    number of users deleted
303    */
304    public function deleteUsers($users) {
305        if(!is_null($this->usermanager_auth) && $this->canDo('delUser') ) {
306            return $this->usermanager_auth->deleteUsers($users);
307        }else{
308            msg("authorisation method does not allow deleting of users", -1);
309            return false;
310        }
311    }
312
313    /**
314    * Forwards the result of the auth plugin of the logged in user or
315    * returns 0
316    *
317    * @author Philipp Neuser <pneuser@physik.fu-berlin.de>
318    * @author Christian Marg <marg@rz.tu-clausthal.de>
319    * @param  array $filter array of field/pattern pairs, empty array for no filter
320    * @return int
321    */
322    public function getUserCount($filter = array()) {
323        if(!is_null($this->usermanager_auth) && $this->canDo('getUserCount') ){
324            return $this->usermanager_auth->getUserCount($filter);
325        } else {
326            msg("authorisation method does not provide user counts", -1);
327            return 0;
328        }
329    }
330
331    /**
332    * Forwards the result of the auth plugin of the logged in user or
333    * returns empty array
334    *
335    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
336    * @author  Christian Marg <marg@rz.tu-clausthal.de>
337    * @param   int   $start     index of first user to be returned
338    * @param   int   $limit     max number of users to be returned
339    * @param   array $filter    array of field/pattern pairs, null for no filter
340    * @return  array list of userinfo (refer getUserData for internal userinfo details)
341    */
342    public function retrieveUsers($start = 0, $limit = -1, $filter = null) {
343        if(!is_null($this->usermanager_auth) && $this->canDo('getUsers') ) {
344            //msg("RetrieveUsers is using ".get_class($this->usermanager_auth));
345            return $this->usermanager_auth->retrieveUsers($start, $limit, $filter);
346        } else {
347            msg("authorisation method does not support mass retrievals", -1);
348            return array();
349        }
350    }
351
352    /**
353    * Forwards the result of the auth plugin of the logged in user or
354    * returns false
355    *
356    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
357    * @author  Christian Marg <marg@rz.tu-clausthal.de>
358    * @param   string $group
359    * @return  bool
360    */
361    public function addGroup($group) {
362        if(!is_null($this->usermanager_auth) && $this->canDo('addGroup') ) {
363            return $this->usermanager_auth->addGroup($group);
364        } else {
365            msg("authorisation method does not support independent group creation", -1);
366            return false;
367        }
368    }
369
370    /**
371    * Forwards the result of the auth plugin of the logged in user or
372    * returns empty array
373    *
374    * @author  Philipp Neuser <pneuser@physik.fu-berlin.de>
375    * @author  Christian Marg <marg@rz.tu-clausthal.de>
376    * @param   int $start
377    * @param   int $limit
378    * @return  array
379    */
380    public function retrieveGroups($start = 0, $limit = 0) {
381        if(!is_null($this->usermanager_auth) && $this->canDo('getGroups') ) {
382                return $this->usermanager_auth->retrieveGroups($start,$limit);
383        } else {
384            msg("authorisation method does not support group list retrieval", -1);
385            return array();
386        }
387    }
388
389    /**
390    * Forwards the result of the auth plugin of the logged in user or
391    * returns true
392    *
393    * @return bool
394    */
395    public function isCaseSensitive() {
396        if(is_null($this->chained_auth))
397            return parent::isCaseSensitive();
398        else
399            return $this->chained_auth->isCaseSensitive();
400    }
401
402    /**
403    * Sanitize a given username [OPTIONAL]
404    * Forwards the result of the auth plugin of the logged in user or
405    * returns false
406    *
407    *
408    * @author Philipp Neuser <pneuser@physik.fu-berlin.de>
409    * @author Christian Marg <marg@rz.tu-clausthal.de>
410    * @param  string $user username
411    * @return string the cleaned username
412    */
413    public function cleanUser($user) {
414        global $ACT;
415        //print_r($this->chained_auth);
416        if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
417            if(!is_null($this->usermanager_auth))
418                return $this->usermanager_auth->cleanUser($user);
419        } else {
420            if(!is_null($this->chained_auth))
421                return $this->chained_auth->cleanUser($user);
422        }
423        return parent::cleanUser($user);
424    }
425
426    /**
427    * Sanitize a given groupname [OPTIONAL]
428    * Forwards the result of the auth plugin of the logged in user or
429    * returns false
430    *
431    * @author Philipp Neuser <pneuser@physik.fu-berlin.de>
432    * @author Christian Marg <marg@rz.tu-clausthal.de>
433    * @param  string $group groupname
434    * @return string the cleaned groupname
435    */
436    public function cleanGroup($group) {
437        global $ACT;
438        if ($ACT == "admin" && $_REQUEST['page']=="usermanager") {
439            if(!is_null($this->usermanager_auth))
440                return $this->usermanager_auth->cleanGroup($group);
441        } else {
442            if(!is_null($this->chained_auth))
443                return $this->chained_auth->cleanGroup($group);
444        }
445        return parent::cleanGroup($group);
446    }
447
448
449    public function useSessionCache($user) {
450        global $conf;
451        if(is_null($this->chained_auth))
452            return parent::useSessionCache($user);
453        else
454            return $this->chained_auth->useSessionCache($user);
455    }
456
457}
458