3 Plugin Name: External DB authentication
4 Plugin URI: http://www.ploofle.com/tag/ext_db_auth/
5 Description: Used to externally authenticate WP users with an existing user DB.
7 Author: Charlene Barina
8 Author URI: http://www.ploofle.com
10 Copyright 2007 Charlene Barina (email : cbarina@u.washington.edu)
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 //backwords compatability with php < 5 for htmlspecialchars_decode
28 if ( !function_exists('htmlspecialchars_decode') )
30 function htmlspecialchars_decode($text)
32 return strtr($text, array_flip(get_html_translation_table(HTML_SPECIALCHARS)));
36 function ext_db_auth_activate() {
37 add_option('ext_db_type',"MySQL","External database type");
38 add_option('ext_db_mdb2_path',"","Path to MDB2 (if non-standard)");
39 add_option('ext_host',"","External database hostname");
40 add_option('ext_db_port',"","Database port (if non-standard)");
41 add_option('ext_db',"","External database name");
42 add_option('ext_db_user',"","External database username");
43 add_option('ext_db_pw',"","External database password");
44 add_option('ext_db_table',"","External database table for authentication");
45 add_option('ext_db_namefield',"","External database field for username");
46 add_option('ext_db_pwfield',"","External database field for password");
47 add_option('ext_db_first_name',"");
48 add_option('ext_db_last_name',"");
49 add_option('ext_db_user_url',"");
50 add_option('ext_db_user_email',"");
51 add_option('ext_db_description',"");
52 add_option('ext_db_aim',"");
53 add_option('ext_db_yim',"");
54 add_option('ext_db_jabber',"");
55 add_option('ext_db_enc',"","Type of encoding for external db (default SHA1? or MD5?)");
56 add_option('ext_db_error_msg',"","Custom login message");
57 add_option('ext_db_other_enc','$password2 = $password;');
58 add_option('ext_db_role_bool','');
59 add_option('ext_db_role','');
60 add_option('ext_db_role_value','');
63 function ext_db_auth_init(){
64 register_setting('ext_db_auth','ext_db_type');
65 register_setting('ext_db_auth','ext_db_mdb2_path');
66 register_setting('ext_db_auth','ext_host');
67 register_setting('ext_db_auth','ext_db_port');
68 register_setting('ext_db_auth','ext_db');
69 register_setting('ext_db_auth','ext_db_user');
70 register_setting('ext_db_auth','ext_db_pw');
71 register_setting('ext_db_auth','ext_db_table');
72 register_setting('ext_db_auth','ext_db_namefield');
73 register_setting('ext_db_auth','ext_db_pwfield');
74 register_setting('ext_db_auth','ext_db_first_name');
75 register_setting('ext_db_auth','ext_db_last_name');
76 register_setting('ext_db_auth','ext_db_user_url');
77 register_setting('ext_db_auth','ext_db_user_email');
78 register_setting('ext_db_auth','ext_db_description');
79 register_setting('ext_db_auth','ext_db_aim');
80 register_setting('ext_db_auth','ext_db_yim');
81 register_setting('ext_db_auth','ext_db_jabber');
82 register_setting('ext_db_auth','ext_db_enc');
83 register_setting('ext_db_auth','ext_db_error_msg');
84 register_setting('ext_db_auth','ext_db_other_enc');
85 register_setting('ext_db_auth','ext_db_role');
86 register_setting('ext_db_auth','ext_db_role_bool');
87 register_setting('ext_db_auth','ext_db_role_value');
90 //page for config menu
91 function ext_db_auth_add_menu() {
92 add_options_page("External DB settings", "External DB settings", 10, __FILE__,"ext_db_auth_display_options");
95 //actual configuration screen
96 function ext_db_auth_display_options() {
97 $db_types[] = "MySQL";
98 $db_types[] = "MSSQL";
99 $db_types[] = "PgSQL";
102 <h2>External Database Authentication Settings</h2>
103 <form method="post" action="options.php">
104 <?php settings_fields('ext_db_auth'); ?>
105 <h3>External Database Settings</h3>
106 <strong>Make sure your WP admin account exists in the external db prior to saving these settings.</strong>
107 <table class="form-table">
109 <th scope="row">Database type</th>
110 <td><select name="ext_db_type" >
112 foreach ($db_types as $key=>$value) { //print out radio buttons
113 if ($value == get_option('ext_db_type'))
114 echo '<option value="'.$value.'" selected="selected">'.$value.'<br/>';
115 else echo '<option value="'.$value.'">'.$value.'<br/>';;
121 <span class="description"><strong style="color:red;">required</strong>; If not MySQL, requires <a href="http://pear.php.net/package/MDB2/" target="_blank">PEAR MDB2 package</a> and relevant database driver package installation.</span>
125 <th scope="row"><label>Path to MDB2.php</label></th>
126 <td><input type="text" name="ext_db_mdb2_path" value="<?php echo get_option('ext_db_mdb2_path'); ?>" /> </td>
127 <td><span class="description">Only when using non-MySQL database and in case this isn't in some sort of include path in your PHP configuration. No trailing slash! e.g., /home/username/php </span></td>
130 <th scope="row"><label>Host</label></th>
131 <td><input type="text" name="ext_host" value="<?php echo get_option('ext_host'); ?>" /> </td>
132 <td><span class="description"><strong style="color:red;">required</strong>; (often localhost)</span> </td>
135 <th scope="row"><label>Port</label></th>
136 <td><input type="text" name="ext_db_port" value="<?php echo get_option('ext_db_port'); ?>" /> </td>
137 <td><span class="description">Only set this if you have a non-standard port for connecting.</span></td>
140 <th scope="row"><label>Name</label></th>
141 <td><input type="text" name="ext_db" value="<?php echo get_option('ext_db'); ?>" /></td>
142 <td><span class="description"><strong style="color:red;">required</strong></span></td>
145 <th scope="row"><label>Username</label></th>
146 <td><input type="text" name="ext_db_user" value="<?php echo get_option('ext_db_user'); ?>" /></td>
147 <td><span class="description"><strong style="color:red;">required</strong>; (recommend select privileges only)</span></td>
150 <th scope="row"><label>Password</label></th>
151 <td><input type="password" name="ext_db_pw" value="<?php echo get_option('ext_db_pw'); ?>" /></td>
152 <td><span class="description"><strong style="color:red;">required</strong></span></td>
155 <th scope="row"><label>User table</label></th>
156 <td><input type="text" name="ext_db_table" value="<?php echo get_option('ext_db_table'); ?>" /></td>
157 <td><span class="description"><strong style="color:red;">required</strong></span></td>
161 <h3>External Database Source Fields</h3>
162 <table class="form-table">
164 <th scope="row"><label>Username</label></th>
165 <td><input type="text" name="ext_db_namefield" value="<?php echo get_option('ext_db_namefield'); ?>" /></td>
166 <td><span class="description"><strong style="color:red;">required</strong></span></td>
169 <th scope="row"><label>Password</label></th>
170 <td><input type="text" name="ext_db_pwfield" value="<?php echo get_option('ext_db_pwfield'); ?>" /></td>
171 <td><span class="description"><strong style="color:red;">required</strong></span><td>
174 <th scope="row">Password encryption method</th>
175 <td><select name="ext_db_enc">
177 switch(get_option('ext_db_enc')) {
179 echo '<option selected="selected">SHA1</option><option>MD5</option><option>Other</option>';
182 echo '<option>SHA1</option><option selected="selected">MD5</option><option>Other</option>';
185 echo '<option>SHA1</option><option selected="selected">MD5</option><option selected="selected">Other</option>';
188 echo '<option selected="selected">SHA1</option><option>MD5</option><option>Other</option>';
193 <td><span class="description"><strong style="color:red;">required</strong>; (using "Other" requires you to enter PHP code below!)</td>
196 <th scope="row"><label>Hash code</label></th>
197 <td><input type="text" name="ext_db_other_enc" size="50" value="<?php echo get_option('ext_db_other_enc'); ?>" /></td>
198 <td><span class="description">Only will run if "Other" is selected and needs to be PHP code. Variable you need to set is $password2, and you have access to (original) $username and $password.</td>
201 <th scope="row"><label>Role check</label></th>
202 <td><input type="text" name="ext_db_role" value="<?php echo get_option('ext_db_role'); ?>" />
204 <select name="ext_db_role_bool">
206 switch(get_option('ext_db_role_bool')) {
208 echo '<option selected="selected">is</option><option>greater than</option><option>less than</option>';
210 case "greater than" :
211 echo '<option>is</option><option selected="selected">greater than</option><option>less than</option>';
214 echo '<option>is</option><option>greater than</option><option selected="selected">less than</option>';
217 echo '<option selected="selected">is</option><option>greater than</option><option>less than</option>';
222 <input type="text" name="ext_db_role_value" value="<?php echo get_option('ext_db_role_value'); ?>" /></td>
223 <td><span class="description">Use this if you have certain user role ids in your external database to further restrict allowed logins. If unused, leave fields blank.</span></td>
226 <th scope="row"><label>First name</label></th>
227 <td><input type="text" name="ext_db_first_name" value="<?php echo get_option('ext_db_first_name'); ?>" /></td>
230 <th scope="row"><label>Last name</label></th>
231 <td><input type="text" name="ext_db_last_name" value="<?php echo get_option('ext_db_last_name'); ?>" /></td>
234 <th scope="row"><label>Homepage</label></th>
235 <td><input type="text" name="ext_db_user_url" value="<?php echo get_option('ext_db_user_url'); ?>" /></td>
238 <th scope="row"><label>Email</label></th>
239 <td><input type="text" name="ext_db_user_email" value="<?php echo get_option('ext_db_user_email'); ?>" /></td>
242 <th scope="row"><label>Bio/description</label></th>
243 <td><input type="text" name="ext_db_description" value="<?php echo get_option('ext_db_description'); ?>" /></td>
246 <th scope="row"><label>AIM screen name</label></th>
247 <td><input type="text" name="ext_db_aim" value="<?php echo get_option('ext_db_aim'); ?>" /></td>
250 <th scope="row"><label>YIM screen name</label></th>
251 <td><input type="text" name="ext_db_yim" value="<?php echo get_option('ext_db_yim'); ?>" /></td>
254 <th scope="row"><label>JABBER screen name</label></th>
255 <td><input type="text" name="ext_db_jabber" value="<?php echo get_option('ext_db_jabber'); ?>" /></td>
259 <table class="form-table">
261 <th scope="row">Custom login message</th>
262 <td><textarea name="ext_db_error_msg" cols=40 rows=4><?php echo htmlspecialchars(get_option('ext_db_error_msg'));?></textarea></td>
263 <td><span class="description">Shows up in login box, e.g., to tell them where to get an account. You can use HTML in this text.</td>
268 <input type="submit" name="Submit" value="Save changes" />
275 //sort-of wrapper for all DB interactions
276 function db_functions($driver,$process,$resource,$query) {
277 if ($driver == "MySQL") { //use built-in PHP mysql connection
280 $port = get_option('ext_db_port');
281 if (!empty($port)) $port = ":".get_option('ext_db_port');
282 $resource = mysql_connect(get_option('ext_host').$port, get_option('ext_db_user'), get_option('ext_db_pw'),true) or die(mysql_error());
283 mysql_select_db(get_option('ext_db'),$resource) or die(mysql_error());
287 $result = mysql_query($query,$resource) or die(mysql_error());
291 return mysql_num_rows($resource);
294 return mysql_fetch_assoc($resource);
297 mysql_close($resource);
302 $mdbpath = get_option('ext_db_mdb2_path')."/MDB2.php";
303 require_once($mdbpath);
306 $port = get_option('ext_db_port');
307 if (!empty($port)) $port = ":".get_option('ext_db_port');
308 $url = strtolower($driver)."://".get_option('ext_db_user').":".get_option('ext_db_pw')."@".get_option('ext_host').$port."/".get_option('ext_db');
309 $resource =& MDB2::connect($url);
310 if(PEAR::isError($resource)) die("Error while connecting : " . $resource->getMessage());
314 $result = $resource->query($query);
315 if(PEAR::isError($result)) die('Failed to issue query, error message : ' . $result->getMessage());
319 return $resource->numRows();
322 return $resource->fetchRow(MDB2_FETCHMODE_ASSOC);
325 $resource->disconnect();
331 //actual meat of plugin - essentially, you're setting $username and $password to pass on to the system.
332 //You check from your external system and insert/update users into the WP system just before WP actually
333 //authenticates with its own database.
334 function ext_db_auth_check_login($username,$password) {
335 require_once('./wp-includes/registration.php');
337 //first figure out the DB type and connect...
338 $driver = get_option('ext_db_type');
339 //if on same host have to use resource id to make sure you don't lose the wp db connection
341 $mdbpath = get_option('ext_db_mdb2_path')."/MDB2.php";
342 if ($mdbpath != "/MDB2.php") @require_once($mdbpath);
344 $resource = db_functions($driver,"connect","","");
345 //prepare the db for unicode queries
346 //to pick up umlauts, non-latin text, etc., without choking
347 $utfquery = "SET NAMES 'utf8'";
348 $resultutf = db_functions($driver,"query",$resource,$utfquery);
350 //do the password hash for comparing
351 switch(get_option('ext_db_enc')) {
353 $password2 = sha1($password);
356 $password2 = md5($password);
358 case "Other" : //right now defaulting to plaintext. People can change code here for their own special hash
359 eval(get_option('ext_db_other_enc'));
364 //first check to see if login exists in external db
365 $query = "SELECT count(*) AS numrows FROM " . get_option('ext_db_table') . " WHERE ".get_option('ext_db_namefield')." = '$username'";
366 $result = db_functions($driver,"query",$resource,$query);
367 $numrows = db_functions($driver,"fetch",$result,"");
368 $numrows = $numrows["numrows"];
371 //then check to see if pw matches and get other fields...
372 $sqlfields['first_name'] = get_option('ext_db_first_name');
373 $sqlfields['last_name'] = get_option('ext_db_last_name');
374 $sqlfields['user_url'] = get_option('ext_db_user_url');
375 $sqlfields['user_email'] = get_option('ext_db_user_email');
376 $sqlfields['description'] = get_option('ext_db_description');
377 $sqlfields['aim'] = get_option('ext_db_aim');
378 $sqlfields['yim'] = get_option('ext_db_yim');
379 $sqlfields['jabber'] = get_option('ext_db_jabber');
380 $sqlfields['ext_db_role'] = get_option('ext_db_role');
382 foreach($sqlfields as $key=>$value) {
383 if ($value == "") unset($sqlfields[$key]);
385 $sqlfields2 = implode(", ",$sqlfields);
387 //just so queries won't error out if there are no relevant fields for extended data.
388 if (empty($sqlfields2)) $sqlfields2 = get_option('ext_db_namefield');
390 $query = "SELECT $sqlfields2 FROM " . get_option('ext_db_table') . " WHERE ".get_option('ext_db_namefield')." = '$username' AND ".get_option('ext_db_pwfield')." = '$password2'";
391 $result = db_functions($driver,"query",$resource,$query);
392 $numrows = db_functions($driver,"numrows",$result,"");
394 if ($numrows) { //create/update wp account from external database if login/pw exact match exists in that db
395 $extfields = db_functions($driver,"fetch",$result,"");
398 //check role, if present.
399 $role = get_option('ext_db_role');
400 if (!empty($role)) { //build the role checker too
401 $rolevalue = $extfields[$sqlfields['ext_db_role']];
402 $rolethresh = get_option('ext_db_role_value');
403 $rolebool = get_option('ext_db_role_bool');
405 if ($rolebool == 'is') {
406 if ($rolevalue == $rolethresh) {}
409 $ext_error = "wrongrole";
413 if ($rolebool == 'greater than') {
414 if ($rolevalue > $rolethresh) {}
417 $ext_error = "wrongrole";
421 if ($rolebool == 'less than') {
422 if ($rolevalue < $rolethresh) {}
425 $ext_error = "wrongrole";
430 //only continue with user update/creation if login/pw is valid AND, if used, proper role perms
432 $userarray['user_login'] = $username;
433 $userarray['user_pass'] = $password;
434 $userarray['first_name'] = $extfields[$sqlfields['first_name']];
435 $userarray['last_name'] = $extfields[$sqlfields['last_name']];
436 $userarray['user_url'] = $extfields[$sqlfields['user_url']];
437 $userarray['user_email'] = $extfields[$sqlfields['user_email']];
438 $userarray['description'] = $extfields[$sqlfields['description']];
439 $userarray['aim'] = $extfields[$sqlfields['aim']];
440 $userarray['yim'] = $extfields[$sqlfields['yim']];
441 $userarray['jabber'] = $extfields[$sqlfields['jabber']];
442 $userarray['display_name'] = $extfields[$sqlfields['first_name']]." ".$extfields[$sqlfields['last_name']];
444 //also if no extended data fields
445 if ($userarray['display_name'] == " ") $userarray['display_name'] = $username;
447 db_functions($driver,"close",$resource,"");
449 //looks like wp functions clean up data before entry, so I'm not going to try to clean out fields beforehand.
450 if ($id = username_exists($username)) { //just do an update
451 $userarray['ID'] = $id;
452 wp_update_user($userarray);
454 else wp_insert_user($userarray); //otherwise create
457 else { //username exists but wrong password...
459 $ext_error = "wrongpw";
463 else { //don't let login even if it's in the WP db - it needs to come only from the external db.
465 $ext_error = "notindb";
471 //gives warning for login - where to get "source" login
472 function ext_db_auth_warning() {
473 echo "<p class=\"message\">".get_option('ext_db_error_msg')."</p>";
476 function ext_db_errors() {
479 if ($ext_error == "notindb")
480 return "<strong>ERROR:</strong> Username not found.";
481 else if ($ext_error == "wrongrole")
482 return "<strong>ERROR:</strong> You don't have permissions to log in.";
483 else if ($ext_error == "wrongpw")
484 return "<strong>ERROR:</strong> Invalid password.";
489 //hopefully grays stuff out.
490 function ext_db_warning() {
491 echo '<strong style="color:red;">Any changes made below WILL NOT be preserved when you login again. You have to change your personal information per instructions found in the <a href="../wp-login.php">login box</a>.</strong>';
494 //disables the (useless) password reset option in WP when this plugin is enabled.
495 function ext_db_show_password_fields() {
501 * Disable functions. Idea taken from http auth plugin.
503 function disable_function_register() {
504 $errors = new WP_Error();
505 $errors->add('registerdisabled', __('User registration is not available from this site, so you can\'t create an account or retrieve your password from here. See the message above.'));
506 ?></form><br /><div id="login_error">User registration is not available from this site, so you can't create an account or retrieve your password from here. See the message above.</div>
507 <p id="backtoblog"><a href="<?php bloginfo('url'); ?>/" title="<?php _e('Are you lost?') ?>"><?php printf(__('← Back to %s'), get_bloginfo('title', 'display' )); ?></a></p>
512 function disable_function() {
513 $errors = new WP_Error();
514 $errors->add('registerdisabled', __('User registration is not available from this site, so you can\'t create an account or retrieve your password from here. See the message above.'));
515 login_header(__('Log In'), '', $errors);
517 <p id="backtoblog"><a href="<?php bloginfo('url'); ?>/" title="<?php _e('Are you lost?') ?>"><?php printf(__('← Back to %s'), get_bloginfo('title', 'display' )); ?></a></p>
523 add_action('admin_init', 'ext_db_auth_init' );
524 add_action('admin_menu', 'ext_db_auth_add_menu');
525 add_action('wp_authenticate', 'ext_db_auth_check_login', 1, 2 );
526 add_action('lost_password', 'disable_function');
527 add_action('user_register', 'disable_function');
528 add_action('register_form', 'disable_function_register');
529 add_action('retrieve_password', 'disable_function');
530 add_action('password_reset', 'disable_function');
531 add_action('profile_personal_options','ext_db_warning');
532 add_filter('login_errors','ext_db_errors');
533 add_filter('show_password_fields','ext_db_show_password_fields');
534 add_filter('login_message','ext_db_auth_warning');
536 register_activation_hook( __FILE__, 'ext_db_auth_activate' );