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