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