PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/components/com_jfusionplugins/dokuwiki/auth/basic.class.php

http://jfusion.googlecode.com/
PHP | 462 lines | 190 code | 20 blank | 252 comment | 41 complexity | 6864cc8bf1b97e36c3767fe2ed2ba50a MD5 | raw file
Possible License(s): Apache-2.0
  1. <?php
  2. /**
  3. * Basic authentication class for dokuwiki
  4. *
  5. * PHP version 5
  6. *
  7. * @category JFusion
  8. * @package JFusionPlugins
  9. * @subpackage DokuWiki
  10. * @author JFusion Team <webmaster@jfusion.org>
  11. * @copyright 2008 JFusion. All rights reserved.
  12. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
  13. * @link http://www.jfusion.org
  14. */
  15. // no direct access
  16. defined('_JEXEC') or die('Restricted access');
  17. /**
  18. * Basic authentication class for dokuwiki
  19. *
  20. * @category JFusion
  21. * @package JFusionPlugins
  22. * @subpackage DokuWiki
  23. * @author JFusion Team <webmaster@jfusion.org>
  24. * @copyright 2008 JFusion. All rights reserved.
  25. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
  26. * @link http://www.jfusion.org
  27. */
  28. class doku_auth_basic
  29. {
  30. var $jname = null;
  31. var $success = true;
  32. /**
  33. * Posible things an auth backend module may be able to
  34. * do. The things a backend can do need to be set to true
  35. * in the constructor.
  36. */
  37. var $cando = array('addUser' => false, // can Users be created?
  38. 'delUser' => false, // can Users be deleted?
  39. 'modLogin' => false, // can login names be changed?
  40. 'modPass' => false, // can passwords be changed?
  41. 'modName' => false, // can real names be changed?
  42. 'modMail' => false, // can emails be changed?
  43. 'modGroups' => false, // can groups be changed?
  44. 'getUsers' => false, // can a (filtered) list of users be retrieved?
  45. 'getUserCount' => false, // can the number of users be retrieved?
  46. 'getGroups' => false, // can a list of available groups be retrieved?
  47. 'external' => false, // does the module do external auth checking?
  48. 'logoff' => false, // has the module some special logoff method?
  49. );
  50. /**
  51. * Encrypts a password using the given method and salt
  52. *
  53. * If the selected method needs a salt and none was given, a random one
  54. * is chosen.
  55. *
  56. * The following methods are understood:
  57. *
  58. * smd5 - Salted MD5 hashing
  59. * md5 - Simple MD5 hashing
  60. * sha1 - SHA1 hashing
  61. * ssha - Salted SHA1 hashing
  62. * crypt - Unix crypt
  63. * mysql - MySQL password (old method)
  64. * my411 - MySQL 4.1.1 password
  65. *
  66. * @param string $clear clear password
  67. * @param string $method method to use
  68. * @param string $salt salt added to password
  69. *
  70. * @author Andreas Gohr <andi@splitbrain.org>
  71. * @return string The crypted password
  72. */
  73. function cryptPassword($clear, $method = '', $salt = '')
  74. {
  75. $share = Dokuwiki::getInstance($this->jname);
  76. $conf = $share->getConf();
  77. if (empty($method)) $method = $conf['passcrypt'];
  78. //prepare a salt
  79. if (empty($salt)) $salt = md5(uniqid(rand(), true));
  80. switch (strtolower($method)) {
  81. case 'smd5':
  82. if(defined('CRYPT_MD5') && CRYPT_MD5) return crypt($clear,'$1$'.substr($salt,0,8).'$');
  83. // when crypt can't handle SMD5, falls through to pure PHP implementation
  84. $magic = '1';
  85. case 'apr1':
  86. //from http://de.php.net/manual/en/function.crypt.php#73619 comment by <mikey_nich at hotmail dot com>
  87. if(!$magic) $magic = 'apr1';
  88. $salt = substr($salt,0,8);
  89. $len = strlen($clear);
  90. $text = $clear.'$'.$magic.'$'.$salt;
  91. $bin = pack("H32", md5($clear.$salt.$clear));
  92. for($i = $len; $i > 0; $i -= 16) { $text .= substr($bin, 0, min(16, $i)); }
  93. for($i = $len; $i > 0; $i >>= 1) { $text .= ($i & 1) ? chr(0) : $clear{0}; }
  94. $bin = pack("H32", md5($text));
  95. for($i = 0; $i < 1000; $i++) {
  96. $new = ($i & 1) ? $clear : $bin;
  97. if ($i % 3) $new .= $salt;
  98. if ($i % 7) $new .= $clear;
  99. $new .= ($i & 1) ? $bin : $clear;
  100. $bin = pack("H32", md5($new));
  101. }
  102. $tmp = '';
  103. for ($i = 0; $i < 5; $i++) {
  104. $k = $i + 6;
  105. $j = $i + 12;
  106. if ($j == 16) $j = 5;
  107. $tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
  108. }
  109. $tmp = chr(0).chr(0).$bin[11].$tmp;
  110. $tmp = strtr(strrev(substr(base64_encode($tmp), 2)),
  111. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
  112. "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
  113. return '$'.$magic.'$'.$salt.'$'.$tmp;
  114. case 'md5':
  115. return md5($clear);
  116. case 'sha1':
  117. return sha1($clear);
  118. case 'ssha':
  119. $salt = substr($salt, 0, 4);
  120. return '{SSHA}' . base64_encode(pack("H*", sha1($clear . $salt)) . $salt);
  121. case 'crypt':
  122. return crypt($clear, substr($salt, 0, 2));
  123. case 'mysql':
  124. //from http://www.php.net/mysql comment by <soren at byu dot edu>
  125. $nr = 0x50305735;
  126. $nr2 = 0x12345671;
  127. $add = 7;
  128. $charArr = preg_split("//", $clear);
  129. foreach ($charArr as $char) {
  130. if (($char == '') || ($char == ' ') || ($char == '\t')) continue;
  131. $charVal = ord($char);
  132. $nr^= ((($nr & 63) + $add) * $charVal) + ($nr << 8);
  133. $nr2+= ($nr2 << 8) ^ $nr;
  134. $add+= $charVal;
  135. }
  136. return sprintf("%08x%08x", ($nr & 0x7fffffff), ($nr2 & 0x7fffffff));
  137. case 'my411':
  138. return '*' . sha1(pack("H*", sha1($clear)));
  139. default:
  140. JError::raiseWarning(500, "Unsupported crypt method $method");
  141. }
  142. }
  143. /**
  144. * Verifies a cleartext password against a crypted hash
  145. *
  146. * The method and salt used for the crypted hash is determined automatically
  147. * then the clear text password is crypted using the same method. If both hashs
  148. * match true is is returned else false
  149. *
  150. * @param string $clear username
  151. * @param string $crypt crupt
  152. *
  153. * @author Andreas Gohr <andi@splitbrain.org>
  154. * @return bool
  155. */
  156. function verifyPassword($clear, $crypt)
  157. {
  158. $method = '';
  159. $salt = '';
  160. //determine the used method and salt
  161. $len = strlen($crypt);
  162. if (preg_match('/^\$1\$([^\$]{0,8})\$/', $crypt, $m)) {
  163. $method = 'smd5';
  164. $salt = $m[1];
  165. } elseif (preg_match('/^\$apr1\$([^\$]{0,8})\$/', $crypt, $m)) {
  166. $method = 'apr1';
  167. $salt = $m[1];
  168. } elseif (substr($crypt, 0, 6) == '{SSHA}') {
  169. $method = 'ssha';
  170. $salt = substr(base64_decode(substr($crypt, 6)), 20);
  171. } elseif ($len == 32) {
  172. $method = 'md5';
  173. } elseif ($len == 40) {
  174. $method = 'sha1';
  175. } elseif ($len == 16) {
  176. $method = 'mysql';
  177. } elseif ($len == 41 && $crypt[0] == '*') {
  178. $method = 'my411';
  179. } else {
  180. $method = 'crypt';
  181. $salt = substr($crypt, 0, 2);
  182. }
  183. //crypt and compare
  184. if ($this->cryptPassword($clear, $method, $salt) === $crypt) {
  185. return true;
  186. }
  187. return false;
  188. }
  189. /**
  190. * Constructor.
  191. *
  192. * Carry out sanity checks to ensure the object is
  193. * able to operate. Set capabilities in $this->cando
  194. * array here
  195. *
  196. * Set $this->success to false if checks fail
  197. *
  198. * @author Christopher Smith <chris@jalakai.co.uk>
  199. * @return void
  200. */
  201. function doku_auth_basic()
  202. {
  203. // the base class constructor does nothing, derived class
  204. // constructors do the real work
  205. }
  206. /**
  207. * Capability check. [ DO NOT OVERRIDE ]
  208. *
  209. * Checks the capabilities set in the $this->cando array and
  210. * some pseudo capabilities (shortcutting access to multiple
  211. * ones)
  212. *
  213. * ususal capabilities start with lowercase letter
  214. * shortcut capabilities start with uppercase letter
  215. *
  216. * @param string $cap action
  217. *
  218. * @author Andreas Gohr <andi@splitbrain.org>
  219. * @return bool
  220. */
  221. function canDo($cap)
  222. {
  223. switch ($cap) {
  224. case 'Profile':
  225. // can at least one of the user's properties be changed?
  226. return ($this->cando['modPass'] || $this->cando['modName'] || $this->cando['modMail']);
  227. break;
  228. case 'UserMod':
  229. // can at least anything be changed?
  230. return ($this->cando['modPass'] || $this->cando['modName'] || $this->cando['modMail'] || $this->cando['modLogin'] || $this->cando['modGroups'] || $this->cando['modMail']);
  231. break;
  232. default:
  233. // print a helping message for developers
  234. if (!isset($this->cando[$cap])) {
  235. JError::raiseWarning(500, "Check for unknown capability '$cap' - Do you use an outdated Plugin?");
  236. return false;
  237. }
  238. return $this->cando[$cap];
  239. }
  240. }
  241. /**
  242. * Log off the current user [ OPTIONAL ]
  243. *
  244. * Is run in addition to the ususal logoff method. Should
  245. * only be needed when trustExternal is implemented.
  246. *
  247. * @see auth_logoff()
  248. * @author Andreas Gohr
  249. */
  250. function logOff()
  251. {
  252. }
  253. /**
  254. * Check user+password [ MUST BE OVERRIDDEN ]
  255. *
  256. * Checks if the given user exists and the given
  257. * plaintext password is correct
  258. *
  259. * May be ommited if trustExternal is used.
  260. *
  261. * @param string $user username
  262. * @param string $pass password
  263. *
  264. * @author Andreas Gohr <andi@splitbrain.org>
  265. * @return bool
  266. */
  267. function checkPass($user, $pass)
  268. {
  269. JError::raiseWarning(500, "no valid authorisation system in use");
  270. return false;
  271. }
  272. /**
  273. * Return user info [ MUST BE OVERRIDDEN ]
  274. *
  275. * Returns info about the given user needs to contain
  276. * at least these fields:
  277. *
  278. * name string full name of the user
  279. * mail string email addres of the user
  280. * grps array list of groups the user is in
  281. *
  282. * @param string $user username
  283. *
  284. * @author Andreas Gohr <andi@splitbrain.org>
  285. * @return array containing user data or false
  286. */
  287. function getUserData($user)
  288. {
  289. if (!$this->cando['external']) JError::raiseWarning(500, "no valid authorisation system in use");
  290. return false;
  291. }
  292. /**
  293. * Create a new User [implement only where required/possible]
  294. *
  295. * Returns false if the user already exists, null when an error
  296. * occurred and true if everything went well.
  297. *
  298. * The new user HAS TO be added to the default group by this
  299. * function!
  300. *
  301. * Set addUser capability when implemented
  302. *
  303. * @param string $user username
  304. * @param string $pass password
  305. * @param string $name real name
  306. * @param string $mail email adress
  307. * @param string $grps groups
  308. *
  309. * @author Andreas Gohr <andi@splitbrain.org>
  310. */
  311. function createUser($user, $pass, $name, $mail, $grps = null)
  312. {
  313. JError::raiseWarning(500, "authorisation method does not allow creation of new users");
  314. return null;
  315. }
  316. /**
  317. * Modify user data [implement only where required/possible]
  318. *
  319. * Set the mod* capabilities according to the implemented features
  320. *
  321. * @param string $user nick of the user to be changed
  322. * @param array $changes array of field/value pairs to be changed (password will be clear text)
  323. *
  324. * @author Chris Smith <chris@jalakai.co.uk>
  325. * @return bool
  326. */
  327. function modifyUser($user, $changes)
  328. {
  329. JError::raiseWarning(500, "authorisation method does not allow modifying of user data");
  330. return false;
  331. }
  332. /**
  333. * Delete one or more users [implement only where required/possible]
  334. *
  335. * Set delUser capability when implemented
  336. *
  337. * @param array $users arrat of users to delete
  338. *
  339. * @author Chris Smith <chris@jalakai.co.uk>
  340. * @return int number of users deleted
  341. */
  342. function deleteUsers($users)
  343. {
  344. JError::raiseWarning(500, "authorisation method does not allow deleting of users");
  345. return false;
  346. }
  347. /**
  348. * Return a count of the number of user which meet $filter criteria
  349. * [should be implemented whenever retrieveUsers is implemented]
  350. *
  351. * Set getUserCount capability when implemented
  352. *
  353. * @param array $filter
  354. *
  355. * @author Chris Smith <chris@jalakai.co.uk>
  356. */
  357. function getUserCount($filter = array())
  358. {
  359. JError::raiseWarning(500, "authorisation method does not provide user counts");
  360. return 0;
  361. }
  362. /**
  363. * Bulk retrieval of user data [implement only where required/possible]
  364. *
  365. * Set getUsers capability when implemented
  366. *
  367. * @param string $start index of first user to be returned
  368. * @param string $limit max number of users to be returned
  369. * @param string $filter array of field/pattern pairs, null for no filter
  370. *
  371. * @author Chris Smith <chris@jalakai.co.uk>
  372. * @return array of userinfo (refer getUserData for internal userinfo details)
  373. */
  374. function retrieveUsers($start = 0, $limit = - 1, $filter = null)
  375. {
  376. JError::raiseWarning(500, "authorisation method does not provide user counts");
  377. return array();
  378. }
  379. /**
  380. * Define a group [implement only where required/possible]
  381. *
  382. * Set addGroup capability when implemented
  383. *
  384. * @param string $group group
  385. *
  386. * @author Chris Smith <chris@jalakai.co.uk>
  387. * @return bool
  388. */
  389. function addGroup($group)
  390. {
  391. JError::raiseWarning(500, "authorisation method does not support independent group creation");
  392. return false;
  393. }
  394. /**
  395. * Retrieve groups [implement only where required/possible]
  396. *
  397. * Set getGroups capability when implemented
  398. *
  399. * @param string $start index of first user to be returned
  400. * @param string $limit max number of users to be returned
  401. *
  402. * @author Chris Smith <chris@jalakai.co.uk>
  403. * @return array
  404. */
  405. function retrieveGroups($start = 0, $limit = 0)
  406. {
  407. JError::raiseWarning(500, "authorisation method does not support group list retrieval");
  408. return array();
  409. }
  410. /**
  411. * Check Session Cache validity [implement only where required/possible]
  412. *
  413. * DokuWiki caches user info in the user's session for the timespan defined
  414. * in $conf['securitytimeout'].
  415. *
  416. * This makes sure slow authentication backends do not slow down DokuWiki.
  417. * This also means that changes to the user database will not be reflected
  418. * on currently logged in users.
  419. *
  420. * To accommodate for this, the user manager plugin will touch a reference
  421. * file whenever a change is submitted. This function compares the filetime
  422. * of this reference file with the time stored in the session.
  423. *
  424. * This reference file mechanism does not reflect changes done directly in
  425. * the backend's database through other means than the user manager plugin.
  426. *
  427. * Fast backends might want to return always false, to force rechecks on
  428. * each page load. Others might want to use their own checking here. If
  429. * unsure, do not override.
  430. *
  431. * @param string $user The username
  432. *
  433. * @author Andreas Gohr <andi@splitbrain.org>
  434. * @return bool
  435. */
  436. function useSessionCache($user)
  437. {
  438. global $conf;
  439. return ($_SESSION[DOKU_COOKIE]['auth']['time'] >= @filemtime($conf['cachedir'] . '/sessionpurge'));
  440. }
  441. }
  442. //Setup VIM: ex: et ts=2 enc=utf-8 :