PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/wiki/inc/auth/plain.class.php

https://github.com/godber/PHXdata-Website
PHP | 328 lines | 169 code | 54 blank | 105 comment | 41 complexity | a002a1a176c008e610edbabd4125134a MD5 | raw file
  1. <?php
  2. /**
  3. * Plaintext authentication backend
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Andreas Gohr <andi@splitbrain.org>
  7. * @author Chris Smith <chris@jalakai.co.uk>
  8. */
  9. class auth_plain extends auth_basic {
  10. var $users = null;
  11. var $_pattern = array();
  12. /**
  13. * Constructor
  14. *
  15. * Carry out sanity checks to ensure the object is
  16. * able to operate. Set capabilities.
  17. *
  18. * @author Christopher Smith <chris@jalakai.co.uk>
  19. */
  20. function auth_plain() {
  21. global $config_cascade;
  22. if (!@is_readable($config_cascade['plainauth.users']['default'])){
  23. $this->success = false;
  24. }else{
  25. if(@is_writable($config_cascade['plainauth.users']['default'])){
  26. $this->cando['addUser'] = true;
  27. $this->cando['delUser'] = true;
  28. $this->cando['modLogin'] = true;
  29. $this->cando['modPass'] = true;
  30. $this->cando['modName'] = true;
  31. $this->cando['modMail'] = true;
  32. $this->cando['modGroups'] = true;
  33. }
  34. $this->cando['getUsers'] = true;
  35. $this->cando['getUserCount'] = true;
  36. }
  37. }
  38. /**
  39. * Check user+password [required auth function]
  40. *
  41. * Checks if the given user exists and the given
  42. * plaintext password is correct
  43. *
  44. * @author Andreas Gohr <andi@splitbrain.org>
  45. * @return bool
  46. */
  47. function checkPass($user,$pass){
  48. $userinfo = $this->getUserData($user);
  49. if ($userinfo === false) return false;
  50. return auth_verifyPassword($pass,$this->users[$user]['pass']);
  51. }
  52. /**
  53. * Return user info
  54. *
  55. * Returns info about the given user needs to contain
  56. * at least these fields:
  57. *
  58. * name string full name of the user
  59. * mail string email addres of the user
  60. * grps array list of groups the user is in
  61. *
  62. * @author Andreas Gohr <andi@splitbrain.org>
  63. */
  64. function getUserData($user){
  65. if($this->users === null) $this->_loadUserData();
  66. return isset($this->users[$user]) ? $this->users[$user] : false;
  67. }
  68. /**
  69. * Create a new User
  70. *
  71. * Returns false if the user already exists, null when an error
  72. * occurred and true if everything went well.
  73. *
  74. * The new user will be added to the default group by this
  75. * function if grps are not specified (default behaviour).
  76. *
  77. * @author Andreas Gohr <andi@splitbrain.org>
  78. * @author Chris Smith <chris@jalakai.co.uk>
  79. */
  80. function createUser($user,$pwd,$name,$mail,$grps=null){
  81. global $conf;
  82. global $config_cascade;
  83. // user mustn't already exist
  84. if ($this->getUserData($user) !== false) return false;
  85. $pass = auth_cryptPassword($pwd);
  86. // set default group if no groups specified
  87. if (!is_array($grps)) $grps = array($conf['defaultgroup']);
  88. // prepare user line
  89. $groups = join(',',$grps);
  90. $userline = join(':',array($user,$pass,$name,$mail,$groups))."\n";
  91. if (io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) {
  92. $this->users[$user] = compact('pass','name','mail','grps');
  93. return $pwd;
  94. }
  95. msg('The '.$config_cascade['plainauth.users']['default'].
  96. ' file is not writable. Please inform the Wiki-Admin',-1);
  97. return null;
  98. }
  99. /**
  100. * Modify user data
  101. *
  102. * @author Chris Smith <chris@jalakai.co.uk>
  103. * @param $user nick of the user to be changed
  104. * @param $changes array of field/value pairs to be changed (password will be clear text)
  105. * @return bool
  106. */
  107. function modifyUser($user, $changes) {
  108. global $conf;
  109. global $ACT;
  110. global $INFO;
  111. global $config_cascade;
  112. // sanity checks, user must already exist and there must be something to change
  113. if (($userinfo = $this->getUserData($user)) === false) return false;
  114. if (!is_array($changes) || !count($changes)) return true;
  115. // update userinfo with new data, remembering to encrypt any password
  116. $newuser = $user;
  117. foreach ($changes as $field => $value) {
  118. if ($field == 'user') {
  119. $newuser = $value;
  120. continue;
  121. }
  122. if ($field == 'pass') $value = auth_cryptPassword($value);
  123. $userinfo[$field] = $value;
  124. }
  125. $groups = join(',',$userinfo['grps']);
  126. $userline = join(':',array($newuser, $userinfo['pass'], $userinfo['name'], $userinfo['mail'], $groups))."\n";
  127. if (!$this->deleteUsers(array($user))) {
  128. msg('Unable to modify user data. Please inform the Wiki-Admin',-1);
  129. return false;
  130. }
  131. if (!io_saveFile($config_cascade['plainauth.users']['default'],$userline,true)) {
  132. msg('There was an error modifying your user data. You should register again.',-1);
  133. // FIXME, user has been deleted but not recreated, should force a logout and redirect to login page
  134. $ACT == 'register';
  135. return false;
  136. }
  137. $this->users[$newuser] = $userinfo;
  138. return true;
  139. }
  140. /**
  141. * Remove one or more users from the list of registered users
  142. *
  143. * @author Christopher Smith <chris@jalakai.co.uk>
  144. * @param array $users array of users to be deleted
  145. * @return int the number of users deleted
  146. */
  147. function deleteUsers($users) {
  148. global $config_cascade;
  149. if (!is_array($users) || empty($users)) return 0;
  150. if ($this->users === null) $this->_loadUserData();
  151. $deleted = array();
  152. foreach ($users as $user) {
  153. if (isset($this->users[$user])) $deleted[] = preg_quote($user,'/');
  154. }
  155. if (empty($deleted)) return 0;
  156. $pattern = '/^('.join('|',$deleted).'):/';
  157. if (io_deleteFromFile($config_cascade['plainauth.users']['default'],$pattern,true)) {
  158. foreach ($deleted as $user) unset($this->users[$user]);
  159. return count($deleted);
  160. }
  161. // problem deleting, reload the user list and count the difference
  162. $count = count($this->users);
  163. $this->_loadUserData();
  164. $count -= count($this->users);
  165. return $count;
  166. }
  167. /**
  168. * Return a count of the number of user which meet $filter criteria
  169. *
  170. * @author Chris Smith <chris@jalakai.co.uk>
  171. */
  172. function getUserCount($filter=array()) {
  173. if($this->users === null) $this->_loadUserData();
  174. if (!count($filter)) return count($this->users);
  175. $count = 0;
  176. $this->_constructPattern($filter);
  177. foreach ($this->users as $user => $info) {
  178. $count += $this->_filter($user, $info);
  179. }
  180. return $count;
  181. }
  182. /**
  183. * Bulk retrieval of user data
  184. *
  185. * @author Chris Smith <chris@jalakai.co.uk>
  186. * @param start index of first user to be returned
  187. * @param limit max number of users to be returned
  188. * @param filter array of field/pattern pairs
  189. * @return array of userinfo (refer getUserData for internal userinfo details)
  190. */
  191. function retrieveUsers($start=0,$limit=0,$filter=array()) {
  192. if ($this->users === null) $this->_loadUserData();
  193. ksort($this->users);
  194. $i = 0;
  195. $count = 0;
  196. $out = array();
  197. $this->_constructPattern($filter);
  198. foreach ($this->users as $user => $info) {
  199. if ($this->_filter($user, $info)) {
  200. if ($i >= $start) {
  201. $out[$user] = $info;
  202. $count++;
  203. if (($limit > 0) && ($count >= $limit)) break;
  204. }
  205. $i++;
  206. }
  207. }
  208. return $out;
  209. }
  210. /**
  211. * Only valid pageid's (no namespaces) for usernames
  212. */
  213. function cleanUser($user){
  214. global $conf;
  215. return cleanID(str_replace(':',$conf['sepchar'],$user));
  216. }
  217. /**
  218. * Only valid pageid's (no namespaces) for groupnames
  219. */
  220. function cleanGroup($group){
  221. global $conf;
  222. return cleanID(str_replace(':',$conf['sepchar'],$group));
  223. }
  224. /**
  225. * Load all user data
  226. *
  227. * loads the user file into a datastructure
  228. *
  229. * @author Andreas Gohr <andi@splitbrain.org>
  230. */
  231. function _loadUserData(){
  232. global $config_cascade;
  233. $this->users = array();
  234. if(!@file_exists($config_cascade['plainauth.users']['default'])) return;
  235. $lines = file($config_cascade['plainauth.users']['default']);
  236. foreach($lines as $line){
  237. $line = preg_replace('/#.*$/','',$line); //ignore comments
  238. $line = trim($line);
  239. if(empty($line)) continue;
  240. $row = explode(":",$line,5);
  241. $groups = array_values(array_filter(explode(",",$row[4])));
  242. $this->users[$row[0]]['pass'] = $row[1];
  243. $this->users[$row[0]]['name'] = urldecode($row[2]);
  244. $this->users[$row[0]]['mail'] = $row[3];
  245. $this->users[$row[0]]['grps'] = $groups;
  246. }
  247. }
  248. /**
  249. * return 1 if $user + $info match $filter criteria, 0 otherwise
  250. *
  251. * @author Chris Smith <chris@jalakai.co.uk>
  252. */
  253. function _filter($user, $info) {
  254. // FIXME
  255. foreach ($this->_pattern as $item => $pattern) {
  256. if ($item == 'user') {
  257. if (!preg_match($pattern, $user)) return 0;
  258. } else if ($item == 'grps') {
  259. if (!count(preg_grep($pattern, $info['grps']))) return 0;
  260. } else {
  261. if (!preg_match($pattern, $info[$item])) return 0;
  262. }
  263. }
  264. return 1;
  265. }
  266. function _constructPattern($filter) {
  267. $this->_pattern = array();
  268. foreach ($filter as $item => $pattern) {
  269. // $this->_pattern[$item] = '/'.preg_quote($pattern,"/").'/i'; // don't allow regex characters
  270. $this->_pattern[$item] = '/'.str_replace('/','\/',$pattern).'/i'; // allow regex characters
  271. }
  272. }
  273. }
  274. //Setup VIM: ex: et ts=2 enc=utf-8 :