xref: /plugin/authwordpress/auth.php (revision 2ef3e6a1b22df01869509843e990b6861bd80e87)
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