[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/Extension/ -> AuthPlugin.php (source)

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