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