1f64dbc90SAndreas Gohr<?php 2f64dbc90SAndreas Gohr/** 3f64dbc90SAndreas Gohr * DokuWiki Plugin authpdo (Auth Component) 4f64dbc90SAndreas Gohr * 5f64dbc90SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6f64dbc90SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 7f64dbc90SAndreas Gohr */ 8f64dbc90SAndreas Gohr 9f64dbc90SAndreas Gohr// must be run within Dokuwiki 10f64dbc90SAndreas Gohrif(!defined('DOKU_INC')) die(); 11f64dbc90SAndreas Gohr 12f64dbc90SAndreas Gohrclass auth_plugin_authpdo extends DokuWiki_Auth_Plugin { 13f64dbc90SAndreas Gohr 14f64dbc90SAndreas Gohr /** @var PDO */ 15f64dbc90SAndreas Gohr protected $pdo; 16f64dbc90SAndreas Gohr 17f64dbc90SAndreas Gohr /** 18f64dbc90SAndreas Gohr * Constructor. 19f64dbc90SAndreas Gohr */ 20f64dbc90SAndreas Gohr public function __construct() { 21f64dbc90SAndreas Gohr parent::__construct(); // for compatibility 22f64dbc90SAndreas Gohr 23f64dbc90SAndreas Gohr if(!class_exists('PDO')) { 24f64dbc90SAndreas Gohr $this->_debug('PDO extension for PHP not found.', -1, __LINE__); 25f64dbc90SAndreas Gohr $this->success = false; 26f64dbc90SAndreas Gohr return; 27f64dbc90SAndreas Gohr } 28f64dbc90SAndreas Gohr 29f64dbc90SAndreas Gohr if(!$this->getConf('dsn')) { 30f64dbc90SAndreas Gohr $this->_debug('No DSN specified', -1, __LINE__); 31f64dbc90SAndreas Gohr $this->success = false; 32f64dbc90SAndreas Gohr return; 33f64dbc90SAndreas Gohr } 34f64dbc90SAndreas Gohr 35f64dbc90SAndreas Gohr try { 36f64dbc90SAndreas Gohr $this->pdo = new PDO( 37f64dbc90SAndreas Gohr $this->getConf('dsn'), 38f64dbc90SAndreas Gohr $this->getConf('user'), 39f64dbc90SAndreas Gohr $this->getConf('pass'), 40f64dbc90SAndreas Gohr array( 4170a89417SAndreas Gohr PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // always fetch as array 4270a89417SAndreas Gohr PDO::ATTR_EMULATE_PREPARES => true, // emulating prepares allows us to reuse param names 435de3a6a5SAndreas Gohr PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes 44f64dbc90SAndreas Gohr ) 45f64dbc90SAndreas Gohr ); 46f64dbc90SAndreas Gohr } catch(PDOException $e) { 47f64dbc90SAndreas Gohr $this->_debug($e); 48f64dbc90SAndreas Gohr $this->success = false; 49f64dbc90SAndreas Gohr return; 50f64dbc90SAndreas Gohr } 51f64dbc90SAndreas Gohr 52f64dbc90SAndreas Gohr // FIXME set capabilities accordingly 53f64dbc90SAndreas Gohr //$this->cando['addUser'] = false; // can Users be created? 54f64dbc90SAndreas Gohr //$this->cando['delUser'] = false; // can Users be deleted? 55f64dbc90SAndreas Gohr //$this->cando['modLogin'] = false; // can login names be changed? 56f64dbc90SAndreas Gohr //$this->cando['modPass'] = false; // can passwords be changed? 57f64dbc90SAndreas Gohr //$this->cando['modName'] = false; // can real names be changed? 58f64dbc90SAndreas Gohr //$this->cando['modMail'] = false; // can emails be changed? 59f64dbc90SAndreas Gohr //$this->cando['modGroups'] = false; // can groups be changed? 60f64dbc90SAndreas Gohr //$this->cando['getUsers'] = false; // can a (filtered) list of users be retrieved? 61f64dbc90SAndreas Gohr //$this->cando['getUserCount']= false; // can the number of users be retrieved? 62f64dbc90SAndreas Gohr //$this->cando['getGroups'] = false; // can a list of available groups be retrieved? 63f64dbc90SAndreas Gohr //$this->cando['external'] = false; // does the module do external auth checking? 64f64dbc90SAndreas Gohr //$this->cando['logout'] = true; // can the user logout again? (eg. not possible with HTTP auth) 65f64dbc90SAndreas Gohr 66f64dbc90SAndreas Gohr // FIXME intialize your auth system and set success to true, if successful 67f64dbc90SAndreas Gohr $this->success = true; 68*e19be516SAndreas Gohr 69f64dbc90SAndreas Gohr } 70f64dbc90SAndreas Gohr 71f64dbc90SAndreas Gohr /** 72f64dbc90SAndreas Gohr * Check user+password 73f64dbc90SAndreas Gohr * 74f64dbc90SAndreas Gohr * @param string $user the user name 75f64dbc90SAndreas Gohr * @param string $pass the clear text password 76f64dbc90SAndreas Gohr * @return bool 77f64dbc90SAndreas Gohr */ 78f64dbc90SAndreas Gohr public function checkPass($user, $pass) { 79f64dbc90SAndreas Gohr 80f64dbc90SAndreas Gohr $data = $this->_selectUser($user); 81f64dbc90SAndreas Gohr if($data == false) return false; 82f64dbc90SAndreas Gohr 83f64dbc90SAndreas Gohr if(isset($data['hash'])) { 84f64dbc90SAndreas Gohr // hashed password 85f64dbc90SAndreas Gohr $passhash = new PassHash(); 86f64dbc90SAndreas Gohr return $passhash->verify_hash($pass, $data['hash']); 87f64dbc90SAndreas Gohr } else { 88f64dbc90SAndreas Gohr // clear text password in the database O_o 89f64dbc90SAndreas Gohr return ($pass == $data['clear']); 90f64dbc90SAndreas Gohr } 91f64dbc90SAndreas Gohr } 92f64dbc90SAndreas Gohr 93f64dbc90SAndreas Gohr /** 94f64dbc90SAndreas Gohr * Return user info 95f64dbc90SAndreas Gohr * 96f64dbc90SAndreas Gohr * Returns info about the given user needs to contain 97f64dbc90SAndreas Gohr * at least these fields: 98f64dbc90SAndreas Gohr * 99f64dbc90SAndreas Gohr * name string full name of the user 100f64dbc90SAndreas Gohr * mail string email addres of the user 101f64dbc90SAndreas Gohr * grps array list of groups the user is in 102f64dbc90SAndreas Gohr * 103f64dbc90SAndreas Gohr * @param string $user the user name 104f64dbc90SAndreas Gohr * @param bool $requireGroups whether or not the returned data must include groups 105f64dbc90SAndreas Gohr * @return array containing user data or false 106f64dbc90SAndreas Gohr */ 107f64dbc90SAndreas Gohr public function getUserData($user, $requireGroups = true) { 108f64dbc90SAndreas Gohr $data = $this->_selectUser($user); 109f64dbc90SAndreas Gohr if($data == false) return false; 110f64dbc90SAndreas Gohr 11170a89417SAndreas Gohr if(isset($data['hash'])) unset($data['hash']); 11270a89417SAndreas Gohr if(isset($data['clean'])) unset($data['clean']); 113f64dbc90SAndreas Gohr 11470a89417SAndreas Gohr if($requireGroups) { 11570a89417SAndreas Gohr $data['grps'] = $this->_selectUserGroups($data); 1165de3a6a5SAndreas Gohr if($data['grps'] === false) return false; 117f64dbc90SAndreas Gohr } 118f64dbc90SAndreas Gohr 119f64dbc90SAndreas Gohr return $data; 120f64dbc90SAndreas Gohr } 121f64dbc90SAndreas Gohr 122f64dbc90SAndreas Gohr /** 123f64dbc90SAndreas Gohr * Create a new User [implement only where required/possible] 124f64dbc90SAndreas Gohr * 125f64dbc90SAndreas Gohr * Returns false if the user already exists, null when an error 126f64dbc90SAndreas Gohr * occurred and true if everything went well. 127f64dbc90SAndreas Gohr * 128f64dbc90SAndreas Gohr * The new user HAS TO be added to the default group by this 129f64dbc90SAndreas Gohr * function! 130f64dbc90SAndreas Gohr * 131f64dbc90SAndreas Gohr * Set addUser capability when implemented 132f64dbc90SAndreas Gohr * 133f64dbc90SAndreas Gohr * @param string $user 1345de3a6a5SAndreas Gohr * @param string $clear 135f64dbc90SAndreas Gohr * @param string $name 136f64dbc90SAndreas Gohr * @param string $mail 137f64dbc90SAndreas Gohr * @param null|array $grps 138f64dbc90SAndreas Gohr * @return bool|null 139f64dbc90SAndreas Gohr */ 1405de3a6a5SAndreas Gohr public function createUser($user, $clear, $name, $mail, $grps = null) { 1415de3a6a5SAndreas Gohr global $conf; 1425de3a6a5SAndreas Gohr 1435de3a6a5SAndreas Gohr if(($info = $this->getUserData($user, false)) !== false) { 1445de3a6a5SAndreas Gohr msg($this->getLang('userexists'), -1); 1455de3a6a5SAndreas Gohr return false; // user already exists 1465de3a6a5SAndreas Gohr } 1475de3a6a5SAndreas Gohr 1485de3a6a5SAndreas Gohr // prepare data 1495de3a6a5SAndreas Gohr if($grps == null) $grps = array(); 1505de3a6a5SAndreas Gohr $grps[] = $conf['defaultgroup']; 1515de3a6a5SAndreas Gohr $grps = array_unique($grps); 1525de3a6a5SAndreas Gohr $hash = auth_cryptPassword($clear); 1535de3a6a5SAndreas Gohr $userdata = compact('user', 'clear', 'hash', 'name', 'mail'); 1545de3a6a5SAndreas Gohr 1555de3a6a5SAndreas Gohr // action protected by transaction 1565de3a6a5SAndreas Gohr $this->pdo->beginTransaction(); 1575de3a6a5SAndreas Gohr { 1585de3a6a5SAndreas Gohr // insert the user 1595de3a6a5SAndreas Gohr $ok = $this->_query($this->getConf('insert-user'), $userdata); 1605de3a6a5SAndreas Gohr if($ok === false) goto FAIL; 1615de3a6a5SAndreas Gohr $userdata = $this->getUserData($user, false); 1625de3a6a5SAndreas Gohr if($userdata === false) goto FAIL; 1635de3a6a5SAndreas Gohr 1645de3a6a5SAndreas Gohr // create all groups that do not exist, the refetch the groups 1655de3a6a5SAndreas Gohr $allgroups = $this->_selectGroups(); 1665de3a6a5SAndreas Gohr foreach($grps as $group) { 1675de3a6a5SAndreas Gohr if(!isset($allgroups[$group])) { 1685de3a6a5SAndreas Gohr $ok = $this->_insertGroup($group); 1695de3a6a5SAndreas Gohr if($ok === false) goto FAIL; 1705de3a6a5SAndreas Gohr } 1715de3a6a5SAndreas Gohr } 1725de3a6a5SAndreas Gohr $allgroups = $this->_selectGroups(); 1735de3a6a5SAndreas Gohr 1745de3a6a5SAndreas Gohr // add user to the groups 1755de3a6a5SAndreas Gohr foreach($grps as $group) { 1765de3a6a5SAndreas Gohr $ok = $this->_joinGroup($userdata, $allgroups[$group]); 1775de3a6a5SAndreas Gohr if($ok === false) goto FAIL; 1785de3a6a5SAndreas Gohr } 1795de3a6a5SAndreas Gohr } 1805de3a6a5SAndreas Gohr $this->pdo->commit(); 1815de3a6a5SAndreas Gohr return true; 1825de3a6a5SAndreas Gohr 1835de3a6a5SAndreas Gohr // something went wrong, rollback 1845de3a6a5SAndreas Gohr FAIL: 1855de3a6a5SAndreas Gohr $this->pdo->rollBack(); 1865de3a6a5SAndreas Gohr $this->_debug('Transaction rolled back', 0, __LINE__); 1875de3a6a5SAndreas Gohr return null; // return error 1885de3a6a5SAndreas Gohr } 189f64dbc90SAndreas Gohr 190f64dbc90SAndreas Gohr /** 1914fb8dfabSAndreas Gohr * Modify user data 192f64dbc90SAndreas Gohr * 193f64dbc90SAndreas Gohr * @param string $user nick of the user to be changed 194f64dbc90SAndreas Gohr * @param array $changes array of field/value pairs to be changed (password will be clear text) 195f64dbc90SAndreas Gohr * @return bool 196f64dbc90SAndreas Gohr */ 1974fb8dfabSAndreas Gohr public function modifyUser($user, $changes) { 1984fb8dfabSAndreas Gohr // secure everything in transaction 1994fb8dfabSAndreas Gohr $this->pdo->beginTransaction(); 2004fb8dfabSAndreas Gohr { 2014fb8dfabSAndreas Gohr $olddata = $this->getUserData($user); 2024fb8dfabSAndreas Gohr $oldgroups = $olddata['grps']; 2034fb8dfabSAndreas Gohr unset($olddata['grps']); 2044fb8dfabSAndreas Gohr 2054fb8dfabSAndreas Gohr // changing the user name? 2064fb8dfabSAndreas Gohr if(isset($changes['user'])) { 2074fb8dfabSAndreas Gohr if($this->getUserData($changes['user'], false)) goto FAIL; 2084fb8dfabSAndreas Gohr $params = $olddata; 2094fb8dfabSAndreas Gohr $params['newlogin'] = $changes['user']; 2104fb8dfabSAndreas Gohr 2114fb8dfabSAndreas Gohr $ok = $this->_query($this->getConf('update-user-login'), $params); 2124fb8dfabSAndreas Gohr if($ok === false) goto FAIL; 2134fb8dfabSAndreas Gohr } 2144fb8dfabSAndreas Gohr 2154fb8dfabSAndreas Gohr // changing the password? 2164fb8dfabSAndreas Gohr if(isset($changes['pass'])) { 2174fb8dfabSAndreas Gohr $params = $olddata; 2184fb8dfabSAndreas Gohr $params['clear'] = $changes['pass']; 2194fb8dfabSAndreas Gohr $params['hash'] = auth_cryptPassword($changes['pass']); 2204fb8dfabSAndreas Gohr 2214fb8dfabSAndreas Gohr $ok = $this->_query($this->getConf('update-user-pass'), $params); 2224fb8dfabSAndreas Gohr if($ok === false) goto FAIL; 2234fb8dfabSAndreas Gohr } 2244fb8dfabSAndreas Gohr 2254fb8dfabSAndreas Gohr // changing info? 2264fb8dfabSAndreas Gohr if(isset($changes['mail']) || isset($changes['name'])) { 2274fb8dfabSAndreas Gohr $params = $olddata; 2284fb8dfabSAndreas Gohr if(isset($changes['mail'])) $params['mail'] = $changes['mail']; 2294fb8dfabSAndreas Gohr if(isset($changes['name'])) $params['name'] = $changes['name']; 2304fb8dfabSAndreas Gohr 2314fb8dfabSAndreas Gohr $ok = $this->_query($this->getConf('update-user-info'), $params); 2324fb8dfabSAndreas Gohr if($ok === false) goto FAIL; 2334fb8dfabSAndreas Gohr } 2344fb8dfabSAndreas Gohr 2354fb8dfabSAndreas Gohr // changing groups? 2364fb8dfabSAndreas Gohr if(isset($changes['grps'])) { 2374fb8dfabSAndreas Gohr $allgroups = $this->_selectGroups(); 2384fb8dfabSAndreas Gohr 2394fb8dfabSAndreas Gohr // remove membership for previous groups 2404fb8dfabSAndreas Gohr foreach($oldgroups as $group) { 2414fb8dfabSAndreas Gohr if(!in_array($group, $changes['grps'])) { 2424fb8dfabSAndreas Gohr $ok = $this->_leaveGroup($olddata, $allgroups[$group]); 2434fb8dfabSAndreas Gohr if($ok === false) goto FAIL; 2444fb8dfabSAndreas Gohr } 2454fb8dfabSAndreas Gohr } 2464fb8dfabSAndreas Gohr 2474fb8dfabSAndreas Gohr // create all new groups that are missing 2484fb8dfabSAndreas Gohr $added = 0; 2494fb8dfabSAndreas Gohr foreach($changes['grps'] as $group) { 2504fb8dfabSAndreas Gohr if(!isset($allgroups[$group])) { 2514fb8dfabSAndreas Gohr $ok = $this->_insertGroup($group); 2524fb8dfabSAndreas Gohr if($ok === false) goto FAIL; 2534fb8dfabSAndreas Gohr $added++; 2544fb8dfabSAndreas Gohr } 2554fb8dfabSAndreas Gohr } 2564fb8dfabSAndreas Gohr // reload group info 2574fb8dfabSAndreas Gohr if($added > 0) $allgroups = $this->_selectGroups(); 2584fb8dfabSAndreas Gohr 2594fb8dfabSAndreas Gohr // add membership for new groups 2604fb8dfabSAndreas Gohr foreach($changes['grps'] as $group) { 2614fb8dfabSAndreas Gohr if(!in_array($group, $oldgroups)) { 2624fb8dfabSAndreas Gohr $ok = $this->_joinGroup($olddata, $allgroups[$group]); 2634fb8dfabSAndreas Gohr if($ok === false) goto FAIL; 2644fb8dfabSAndreas Gohr } 2654fb8dfabSAndreas Gohr } 2664fb8dfabSAndreas Gohr } 2674fb8dfabSAndreas Gohr 2684fb8dfabSAndreas Gohr } 2694fb8dfabSAndreas Gohr $this->pdo->commit(); 2704fb8dfabSAndreas Gohr return true; 2714fb8dfabSAndreas Gohr 2724fb8dfabSAndreas Gohr // something went wrong, rollback 2734fb8dfabSAndreas Gohr FAIL: 2744fb8dfabSAndreas Gohr $this->pdo->rollBack(); 2754fb8dfabSAndreas Gohr $this->_debug('Transaction rolled back', 0, __LINE__); 2764fb8dfabSAndreas Gohr return false; // return error 2774fb8dfabSAndreas Gohr } 278f64dbc90SAndreas Gohr 279f64dbc90SAndreas Gohr /** 280*e19be516SAndreas Gohr * Delete one or more users 281f64dbc90SAndreas Gohr * 282f64dbc90SAndreas Gohr * Set delUser capability when implemented 283f64dbc90SAndreas Gohr * 284f64dbc90SAndreas Gohr * @param array $users 285f64dbc90SAndreas Gohr * @return int number of users deleted 286f64dbc90SAndreas Gohr */ 287*e19be516SAndreas Gohr public function deleteUsers($users) { 288*e19be516SAndreas Gohr $count = 0; 289*e19be516SAndreas Gohr foreach($users as $user) { 290*e19be516SAndreas Gohr if($this->_deleteUser($user)) $count++; 291*e19be516SAndreas Gohr } 292*e19be516SAndreas Gohr return $count; 293*e19be516SAndreas Gohr } 294f64dbc90SAndreas Gohr 295f64dbc90SAndreas Gohr /** 296f64dbc90SAndreas Gohr * Bulk retrieval of user data [implement only where required/possible] 297f64dbc90SAndreas Gohr * 298f64dbc90SAndreas Gohr * Set getUsers capability when implemented 299f64dbc90SAndreas Gohr * 300f64dbc90SAndreas Gohr * @param int $start index of first user to be returned 301f64dbc90SAndreas Gohr * @param int $limit max number of users to be returned 302f64dbc90SAndreas Gohr * @param array $filter array of field/pattern pairs, null for no filter 303f64dbc90SAndreas Gohr * @return array list of userinfo (refer getUserData for internal userinfo details) 304f64dbc90SAndreas Gohr */ 305f64dbc90SAndreas Gohr //public function retrieveUsers($start = 0, $limit = -1, $filter = null) { 306f64dbc90SAndreas Gohr // FIXME implement 307f64dbc90SAndreas Gohr // return array(); 308f64dbc90SAndreas Gohr //} 309f64dbc90SAndreas Gohr 310f64dbc90SAndreas Gohr /** 311f64dbc90SAndreas Gohr * Return a count of the number of user which meet $filter criteria 312f64dbc90SAndreas Gohr * [should be implemented whenever retrieveUsers is implemented] 313f64dbc90SAndreas Gohr * 314f64dbc90SAndreas Gohr * Set getUserCount capability when implemented 315f64dbc90SAndreas Gohr * 316f64dbc90SAndreas Gohr * @param array $filter array of field/pattern pairs, empty array for no filter 317f64dbc90SAndreas Gohr * @return int 318f64dbc90SAndreas Gohr */ 319f64dbc90SAndreas Gohr //public function getUserCount($filter = array()) { 320f64dbc90SAndreas Gohr // FIXME implement 321f64dbc90SAndreas Gohr // return 0; 322f64dbc90SAndreas Gohr //} 323f64dbc90SAndreas Gohr 324f64dbc90SAndreas Gohr /** 325f64dbc90SAndreas Gohr * Define a group [implement only where required/possible] 326f64dbc90SAndreas Gohr * 327f64dbc90SAndreas Gohr * Set addGroup capability when implemented 328f64dbc90SAndreas Gohr * 329f64dbc90SAndreas Gohr * @param string $group 330f64dbc90SAndreas Gohr * @return bool 331f64dbc90SAndreas Gohr */ 332f64dbc90SAndreas Gohr //public function addGroup($group) { 333f64dbc90SAndreas Gohr // FIXME implement 334f64dbc90SAndreas Gohr // return false; 335f64dbc90SAndreas Gohr //} 336f64dbc90SAndreas Gohr 337f64dbc90SAndreas Gohr /** 3385de3a6a5SAndreas Gohr * Retrieve groups 339f64dbc90SAndreas Gohr * 340f64dbc90SAndreas Gohr * Set getGroups capability when implemented 341f64dbc90SAndreas Gohr * 342f64dbc90SAndreas Gohr * @param int $start 343f64dbc90SAndreas Gohr * @param int $limit 344f64dbc90SAndreas Gohr * @return array 345f64dbc90SAndreas Gohr */ 3465de3a6a5SAndreas Gohr public function retrieveGroups($start = 0, $limit = 0) { 3475de3a6a5SAndreas Gohr $groups = array_keys($this->_selectGroups()); 3485de3a6a5SAndreas Gohr if($groups === false) return array(); 349f64dbc90SAndreas Gohr 3505de3a6a5SAndreas Gohr if(!$limit) { 3515de3a6a5SAndreas Gohr return array_splice($groups, $start); 3525de3a6a5SAndreas Gohr } else { 3535de3a6a5SAndreas Gohr return array_splice($groups, $start, $limit); 354f64dbc90SAndreas Gohr } 355f64dbc90SAndreas Gohr } 356f64dbc90SAndreas Gohr 357f64dbc90SAndreas Gohr /** 358f64dbc90SAndreas Gohr * Select data of a specified user 359f64dbc90SAndreas Gohr * 3605de3a6a5SAndreas Gohr * @param string $user the user name 3615de3a6a5SAndreas Gohr * @return bool|array user data, false on error 362f64dbc90SAndreas Gohr */ 363f64dbc90SAndreas Gohr protected function _selectUser($user) { 364f64dbc90SAndreas Gohr $sql = $this->getConf('select-user'); 365f64dbc90SAndreas Gohr 3665de3a6a5SAndreas Gohr $result = $this->_query($sql, array(':user' => $user)); 36770a89417SAndreas Gohr if(!$result) return false; 368f64dbc90SAndreas Gohr 36970a89417SAndreas Gohr if(count($result) > 1) { 370f64dbc90SAndreas Gohr $this->_debug('Found more than one matching user', -1, __LINE__); 371f64dbc90SAndreas Gohr return false; 372f64dbc90SAndreas Gohr } 373f64dbc90SAndreas Gohr 374f64dbc90SAndreas Gohr $data = array_shift($result); 375f64dbc90SAndreas Gohr $dataok = true; 376f64dbc90SAndreas Gohr 377f64dbc90SAndreas Gohr if(!isset($data['user'])) { 378f64dbc90SAndreas Gohr $this->_debug("Statement did not return 'user' attribute", -1, __LINE__); 379f64dbc90SAndreas Gohr $dataok = false; 380f64dbc90SAndreas Gohr } 381f64dbc90SAndreas Gohr if(!isset($data['hash']) && !isset($data['clear'])) { 382f64dbc90SAndreas Gohr $this->_debug("Statement did not return 'clear' or 'hash' attribute", -1, __LINE__); 383f64dbc90SAndreas Gohr $dataok = false; 384f64dbc90SAndreas Gohr } 385f64dbc90SAndreas Gohr if(!isset($data['name'])) { 386f64dbc90SAndreas Gohr $this->_debug("Statement did not return 'name' attribute", -1, __LINE__); 387f64dbc90SAndreas Gohr $dataok = false; 388f64dbc90SAndreas Gohr } 389f64dbc90SAndreas Gohr if(!isset($data['mail'])) { 390f64dbc90SAndreas Gohr $this->_debug("Statement did not return 'mail' attribute", -1, __LINE__); 391f64dbc90SAndreas Gohr $dataok = false; 392f64dbc90SAndreas Gohr } 393f64dbc90SAndreas Gohr 394f64dbc90SAndreas Gohr if(!$dataok) return false; 395f64dbc90SAndreas Gohr return $data; 396f64dbc90SAndreas Gohr } 397f64dbc90SAndreas Gohr 398f64dbc90SAndreas Gohr /** 399*e19be516SAndreas Gohr * Delete a user after removing all their group memberships 400*e19be516SAndreas Gohr * 401*e19be516SAndreas Gohr * @param string $user 402*e19be516SAndreas Gohr * @return bool true when the user was deleted 403*e19be516SAndreas Gohr */ 404*e19be516SAndreas Gohr protected function _deleteUser($user) { 405*e19be516SAndreas Gohr $this->pdo->beginTransaction(); 406*e19be516SAndreas Gohr { 407*e19be516SAndreas Gohr $userdata = $this->getUserData($user); 408*e19be516SAndreas Gohr if($userdata === false) goto FAIL; 409*e19be516SAndreas Gohr $allgroups = $this->_selectGroups(); 410*e19be516SAndreas Gohr 411*e19be516SAndreas Gohr // remove group memberships (ignore errors) 412*e19be516SAndreas Gohr foreach($userdata['grps'] as $group) { 413*e19be516SAndreas Gohr $this->_leaveGroup($userdata, $allgroups[$group]); 414*e19be516SAndreas Gohr } 415*e19be516SAndreas Gohr 416*e19be516SAndreas Gohr $ok = $this->_query($this->getConf('delete-user'), $userdata); 417*e19be516SAndreas Gohr if($ok === false) goto FAIL; 418*e19be516SAndreas Gohr } 419*e19be516SAndreas Gohr $this->pdo->commit(); 420*e19be516SAndreas Gohr return true; 421*e19be516SAndreas Gohr 422*e19be516SAndreas Gohr FAIL: 423*e19be516SAndreas Gohr $this->pdo->rollBack(); 424*e19be516SAndreas Gohr return false; 425*e19be516SAndreas Gohr } 426*e19be516SAndreas Gohr 427*e19be516SAndreas Gohr /** 42870a89417SAndreas Gohr * Select all groups of a user 42970a89417SAndreas Gohr * 43070a89417SAndreas Gohr * @param array $userdata The userdata as returned by _selectUser() 4315de3a6a5SAndreas Gohr * @return array|bool list of group names, false on error 43270a89417SAndreas Gohr */ 43370a89417SAndreas Gohr protected function _selectUserGroups($userdata) { 43470a89417SAndreas Gohr global $conf; 43570a89417SAndreas Gohr $sql = $this->getConf('select-user-groups'); 4365de3a6a5SAndreas Gohr $result = $this->_query($sql, $userdata); 4375de3a6a5SAndreas Gohr if($result === false) return false; 43870a89417SAndreas Gohr 43970a89417SAndreas Gohr $groups = array($conf['defaultgroup']); // always add default config 4405de3a6a5SAndreas Gohr foreach($result as $row) { 4415de3a6a5SAndreas Gohr if(!isset($row['group'])) { 4425de3a6a5SAndreas Gohr $this->_debug("No 'group' field returned in select-user-groups statement"); 4435de3a6a5SAndreas Gohr return false; 4445de3a6a5SAndreas Gohr } 44570a89417SAndreas Gohr $groups[] = $row['group']; 44670a89417SAndreas Gohr } 44770a89417SAndreas Gohr 44870a89417SAndreas Gohr $groups = array_unique($groups); 44970a89417SAndreas Gohr sort($groups); 45070a89417SAndreas Gohr return $groups; 45170a89417SAndreas Gohr } 45270a89417SAndreas Gohr 45370a89417SAndreas Gohr /** 4545de3a6a5SAndreas Gohr * Select all available groups 4555de3a6a5SAndreas Gohr * 4565de3a6a5SAndreas Gohr * @todo this should be cached 4575de3a6a5SAndreas Gohr * @return array|bool list of all available groups and their properties 4585de3a6a5SAndreas Gohr */ 4595de3a6a5SAndreas Gohr protected function _selectGroups() { 4605de3a6a5SAndreas Gohr $sql = $this->getConf('select-groups'); 4615de3a6a5SAndreas Gohr $result = $this->_query($sql); 4625de3a6a5SAndreas Gohr if($result === false) return false; 4635de3a6a5SAndreas Gohr 4645de3a6a5SAndreas Gohr $groups = array(); 4655de3a6a5SAndreas Gohr foreach($result as $row) { 4665de3a6a5SAndreas Gohr if(!isset($row['group'])) { 4675de3a6a5SAndreas Gohr $this->_debug("No 'group' field returned from select-groups statement", -1, __LINE__); 4685de3a6a5SAndreas Gohr return false; 4695de3a6a5SAndreas Gohr } 4705de3a6a5SAndreas Gohr 4715de3a6a5SAndreas Gohr // relayout result with group name as key 4725de3a6a5SAndreas Gohr $group = $row['group']; 4735de3a6a5SAndreas Gohr $groups[$group] = $row; 4745de3a6a5SAndreas Gohr } 4755de3a6a5SAndreas Gohr 4765de3a6a5SAndreas Gohr ksort($groups); 4775de3a6a5SAndreas Gohr return $groups; 4785de3a6a5SAndreas Gohr } 4795de3a6a5SAndreas Gohr 4805de3a6a5SAndreas Gohr /** 4815de3a6a5SAndreas Gohr * Create a new group with the given name 4825de3a6a5SAndreas Gohr * 4835de3a6a5SAndreas Gohr * @param string $group 4845de3a6a5SAndreas Gohr * @return bool 4855de3a6a5SAndreas Gohr */ 4865de3a6a5SAndreas Gohr protected function _insertGroup($group) { 4875de3a6a5SAndreas Gohr $sql = $this->getConf('insert-group'); 4885de3a6a5SAndreas Gohr 4895de3a6a5SAndreas Gohr $result = $this->_query($sql, array(':group' => $group)); 4905de3a6a5SAndreas Gohr if($result === false) return false; 4915de3a6a5SAndreas Gohr return true; 4925de3a6a5SAndreas Gohr } 4935de3a6a5SAndreas Gohr 4945de3a6a5SAndreas Gohr /** 4954fb8dfabSAndreas Gohr * Adds the user to the group 4965de3a6a5SAndreas Gohr * 4975de3a6a5SAndreas Gohr * @param array $userdata all the user data 4985de3a6a5SAndreas Gohr * @param array $groupdata all the group data 4995de3a6a5SAndreas Gohr * @return bool 5005de3a6a5SAndreas Gohr */ 5015de3a6a5SAndreas Gohr protected function _joinGroup($userdata, $groupdata) { 5025de3a6a5SAndreas Gohr $data = array_merge($userdata, $groupdata); 5035de3a6a5SAndreas Gohr $sql = $this->getConf('join-group'); 5045de3a6a5SAndreas Gohr $result = $this->_query($sql, $data); 5055de3a6a5SAndreas Gohr if($result === false) return false; 5065de3a6a5SAndreas Gohr return true; 5075de3a6a5SAndreas Gohr } 5085de3a6a5SAndreas Gohr 5095de3a6a5SAndreas Gohr /** 5104fb8dfabSAndreas Gohr * Removes the user from the group 5114fb8dfabSAndreas Gohr * 5124fb8dfabSAndreas Gohr * @param array $userdata all the user data 5134fb8dfabSAndreas Gohr * @param array $groupdata all the group data 5144fb8dfabSAndreas Gohr * @return bool 5154fb8dfabSAndreas Gohr */ 5164fb8dfabSAndreas Gohr protected function _leaveGroup($userdata, $groupdata) { 5174fb8dfabSAndreas Gohr $data = array_merge($userdata, $groupdata); 5184fb8dfabSAndreas Gohr $sql = $this->getConf('leave-group'); 5194fb8dfabSAndreas Gohr $result = $this->_query($sql, $data); 5204fb8dfabSAndreas Gohr if($result === false) return false; 5214fb8dfabSAndreas Gohr return true; 5224fb8dfabSAndreas Gohr } 5234fb8dfabSAndreas Gohr 5244fb8dfabSAndreas Gohr /** 52570a89417SAndreas Gohr * Executes a query 52670a89417SAndreas Gohr * 52770a89417SAndreas Gohr * @param string $sql The SQL statement to execute 52870a89417SAndreas Gohr * @param array $arguments Named parameters to be used in the statement 5295de3a6a5SAndreas Gohr * @return array|bool The result as associative array, false on error 53070a89417SAndreas Gohr */ 5315de3a6a5SAndreas Gohr protected function _query($sql, $arguments = array()) { 5325de3a6a5SAndreas Gohr if(empty($sql)) { 5335de3a6a5SAndreas Gohr $this->_debug('No SQL query given', -1, __LINE__); 5345de3a6a5SAndreas Gohr return false; 5355de3a6a5SAndreas Gohr } 5365de3a6a5SAndreas Gohr 53770a89417SAndreas Gohr // prepare parameters - we only use those that exist in the SQL 53870a89417SAndreas Gohr $params = array(); 53970a89417SAndreas Gohr foreach($arguments as $key => $value) { 54070a89417SAndreas Gohr if(is_array($value)) continue; 54170a89417SAndreas Gohr if(is_object($value)) continue; 54270a89417SAndreas Gohr if($key[0] != ':') $key = ":$key"; // prefix with colon if needed 54370a89417SAndreas Gohr if(strpos($sql, $key) !== false) $params[$key] = $value; 54470a89417SAndreas Gohr } 54570a89417SAndreas Gohr 54670a89417SAndreas Gohr // execute 54770a89417SAndreas Gohr $sth = $this->pdo->prepare($sql); 5485de3a6a5SAndreas Gohr try { 54970a89417SAndreas Gohr $sth->execute($params); 55070a89417SAndreas Gohr $result = $sth->fetchAll(); 5515de3a6a5SAndreas Gohr } catch(Exception $e) { 5524fb8dfabSAndreas Gohr // report the caller's line 5534fb8dfabSAndreas Gohr $trace = debug_backtrace(); 5544fb8dfabSAndreas Gohr $line = $trace[0]['line']; 5555de3a6a5SAndreas Gohr $dsql = $this->_debugSQL($sql, $params, !defined('DOKU_UNITTEST')); 5564fb8dfabSAndreas Gohr $this->_debug($e, -1, $line); 5574fb8dfabSAndreas Gohr $this->_debug("SQL: <pre>$dsql</pre>", -1, $line); 55870a89417SAndreas Gohr $result = false; 5595de3a6a5SAndreas Gohr } finally { 56070a89417SAndreas Gohr $sth->closeCursor(); 56170a89417SAndreas Gohr $sth = null; 56270a89417SAndreas Gohr } 56370a89417SAndreas Gohr 5645de3a6a5SAndreas Gohr return $result; 5655de3a6a5SAndreas Gohr } 56670a89417SAndreas Gohr 56770a89417SAndreas Gohr /** 568f64dbc90SAndreas Gohr * Wrapper around msg() but outputs only when debug is enabled 569f64dbc90SAndreas Gohr * 570f64dbc90SAndreas Gohr * @param string|Exception $message 571f64dbc90SAndreas Gohr * @param int $err 572f64dbc90SAndreas Gohr * @param int $line 573f64dbc90SAndreas Gohr */ 574f64dbc90SAndreas Gohr protected function _debug($message, $err = 0, $line = 0) { 575f64dbc90SAndreas Gohr if(!$this->getConf('debug')) return; 576f64dbc90SAndreas Gohr if(is_a($message, 'Exception')) { 577f64dbc90SAndreas Gohr $err = -1; 578f64dbc90SAndreas Gohr $msg = $message->getMessage(); 5794fb8dfabSAndreas Gohr if(!$line) $line = $message->getLine(); 580f64dbc90SAndreas Gohr } else { 581f64dbc90SAndreas Gohr $msg = $message; 582f64dbc90SAndreas Gohr } 583f64dbc90SAndreas Gohr 584f64dbc90SAndreas Gohr if(defined('DOKU_UNITTEST')) { 585f64dbc90SAndreas Gohr printf("\n%s, %s:%d\n", $msg, __FILE__, $line); 586f64dbc90SAndreas Gohr } else { 587f64dbc90SAndreas Gohr msg('authpdo: ' . $msg, $err, $line, __FILE__); 588f64dbc90SAndreas Gohr } 589f64dbc90SAndreas Gohr } 5905de3a6a5SAndreas Gohr 5915de3a6a5SAndreas Gohr /** 5925de3a6a5SAndreas Gohr * Check if the given config strings are set 5935de3a6a5SAndreas Gohr * 5945de3a6a5SAndreas Gohr * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> 5955de3a6a5SAndreas Gohr * 5965de3a6a5SAndreas Gohr * @param string[] $keys 5975de3a6a5SAndreas Gohr * @return bool 5985de3a6a5SAndreas Gohr */ 5995de3a6a5SAndreas Gohr protected function _chkcnf($keys) { 6005de3a6a5SAndreas Gohr foreach($keys as $key) { 6015de3a6a5SAndreas Gohr if(!$this->getConf($key)) return false; 6025de3a6a5SAndreas Gohr } 6035de3a6a5SAndreas Gohr 6045de3a6a5SAndreas Gohr return true; 6055de3a6a5SAndreas Gohr } 6065de3a6a5SAndreas Gohr 6075de3a6a5SAndreas Gohr /** 6085de3a6a5SAndreas Gohr * create an approximation of the SQL string with parameters replaced 6095de3a6a5SAndreas Gohr * 6105de3a6a5SAndreas Gohr * @param string $sql 6115de3a6a5SAndreas Gohr * @param array $params 6125de3a6a5SAndreas Gohr * @param bool $htmlescape Should the result be escaped for output in HTML? 6135de3a6a5SAndreas Gohr * @return string 6145de3a6a5SAndreas Gohr */ 6155de3a6a5SAndreas Gohr protected function _debugSQL($sql, $params, $htmlescape = true) { 6165de3a6a5SAndreas Gohr foreach($params as $key => $val) { 6175de3a6a5SAndreas Gohr if(is_int($val)) { 6185de3a6a5SAndreas Gohr $val = $this->pdo->quote($val, PDO::PARAM_INT); 6195de3a6a5SAndreas Gohr } elseif(is_bool($val)) { 6205de3a6a5SAndreas Gohr $val = $this->pdo->quote($val, PDO::PARAM_BOOL); 6215de3a6a5SAndreas Gohr } elseif(is_null($val)) { 6225de3a6a5SAndreas Gohr $val = 'NULL'; 6235de3a6a5SAndreas Gohr } else { 6245de3a6a5SAndreas Gohr $val = $this->pdo->quote($val); 6255de3a6a5SAndreas Gohr } 6265de3a6a5SAndreas Gohr $sql = str_replace($key, $val, $sql); 6275de3a6a5SAndreas Gohr } 6285de3a6a5SAndreas Gohr if($htmlescape) $sql = hsc($sql); 6295de3a6a5SAndreas Gohr return $sql; 6305de3a6a5SAndreas Gohr } 631f64dbc90SAndreas Gohr} 632f64dbc90SAndreas Gohr 633f64dbc90SAndreas Gohr// vim:ts=4:sw=4:et: 634