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" && isset($_REQUEST['page']) && $_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 global $INPUT; 172 foreach($this->chained_plugins as $module) { 173 if($module[1]->canDo('external') && $module[1]->trustExternal($user, $pass, $sticky)) { 174 $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0]; 175 $this->chained_auth = $module[1]; 176 return true; 177 } 178 } 179 $evdata = array( 180 'user' => $INPUT->str('u'), 181 'password' => $INPUT->str('p'), 182 'sticky' => $INPUT->bool('r'), 183 'silent' => $INPUT->bool('http_credentials') 184 ); 185 trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper'); 186 return false; 187 } 188 189 /** 190 * Check user+password [ MUST BE OVERRIDDEN ] 191 * 192 * Checks if the given user exists in one of the plugins and checks 193 * against the given password. The first plugin returning true becomes 194 * auth plugin of the user session. 195 * 196 * @author Philipp Neuser <pneuser@physik.fu-berlin.de 197 * @author Christian Marg <marg@rz.tu-clausthal.de> 198 * @param string $user the user name 199 * @param string $pass the clear text password 200 * @return bool 201 */ 202 public function checkPass($user, $pass) { 203 //debug 204 // print_r($this->chained_plugins); 205 if(!is_null($this->chained_auth)) 206 return $this->chained_auth->checkPass($user, $pass); 207 foreach($this->chained_plugins as $module) { 208 if($module[1]->canDo('external') && $module[1]->trustExternal($user, $pass)) { 209 $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0]; 210 $this->chained_auth = $module[1]; 211 return true; 212 } 213 if($module[1]->checkPass($user, $pass)) { 214 $_SESSION[DOKU_COOKIE]['plugin']['authchained']['module'] = $module[0]; 215 $this->chained_auth = $module[1]; 216 return true; 217 } 218 } 219 return false; 220 } 221 222 /** 223 * Forwards the result of the auth plugin of the logged in user or 224 * checks all plugins if the users exists. The first plugin returning 225 * data is used. 226 * 227 * name string full name of the user 228 * mail string email addres of the user 229 * grps array list of groups the user is in 230 * 231 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 232 * @author Christian Marg <marg@rz.tu-clausthal.de> 233 * @param string $user the user name 234 * @return array containing user data or false 235 */ 236 public function getUserData($user, $requireGroups=true) { 237 global $ACT, $INPUT; 238 239 //if(!$this->cando['external']) msg("no valid authorisation system in use", -1); 240 // echo "TESTSETEST"; 241 242 //print_r($this->chained_auth); 243 if ($ACT == "admin" && isset($_REQUEST['page']) && $_REQUEST['page']=="usermanager") { 244 if(!is_null($this->usermanager_auth)) 245 return $this->usermanager_auth->getUserData($user); 246 } 247 248 if(is_null($this->chained_auth)||(!is_null($INPUT->server) && $user != $INPUT->server->str('REMOTE_USER'))) { 249 foreach($this->chained_plugins as $module) { 250 $tmp_array = $module[1]->getUserData($user); 251 if(!is_bool($tmp_array)) 252 $tmp_chk_arr =array_filter($tmp_array); 253 if(!empty($tmp_chk_arr) && $tmp_array) 254 return $tmp_array; 255 } 256 return false; 257 } else { 258 return $this->chained_auth->getUserData($user); 259 } 260 } 261 262 /** 263 * Forwards the result of the auth plugin of the logged in user or 264 * returns null. 265 * 266 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 267 * @author Christian Marg <marg@rz.tu-clausthal.de> 268 * @param string $user 269 * @param string $pass 270 * @param string $name 271 * @param string $mail 272 * @param null|array $grps 273 * @return bool|null 274 */ 275 public function createUser($user, $pass, $name, $mail, $grps = null) { 276 if(!is_null($this->usermanager_auth) && $this->canDo('addUser')) { 277 return $this->usermanager_auth->createUser($user, $pass, $name, $mail, $grps); 278 } else { 279 msg("authorisation method does not allow creation of new users", -1); 280 return null; 281 } 282 } 283 284 /** 285 * Forwards the result of the auth plugin of the logged in user or 286 * returns false 287 * 288 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 289 * @author Christian Marg <marg@rz.tu-clausthal.de> 290 * @param string $user nick of the user to be changed 291 * @param array $changes array of field/value pairs to be changed (password will be clear text) 292 * @return bool 293 */ 294 public function modifyUser($user, $changes) { 295 if(!is_null($this->usermanager_auth) && $this->canDo('UserMod') ) { 296 return $this->usermanager_auth->modifyUser($user, $changes); 297 } else { 298 msg("authorisation method does not allow modifying of user data", -1); 299 return null; 300 } 301 } 302 303 /** 304 * Forwards the result of the auth plugin of the logged in user or 305 * returns false 306 * 307 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 308 * @author Christian Marg <marg@rz.tu-clausthal.de> 309 * @param array $users 310 * @return int number of users deleted 311 */ 312 public function deleteUsers($users) { 313 if(!is_null($this->usermanager_auth) && $this->canDo('delUser') ) { 314 return $this->usermanager_auth->deleteUsers($users); 315 }else{ 316 msg("authorisation method does not allow deleting of users", -1); 317 return false; 318 } 319 } 320 321 /** 322 * Forwards the result of the auth plugin of the logged in user or 323 * returns 0 324 * 325 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 326 * @author Christian Marg <marg@rz.tu-clausthal.de> 327 * @param array $filter array of field/pattern pairs, empty array for no filter 328 * @return int 329 */ 330 public function getUserCount($filter = array()) { 331 if(!is_null($this->usermanager_auth) && $this->canDo('getUserCount') ){ 332 return $this->usermanager_auth->getUserCount($filter); 333 } else { 334 msg("authorisation method does not provide user counts", -1); 335 return 0; 336 } 337 } 338 339 /** 340 * Forwards the result of the auth plugin of the logged in user or 341 * returns empty array 342 * 343 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 344 * @author Christian Marg <marg@rz.tu-clausthal.de> 345 * @param int $start index of first user to be returned 346 * @param int $limit max number of users to be returned 347 * @param array $filter array of field/pattern pairs, null for no filter 348 * @return array list of userinfo (refer getUserData for internal userinfo details) 349 */ 350 public function retrieveUsers($start = 0, $limit = -1, $filter = null) { 351 if(!is_null($this->usermanager_auth) && $this->canDo('getUsers') ) { 352 //msg("RetrieveUsers is using ".get_class($this->usermanager_auth)); 353 return $this->usermanager_auth->retrieveUsers($start, $limit, $filter); 354 } else { 355 msg("authorisation method does not support mass retrievals", -1); 356 return array(); 357 } 358 } 359 360 /** 361 * Forwards the result of the auth plugin of the logged in user or 362 * returns false 363 * 364 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 365 * @author Christian Marg <marg@rz.tu-clausthal.de> 366 * @param string $group 367 * @return bool 368 */ 369 public function addGroup($group) { 370 if(!is_null($this->usermanager_auth) && $this->canDo('addGroup') ) { 371 return $this->usermanager_auth->addGroup($group); 372 } else { 373 msg("authorisation method does not support independent group creation", -1); 374 return false; 375 } 376 } 377 378 /** 379 * Forwards the result of the auth plugin of the logged in user or 380 * returns empty array 381 * 382 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 383 * @author Christian Marg <marg@rz.tu-clausthal.de> 384 * @param int $start 385 * @param int $limit 386 * @return array 387 */ 388 public function retrieveGroups($start = 0, $limit = 0) { 389 if(!is_null($this->usermanager_auth) && $this->canDo('getGroups') ) { 390 return $this->usermanager_auth->retrieveGroups($start,$limit); 391 } else { 392 msg("authorisation method does not support group list retrieval", -1); 393 return array(); 394 } 395 } 396 397 /** 398 * Forwards the result of the auth plugin of the logged in user or 399 * returns true 400 * 401 * @return bool 402 */ 403 public function isCaseSensitive() { 404 if(is_null($this->chained_auth)) 405 return parent::isCaseSensitive(); 406 else 407 return $this->chained_auth->isCaseSensitive(); 408 } 409 410 /** 411 * Sanitize a given username [OPTIONAL] 412 * Forwards the result of the auth plugin of the logged in user or 413 * returns false 414 * 415 * 416 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 417 * @author Christian Marg <marg@rz.tu-clausthal.de> 418 * @param string $user username 419 * @return string the cleaned username 420 */ 421 public function cleanUser($user) { 422 global $ACT; 423 //print_r($this->chained_auth); 424 if ($ACT == "admin" && isset($_REQUEST['page']) && $_REQUEST['page']=="usermanager") { 425 if(!is_null($this->usermanager_auth)) 426 return $this->usermanager_auth->cleanUser($user); 427 } else { 428 if(!is_null($this->chained_auth)) 429 return $this->chained_auth->cleanUser($user); 430 } 431 return parent::cleanUser($user); 432 } 433 434 /** 435 * Sanitize a given groupname [OPTIONAL] 436 * Forwards the result of the auth plugin of the logged in user or 437 * returns false 438 * 439 * @author Philipp Neuser <pneuser@physik.fu-berlin.de> 440 * @author Christian Marg <marg@rz.tu-clausthal.de> 441 * @param string $group groupname 442 * @return string the cleaned groupname 443 */ 444 public function cleanGroup($group) { 445 global $ACT; 446 if ($ACT == "admin" && isset($_REQUEST['page']) && $_REQUEST['page']=="usermanager") { 447 if(!is_null($this->usermanager_auth)) 448 return $this->usermanager_auth->cleanGroup($group); 449 } else { 450 if(!is_null($this->chained_auth)) 451 return $this->chained_auth->cleanGroup($group); 452 } 453 return parent::cleanGroup($group); 454 } 455 456 457 public function useSessionCache($user) { 458 global $conf; 459 if(is_null($this->chained_auth)) 460 return parent::useSessionCache($user); 461 else 462 return $this->chained_auth->useSessionCache($user); 463 } 464 465} 466