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