1<?php 2/** 3 * DokuWiki Plugin authwordpress (Auth Component) 4 * 5 * Provides authentication against a WordPress MySQL database backend 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; version 2 of the License 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * See the COPYING file in your DokuWiki folder for details 17 * 18 * @author Damien Regad <dregad@mantisbt.org> 19 * @copyright 2015 Damien Regad 20 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 21 * @version 1.1 22 * @link https://github.com/dregad/dokuwiki-authwordpress 23 */ 24 25 26// must be run within Dokuwiki 27if(!defined('DOKU_INC')) die(); 28 29/** 30 * WordPress password hashing framework 31 */ 32require_once('class-phpass.php'); 33 34/** 35 * Authentication class 36 */ 37class auth_plugin_authwordpress extends DokuWiki_Auth_Plugin { 38 39 /** 40 * SQL statement to retrieve User data from WordPress DB 41 * (including group memberships) 42 * '%prefix%' will be replaced by the actual prefix (from plugin config) 43 */ 44 protected $sql_wp_user_data = "SELECT 45 id, user_login, user_pass, user_email, display_name, 46 meta_value AS groups 47 FROM %prefix%users u 48 JOIN %prefix%usermeta m ON u.id = m.user_id AND meta_key = '%prefix%capabilities'"; 49 50 /** 51 * Wordpress database connection 52 */ 53 protected $db; 54 55 56 /** 57 * Constructor. 58 */ 59 public function __construct() { 60 parent::__construct(); 61 62 $this->cando['getUsers'] = true; 63 64 // Try to establish a connection to the WordPress DB 65 // abort in case of failure 66 try { 67 $this->wp_connect(); 68 } 69 catch (Exception $e) { 70 msg(sprintf($this->getLang('error_connect_failed'), $e->getMessage())); 71 $this->success = false; 72 return; 73 } 74 75 // Initialize SQL query with configured prefix 76 $this->sql_wp_user_data = str_replace( 77 '%prefix%', 78 $this->getConf('prefix'), 79 $this->sql_wp_user_data 80 ); 81 82 $this->success = true; 83 } 84 85 86 /** 87 * Check user+password 88 * 89 * @param string $user the user name 90 * @param string $pass the clear text password 91 * @return bool 92 * 93 * @uses PasswordHash::CheckPassword WordPress password hasher 94 */ 95 public function checkPass($user, $pass) { 96 $data = $this->getUserData($user); 97 if ($data === false) { 98 return false; 99 } 100 101 $hasher = new PasswordHash(8, true); 102 $check = $hasher->CheckPassword($pass, $data['pass']); 103 dbglog("Password " . ($check ? 'OK' : 'Invalid')); 104 105 return $check; 106 } 107 108 /** 109 * Bulk retrieval of user data 110 * 111 * @param int $start index of first user to be returned 112 * @param int $limit max number of users to be returned 113 * @param array $filter array of field/pattern pairs 114 * @return array userinfo (refer getUserData for internal userinfo details) 115 */ 116 public function retrieveUsers($start = 0, $limit = 0, $filter = array()) { 117 $stmt = $this->db->prepare($this->sql_wp_user_data); 118 $stmt->execute(); 119 120 $users = array(); 121 foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $user) { 122 $users[] = $this->wp2dw($user); 123 } 124 125 msg($this->getLang('user_list_use_wordpress')); 126 if($filter) { 127 msg($this->getLang('error_filters_unsupported')); 128 } 129 130 return $users; 131 } 132 133 134 /** 135 * Returns info about the given user 136 * 137 * @param string $user the user name 138 * @return array containing user data or false 139 */ 140 public function getUserData($user, $requireGroups=true) { 141 $sql = $this->sql_wp_user_data 142 . 'WHERE user_login = :user'; 143 144 $stmt = $this->db->prepare($sql); 145 $stmt->bindParam(':user', $user); 146 dbglog("Retrieving data for user '$user'\n$sql"); 147 148 if (!$stmt->execute()) { 149 // Query execution failed 150 $err = $stmt->errorInfo(); 151 dbglog("Error $err[1]: $err[2]"); 152 return false; 153 } 154 155 $user = $stmt->fetch(PDO::FETCH_ASSOC); 156 if ($user === false) { 157 // Unknown user 158 dbglog("Unknown user"); 159 return false; 160 } 161 162 return $this->wp2dw($user); 163 } 164 165 166 /** 167 * Connect to Wordpress database 168 * Initializes $db property as PDO object 169 */ 170 protected function wp_connect() { 171 if($this->db) { 172 // Already connected 173 return; 174 } 175 176 // Build connection string 177 $dsn = array( 178 'host=' . $this->getConf('hostname'), 179 'dbname=' . $this->getConf('database'), 180 ); 181 $port = $this->getConf('port'); 182 if ($port) { 183 $dsn[] = 'port=' . $port; 184 } 185 $dsn = 'mysql:' . implode(';', $dsn); 186 187 $this->db = new PDO($dsn, $this->getConf('username'), $this->getConf('password')); 188 } 189 190 /** 191 * Convert a Wordpress DB User row to DokuWiki user info array 192 * 193 * @param array $user Raw Wordpress user table row 194 * @return array user data 195 */ 196 protected function wp2dw($user) { 197 global $conf; 198 199 // Group membership - add DokuWiki's default group 200 $groups = array_keys(unserialize($user['groups'])); 201 if($this->getConf('usedefaultgroup')) { 202 $groups[] = $conf['defaultgroup']; 203 } 204 205 $info = array( 206 'user' => $user['user_login'], 207 'name' => $user['display_name'], 208 'pass' => $user['user_pass'], 209 'mail' => $user['user_email'], 210 'grps' => $groups, 211 ); 212 return $info; 213 } 214 215} 216 217// vim:ts=4:sw=4:noet: 218