124cd6f55SDamien Regad<?php 224cd6f55SDamien Regad/** 324cd6f55SDamien Regad * DokuWiki Plugin authwordpress (Auth Component) 424cd6f55SDamien Regad * 535dd80b8SDamien Regad * Provides authentication against a WordPress MySQL database backend 635dd80b8SDamien Regad * 735dd80b8SDamien Regad * This program is free software; you can redistribute it and/or modify 835dd80b8SDamien Regad * it under the terms of the GNU General Public License as published by 935dd80b8SDamien Regad * the Free Software Foundation; version 2 of the License 1035dd80b8SDamien Regad * 1135dd80b8SDamien Regad * This program is distributed in the hope that it will be useful, 1235dd80b8SDamien Regad * but WITHOUT ANY WARRANTY; without even the implied warranty of 1335dd80b8SDamien Regad * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1435dd80b8SDamien Regad * GNU General Public License for more details. 1535dd80b8SDamien Regad * 1635dd80b8SDamien Regad * See the COPYING file in your DokuWiki folder for details 1735dd80b8SDamien Regad * 1824cd6f55SDamien Regad * @author Damien Regad <dregad@mantisbt.org> 1935dd80b8SDamien Regad * @copyright 2015 Damien Regad 2035dd80b8SDamien Regad * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 21b5b72c15SDamien Regad * @version 1.1 2235dd80b8SDamien Regad * @link https://github.com/dregad/dokuwiki-authwordpress 2324cd6f55SDamien Regad */ 2424cd6f55SDamien Regad 2535dd80b8SDamien Regad 2624cd6f55SDamien Regad// must be run within Dokuwiki 2724cd6f55SDamien Regadif(!defined('DOKU_INC')) die(); 2824cd6f55SDamien Regad 2935dd80b8SDamien Regad/** 3035dd80b8SDamien Regad * WordPress password hashing framework 3135dd80b8SDamien Regad */ 3235dd80b8SDamien Regadrequire_once('class-phpass.php'); 3335dd80b8SDamien Regad 3435dd80b8SDamien Regad/** 3535dd80b8SDamien Regad * Authentication class 3635dd80b8SDamien Regad */ 3724cd6f55SDamien Regadclass auth_plugin_authwordpress extends DokuWiki_Auth_Plugin { 3824cd6f55SDamien Regad 3935dd80b8SDamien Regad /** 4035dd80b8SDamien Regad * SQL statement to retrieve User data from WordPress DB 4135dd80b8SDamien Regad * (including group memberships) 42b5b72c15SDamien Regad * '%prefix%' will be replaced by the actual prefix (from plugin config) 4335dd80b8SDamien Regad */ 440341717fSDamien Regad protected $sql_wp_user_data = "SELECT 4535dd80b8SDamien Regad id, user_login, user_pass, user_email, display_name, 4635dd80b8SDamien Regad meta_value AS groups 47b5b72c15SDamien Regad FROM %prefix%users u 482ef3e6a1SDamien Regad JOIN %prefix%usermeta m ON u.id = m.user_id AND meta_key = '%prefix%capabilities'"; 4924cd6f55SDamien Regad 5024cd6f55SDamien Regad /** 51015f33b2SDamien Regad * Wordpress database connection 52015f33b2SDamien Regad */ 530341717fSDamien Regad protected $db; 54015f33b2SDamien Regad 55*d35aa3ecSDamien Regad /** 56*d35aa3ecSDamien Regad * Users cache 57*d35aa3ecSDamien Regad */ 58*d35aa3ecSDamien Regad protected $users; 59*d35aa3ecSDamien Regad 60*d35aa3ecSDamien Regad /** 61*d35aa3ecSDamien Regad * True if all users have been loaded in the cache 62*d35aa3ecSDamien Regad * @see $users 63*d35aa3ecSDamien Regad */ 64*d35aa3ecSDamien Regad protected $usersCached = false; 65*d35aa3ecSDamien Regad 66015f33b2SDamien Regad 67015f33b2SDamien Regad /** 6824cd6f55SDamien Regad * Constructor. 6924cd6f55SDamien Regad */ 7024cd6f55SDamien Regad public function __construct() { 7135dd80b8SDamien Regad parent::__construct(); 7224cd6f55SDamien Regad 7316ceb666SDamien Regad $this->cando['getUsers'] = true; 7416ceb666SDamien Regad 7535dd80b8SDamien Regad // Try to establish a connection to the WordPress DB 7635dd80b8SDamien Regad // abort in case of failure 7735dd80b8SDamien Regad try { 785a360df9SDamien Regad $this->wp_connect(); 7935dd80b8SDamien Regad } 8035dd80b8SDamien Regad catch (Exception $e) { 8135dd80b8SDamien Regad msg(sprintf($this->getLang('error_connect_failed'), $e->getMessage())); 8235dd80b8SDamien Regad $this->success = false; 8335dd80b8SDamien Regad return; 8435dd80b8SDamien Regad } 8524cd6f55SDamien Regad 86b5b72c15SDamien Regad // Initialize SQL query with configured prefix 87b5b72c15SDamien Regad $this->sql_wp_user_data = str_replace( 88b5b72c15SDamien Regad '%prefix%', 89b5b72c15SDamien Regad $this->getConf('prefix'), 90b5b72c15SDamien Regad $this->sql_wp_user_data 91b5b72c15SDamien Regad ); 92b5b72c15SDamien Regad 9324cd6f55SDamien Regad $this->success = true; 9424cd6f55SDamien Regad } 9524cd6f55SDamien Regad 9624cd6f55SDamien Regad 9724cd6f55SDamien Regad /** 9824cd6f55SDamien Regad * Check user+password 9924cd6f55SDamien Regad * 10024cd6f55SDamien Regad * @param string $user the user name 10124cd6f55SDamien Regad * @param string $pass the clear text password 10224cd6f55SDamien Regad * @return bool 10335dd80b8SDamien Regad * 10435dd80b8SDamien Regad * @uses PasswordHash::CheckPassword WordPress password hasher 10524cd6f55SDamien Regad */ 10624cd6f55SDamien Regad public function checkPass($user, $pass) { 10735dd80b8SDamien Regad $data = $this->getUserData($user); 10835dd80b8SDamien Regad if ($data === false) { 10935dd80b8SDamien Regad return false; 11024cd6f55SDamien Regad } 11124cd6f55SDamien Regad 11235dd80b8SDamien Regad $hasher = new PasswordHash(8, true); 113eed09871SDamien Regad $check = $hasher->CheckPassword($pass, $data['pass']); 114eed09871SDamien Regad dbglog("Password " . ($check ? 'OK' : 'Invalid')); 115eed09871SDamien Regad 116eed09871SDamien Regad return $check; 11735dd80b8SDamien Regad } 11835dd80b8SDamien Regad 11916ceb666SDamien Regad /** 12016ceb666SDamien Regad * Bulk retrieval of user data 12116ceb666SDamien Regad * 12216ceb666SDamien Regad * @param int $start index of first user to be returned 12316ceb666SDamien Regad * @param int $limit max number of users to be returned 12416ceb666SDamien Regad * @param array $filter array of field/pattern pairs 12516ceb666SDamien Regad * @return array userinfo (refer getUserData for internal userinfo details) 12616ceb666SDamien Regad */ 12716ceb666SDamien Regad public function retrieveUsers($start = 0, $limit = 0, $filter = array()) { 12816ceb666SDamien Regad msg($this->getLang('user_list_use_wordpress')); 1292ef3e6a1SDamien Regad if($filter) { 1302ef3e6a1SDamien Regad msg($this->getLang('error_filters_unsupported')); 1312ef3e6a1SDamien Regad } 1322ef3e6a1SDamien Regad 133*d35aa3ecSDamien Regad $this->cacheAllUsers(); 134*d35aa3ecSDamien Regad return $this->users; 13516ceb666SDamien Regad } 13616ceb666SDamien Regad 13735dd80b8SDamien Regad 13824cd6f55SDamien Regad /** 13935dd80b8SDamien Regad * Returns info about the given user 14024cd6f55SDamien Regad * 14124cd6f55SDamien Regad * @param string $user the user name 14224cd6f55SDamien Regad * @return array containing user data or false 14324cd6f55SDamien Regad */ 1440341717fSDamien Regad public function getUserData($user, $requireGroups=true) { 145*d35aa3ecSDamien Regad if(isset($this->users[$user])) { 146*d35aa3ecSDamien Regad return $this->users[$user]; 147*d35aa3ecSDamien Regad } 148*d35aa3ecSDamien Regad 1492ef3e6a1SDamien Regad $sql = $this->sql_wp_user_data 1502ef3e6a1SDamien Regad . 'WHERE user_login = :user'; 15135dd80b8SDamien Regad 1522ef3e6a1SDamien Regad $stmt = $this->db->prepare($sql); 15335dd80b8SDamien Regad $stmt->bindParam(':user', $user); 1542ef3e6a1SDamien Regad dbglog("Retrieving data for user '$user'\n$sql"); 15535dd80b8SDamien Regad 15635dd80b8SDamien Regad if (!$stmt->execute()) { 1579520968dSDamien Regad // Query execution failed 158eed09871SDamien Regad $err = $stmt->errorInfo(); 159eed09871SDamien Regad dbglog("Error $err[1]: $err[2]"); 16024cd6f55SDamien Regad return false; 16124cd6f55SDamien Regad } 1629520968dSDamien Regad 1639520968dSDamien Regad $user = $stmt->fetch(PDO::FETCH_ASSOC); 1649520968dSDamien Regad if ($user === false) { 1659520968dSDamien Regad // Unknown user 166eed09871SDamien Regad dbglog("Unknown user"); 1679520968dSDamien Regad return false; 1689520968dSDamien Regad } 16924cd6f55SDamien Regad 170*d35aa3ecSDamien Regad return $this->cacheUser($user); 17124cd6f55SDamien Regad } 17224cd6f55SDamien Regad 17324cd6f55SDamien Regad 17424cd6f55SDamien Regad /** 17535dd80b8SDamien Regad * Connect to Wordpress database 176015f33b2SDamien Regad * Initializes $db property as PDO object 17724cd6f55SDamien Regad */ 1780341717fSDamien Regad protected function wp_connect() { 179cb81639bSDamien Regad if($this->db) { 180cb81639bSDamien Regad // Already connected 181cb81639bSDamien Regad return; 182cb81639bSDamien Regad } 183cb81639bSDamien Regad 184cb81639bSDamien Regad // Build connection string 18535dd80b8SDamien Regad $dsn = array( 18635dd80b8SDamien Regad 'host=' . $this->getConf('hostname'), 18735dd80b8SDamien Regad 'dbname=' . $this->getConf('database'), 18835dd80b8SDamien Regad ); 18935dd80b8SDamien Regad $port = $this->getConf('port'); 19035dd80b8SDamien Regad if ($port) { 19135dd80b8SDamien Regad $dsn[] = 'port=' . $port; 19235dd80b8SDamien Regad } 19335dd80b8SDamien Regad $dsn = 'mysql:' . implode(';', $dsn); 19435dd80b8SDamien Regad 195015f33b2SDamien Regad $this->db = new PDO($dsn, $this->getConf('username'), $this->getConf('password')); 19624cd6f55SDamien Regad } 19724cd6f55SDamien Regad 198d1f83a80SDamien Regad /** 199d1f83a80SDamien Regad * Convert a Wordpress DB User row to DokuWiki user info array 200*d35aa3ecSDamien Regad * and stores it in the users cache 201d1f83a80SDamien Regad * 202d1f83a80SDamien Regad * @param array $user Raw Wordpress user table row 203d1f83a80SDamien Regad * @return array user data 204d1f83a80SDamien Regad */ 205*d35aa3ecSDamien Regad protected function cacheUser($row) { 206d1f83a80SDamien Regad global $conf; 207d1f83a80SDamien Regad 208*d35aa3ecSDamien Regad $login = $row['user_login']; 209*d35aa3ecSDamien Regad 210*d35aa3ecSDamien Regad // If the user is already cached, just return it 211*d35aa3ecSDamien Regad if(isset($this->users[$login])) { 212*d35aa3ecSDamien Regad return $this->users[$login]; 213*d35aa3ecSDamien Regad } 214*d35aa3ecSDamien Regad 215d1f83a80SDamien Regad // Group membership - add DokuWiki's default group 216*d35aa3ecSDamien Regad $groups = array_keys(unserialize($row['groups'])); 217d1f83a80SDamien Regad if($this->getConf('usedefaultgroup')) { 218d1f83a80SDamien Regad $groups[] = $conf['defaultgroup']; 219d1f83a80SDamien Regad } 220d1f83a80SDamien Regad 221d1f83a80SDamien Regad $info = array( 222*d35aa3ecSDamien Regad 'user' => $login, 223*d35aa3ecSDamien Regad 'name' => $row['display_name'], 224*d35aa3ecSDamien Regad 'pass' => $row['user_pass'], 225*d35aa3ecSDamien Regad 'mail' => $row['user_email'], 226d1f83a80SDamien Regad 'grps' => $groups, 227d1f83a80SDamien Regad ); 228*d35aa3ecSDamien Regad 229*d35aa3ecSDamien Regad $this->users[$login] = $info; 230d1f83a80SDamien Regad return $info; 231d1f83a80SDamien Regad } 232d1f83a80SDamien Regad 233*d35aa3ecSDamien Regad /** 234*d35aa3ecSDamien Regad * Loads all Wordpress users into the cache 235*d35aa3ecSDamien Regad * 236*d35aa3ecSDamien Regad * @return void 237*d35aa3ecSDamien Regad */ 238*d35aa3ecSDamien Regad protected function cacheAllUsers() { 239*d35aa3ecSDamien Regad if($this->usersCached) { 240*d35aa3ecSDamien Regad return; 241*d35aa3ecSDamien Regad } 242*d35aa3ecSDamien Regad 243*d35aa3ecSDamien Regad $stmt = $this->db->prepare($this->sql_wp_user_data); 244*d35aa3ecSDamien Regad $stmt->execute(); 245*d35aa3ecSDamien Regad 246*d35aa3ecSDamien Regad foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $user) { 247*d35aa3ecSDamien Regad $this->cacheUser($user); 248*d35aa3ecSDamien Regad } 249*d35aa3ecSDamien Regad 250*d35aa3ecSDamien Regad $this->usersCached = true; 251*d35aa3ecSDamien Regad } 252*d35aa3ecSDamien Regad 25324cd6f55SDamien Regad} 25424cd6f55SDamien Regad 2550e6cb03cSDamien Regad// vim:ts=4:sw=4:noet: 256