1<?php 2/** 3 * Auth Plugin Prototype 4 * 5 * foundation authorisation class 6 * all auth classes should inherit from this class 7 * 8 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 9 * @author Chris Smith <chris@jalakai.co.uk> 10 * @author Jan Schumann <js@jschumann-it.com> 11 */ 12abstract class DokuWiki_Auth_Plugin extends DokuWiki_Plugin { 13 public $success = true; 14 15 /** 16 * Possible things an auth backend module may be able to 17 * do. The things a backend can do need to be set to true 18 * in the constructor. 19 */ 20 protected $cando = array( 21 'addUser' => false, // can Users be created? 22 'delUser' => false, // can Users be deleted? 23 'modLogin' => false, // can login names be changed? 24 'modPass' => false, // can passwords be changed? 25 'modName' => false, // can real names be changed? 26 'modMail' => false, // can emails be changed? 27 'modGroups' => false, // can groups be changed? 28 'getUsers' => false, // can a (filtered) list of users be retrieved? 29 'getUserCount' => false, // can the number of users be retrieved? 30 'getGroups' => false, // can a list of available groups be retrieved? 31 'external' => false, // does the module do external auth checking? 32 'logout' => true, // can the user logout again? (eg. not possible with HTTP auth) 33 ); 34 35 /** 36 * Constructor. 37 * 38 * Carry out sanity checks to ensure the object is 39 * able to operate. Set capabilities in $this->cando 40 * array here 41 * 42 * For future compatibility, sub classes should always include a call 43 * to parent::__constructor() in their constructors! 44 * 45 * Set $this->success to false if checks fail 46 * 47 * @author Christopher Smith <chris@jalakai.co.uk> 48 */ 49 public function __construct() { 50 // the base class constructor does nothing, derived class 51 // constructors do the real work 52 } 53 54 /** 55 * Available Capabilities. [ DO NOT OVERRIDE ] 56 * 57 * For introspection/debugging 58 * 59 * @author Christopher Smith <chris@jalakai.co.uk> 60 * @return array 61 */ 62 public function getCapabilities(){ 63 return array_keys($this->cando); 64 } 65 66 /** 67 * Capability check. [ DO NOT OVERRIDE ] 68 * 69 * Checks the capabilities set in the $this->cando array and 70 * some pseudo capabilities (shortcutting access to multiple 71 * ones) 72 * 73 * ususal capabilities start with lowercase letter 74 * shortcut capabilities start with uppercase letter 75 * 76 * @author Andreas Gohr <andi@splitbrain.org> 77 * @param string $cap the capability to check 78 * @return bool 79 */ 80 public function canDo($cap) { 81 switch($cap) { 82 case 'Profile': 83 // can at least one of the user's properties be changed? 84 return ($this->cando['modPass'] || 85 $this->cando['modName'] || 86 $this->cando['modMail']); 87 break; 88 case 'UserMod': 89 // can at least anything be changed? 90 return ($this->cando['modPass'] || 91 $this->cando['modName'] || 92 $this->cando['modMail'] || 93 $this->cando['modLogin'] || 94 $this->cando['modGroups'] || 95 $this->cando['modMail']); 96 break; 97 default: 98 // print a helping message for developers 99 if(!isset($this->cando[$cap])) { 100 msg("Check for unknown capability '$cap' - Do you use an outdated Plugin?", -1); 101 } 102 return $this->cando[$cap]; 103 } 104 } 105 106 /** 107 * Trigger the AUTH_USERDATA_CHANGE event and call the modification function. [ DO NOT OVERRIDE ] 108 * 109 * You should use this function instead of calling createUser, modifyUser or 110 * deleteUsers directly. The event handlers can prevent the modification, for 111 * example for enforcing a user name schema. 112 * 113 * @author Gabriel Birke <birke@d-scribe.de> 114 * @param string $type Modification type ('create', 'modify', 'delete') 115 * @param array $params Parameters for the createUser, modifyUser or deleteUsers method. 116 * The content of this array depends on the modification type 117 * @return bool|null|int Result from the modification function or false if an event handler has canceled the action 118 */ 119 public function triggerUserMod($type, $params) { 120 $validTypes = array( 121 'create' => 'createUser', 122 'modify' => 'modifyUser', 123 'delete' => 'deleteUsers' 124 ); 125 if(empty($validTypes[$type])) { 126 return false; 127 } 128 129 $result = false; 130 $eventdata = array('type' => $type, 'params' => $params, 'modification_result' => null); 131 $evt = new Doku_Event('AUTH_USER_CHANGE', $eventdata); 132 if($evt->advise_before(true)) { 133 $result = call_user_func_array(array($this, $validTypes[$type]), $evt->data['params']); 134 $evt->data['modification_result'] = $result; 135 } 136 $evt->advise_after(); 137 unset($evt); 138 return $result; 139 } 140 141 /** 142 * Log off the current user [ OPTIONAL ] 143 * 144 * Is run in addition to the ususal logoff method. Should 145 * only be needed when trustExternal is implemented. 146 * 147 * @see auth_logoff() 148 * @author Andreas Gohr <andi@splitbrain.org> 149 */ 150 public function logOff() { 151 } 152 153 /** 154 * Do all authentication [ OPTIONAL ] 155 * 156 * Set $this->cando['external'] = true when implemented 157 * 158 * If this function is implemented it will be used to 159 * authenticate a user - all other DokuWiki internals 160 * will not be used for authenticating, thus 161 * implementing the checkPass() function is not needed 162 * anymore. 163 * 164 * The function can be used to authenticate against third 165 * party cookies or Apache auth mechanisms and replaces 166 * the auth_login() function 167 * 168 * The function will be called with or without a set 169 * username. If the Username is given it was called 170 * from the login form and the given credentials might 171 * need to be checked. If no username was given it 172 * the function needs to check if the user is logged in 173 * by other means (cookie, environment). 174 * 175 * The function needs to set some globals needed by 176 * DokuWiki like auth_login() does. 177 * 178 * @see auth_login() 179 * @author Andreas Gohr <andi@splitbrain.org> 180 * 181 * @param string $user Username 182 * @param string $pass Cleartext Password 183 * @param bool $sticky Cookie should not expire 184 * @return bool true on successful auth 185 */ 186 public function trustExternal($user, $pass, $sticky = false) { 187 /* some example: 188 189 global $USERINFO; 190 global $conf; 191 $sticky ? $sticky = true : $sticky = false; //sanity check 192 193 // do the checking here 194 195 // set the globals if authed 196 $USERINFO['name'] = 'FIXME'; 197 $USERINFO['mail'] = 'FIXME'; 198 $USERINFO['grps'] = array('FIXME'); 199 $_SERVER['REMOTE_USER'] = $user; 200 $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; 201 $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass; 202 $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; 203 return true; 204 205 */ 206 } 207 208 /** 209 * Check user+password [ MUST BE OVERRIDDEN ] 210 * 211 * Checks if the given user exists and the given 212 * plaintext password is correct 213 * 214 * May be ommited if trustExternal is used. 215 * 216 * @author Andreas Gohr <andi@splitbrain.org> 217 * @param string $user the user name 218 * @param string $pass the clear text password 219 * @return bool 220 */ 221 public function checkPass($user, $pass) { 222 msg("no valid authorisation system in use", -1); 223 return false; 224 } 225 226 /** 227 * Return user info [ MUST BE OVERRIDDEN ] 228 * 229 * Returns info about the given user needs to contain 230 * at least these fields: 231 * 232 * name string full name of the user 233 * mail string email address of the user 234 * grps array list of groups the user is in 235 * 236 * @author Andreas Gohr <andi@splitbrain.org> 237 * @param string $user the user name 238 * @param bool $requireGroups whether or not the returned data must include groups 239 * @return false|array containing user data or false 240 */ 241 public function getUserData($user, $requireGroups=true) { 242 if(!$this->cando['external']) msg("no valid authorisation system in use", -1); 243 return false; 244 } 245 246 /** 247 * Create a new User [implement only where required/possible] 248 * 249 * Returns false if the user already exists, null when an error 250 * occurred and true if everything went well. 251 * 252 * The new user HAS TO be added to the default group by this 253 * function! 254 * 255 * Set addUser capability when implemented 256 * 257 * @author Andreas Gohr <andi@splitbrain.org> 258 * @param string $user 259 * @param string $pass 260 * @param string $name 261 * @param string $mail 262 * @param null|array $grps 263 * @return bool|null 264 */ 265 public function createUser($user, $pass, $name, $mail, $grps = null) { 266 msg("authorisation method does not allow creation of new users", -1); 267 return null; 268 } 269 270 /** 271 * Modify user data [implement only where required/possible] 272 * 273 * Set the mod* capabilities according to the implemented features 274 * 275 * @author Chris Smith <chris@jalakai.co.uk> 276 * @param string $user nick of the user to be changed 277 * @param array $changes array of field/value pairs to be changed (password will be clear text) 278 * @return bool 279 */ 280 public function modifyUser($user, $changes) { 281 msg("authorisation method does not allow modifying of user data", -1); 282 return false; 283 } 284 285 /** 286 * Delete one or more users [implement only where required/possible] 287 * 288 * Set delUser capability when implemented 289 * 290 * @author Chris Smith <chris@jalakai.co.uk> 291 * @param array $users 292 * @return int number of users deleted 293 */ 294 public function deleteUsers($users) { 295 msg("authorisation method does not allow deleting of users", -1); 296 return 0; 297 } 298 299 /** 300 * Return a count of the number of user which meet $filter criteria 301 * [should be implemented whenever retrieveUsers is implemented] 302 * 303 * Set getUserCount capability when implemented 304 * 305 * @author Chris Smith <chris@jalakai.co.uk> 306 * @param array $filter array of field/pattern pairs, empty array for no filter 307 * @return int 308 */ 309 public function getUserCount($filter = array()) { 310 msg("authorisation method does not provide user counts", -1); 311 return 0; 312 } 313 314 /** 315 * Bulk retrieval of user data [implement only where required/possible] 316 * 317 * Set getUsers capability when implemented 318 * 319 * @author Chris Smith <chris@jalakai.co.uk> 320 * @param int $start index of first user to be returned 321 * @param int $limit max number of users to be returned, 0 for unlimited 322 * @param array $filter array of field/pattern pairs, null for no filter 323 * @return array list of userinfo (refer getUserData for internal userinfo details) 324 */ 325 public function retrieveUsers($start = 0, $limit = 0, $filter = null) { 326 msg("authorisation method does not support mass retrieval of user data", -1); 327 return array(); 328 } 329 330 /** 331 * Define a group [implement only where required/possible] 332 * 333 * Set addGroup capability when implemented 334 * 335 * @author Chris Smith <chris@jalakai.co.uk> 336 * @param string $group 337 * @return bool 338 */ 339 public function addGroup($group) { 340 msg("authorisation method does not support independent group creation", -1); 341 return false; 342 } 343 344 /** 345 * Retrieve groups [implement only where required/possible] 346 * 347 * Set getGroups capability when implemented 348 * 349 * @author Chris Smith <chris@jalakai.co.uk> 350 * @param int $start 351 * @param int $limit 352 * @return array 353 */ 354 public function retrieveGroups($start = 0, $limit = 0) { 355 msg("authorisation method does not support group list retrieval", -1); 356 return array(); 357 } 358 359 /** 360 * Return case sensitivity of the backend [OPTIONAL] 361 * 362 * When your backend is caseinsensitive (eg. you can login with USER and 363 * user) then you need to overwrite this method and return false 364 * 365 * @return bool 366 */ 367 public function isCaseSensitive() { 368 return true; 369 } 370 371 /** 372 * Sanitize a given username [OPTIONAL] 373 * 374 * This function is applied to any user name that is given to 375 * the backend and should also be applied to any user name within 376 * the backend before returning it somewhere. 377 * 378 * This should be used to enforce username restrictions. 379 * 380 * @author Andreas Gohr <andi@splitbrain.org> 381 * @param string $user username 382 * @return string the cleaned username 383 */ 384 public function cleanUser($user) { 385 return $user; 386 } 387 388 /** 389 * Sanitize a given groupname [OPTIONAL] 390 * 391 * This function is applied to any groupname that is given to 392 * the backend and should also be applied to any groupname within 393 * the backend before returning it somewhere. 394 * 395 * This should be used to enforce groupname restrictions. 396 * 397 * Groupnames are to be passed without a leading '@' here. 398 * 399 * @author Andreas Gohr <andi@splitbrain.org> 400 * @param string $group groupname 401 * @return string the cleaned groupname 402 */ 403 public function cleanGroup($group) { 404 return $group; 405 } 406 407 /** 408 * Check Session Cache validity [implement only where required/possible] 409 * 410 * DokuWiki caches user info in the user's session for the timespan defined 411 * in $conf['auth_security_timeout']. 412 * 413 * This makes sure slow authentication backends do not slow down DokuWiki. 414 * This also means that changes to the user database will not be reflected 415 * on currently logged in users. 416 * 417 * To accommodate for this, the user manager plugin will touch a reference 418 * file whenever a change is submitted. This function compares the filetime 419 * of this reference file with the time stored in the session. 420 * 421 * This reference file mechanism does not reflect changes done directly in 422 * the backend's database through other means than the user manager plugin. 423 * 424 * Fast backends might want to return always false, to force rechecks on 425 * each page load. Others might want to use their own checking here. If 426 * unsure, do not override. 427 * 428 * @param string $user - The username 429 * @author Andreas Gohr <andi@splitbrain.org> 430 * @return bool 431 */ 432 public function useSessionCache($user) { 433 global $conf; 434 return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'].'/sessionpurge')); 435 } 436} 437