* @copyright 2007 Sam Bauers * @license http://www.gnu.org/licenses/gpl.txt GNU General Public License v2 * @version 2.0 **/ /** * Container class for LDAP authentication * * @author Sam Bauers * @version 1.0 **/ class LDAP_Authentication { /** * The current version of the plugin * * @var string **/ public $version = '2.0'; /** * Whether the plugin is enabled * * @var boolean **/ public $enabled; /** * An array of settings for the LDAP server connection * * @var array **/ public $server; /** * Whether the plugin has enough settings to work * * @var boolean **/ private $active = false; /** * Additional plugin options in an array * * @var array **/ public $options; /** * Pulls out database settings * * @return void * @author Sam Bauers **/ public function __construct() { // An integer set to 1 for enabled or 0 for disabled $this->enabled = bb_get_option('ldap_authentication_enabled'); $this->server = bb_get_option('ldap_authentication_server'); if (isset($this->server['host']) && isset($this->server['domain'])) { $this->active = true; } $this->options = bb_get_option('ldap_authentication_options'); } /** * Returns whether the plugin is active or not * * @return boolean * @author Sam Bauers **/ public function isActive() { if ($this->enabled && $this->active) { return true; } else { return false; } } /** * Determines whether we are viewing the given page * * Mostly adapted from bb_get_location(); * * @return boolean * @author Sam Bauers **/ private function locationIs($page) { $names = array( $_SERVER['PHP_SELF'], $_SERVER['SCRIPT_FILENAME'], $_SERVER['SCRIPT_NAME'] ); foreach ($names as $name) { if (false !== strpos($name, '.php')) { $file = $name; } } if (bb_find_filename($file) == $page) { return true; } else { return false; } } /** * Disables standard registration * * @return void * @author Sam Bauers **/ public function disableRegistration() { if ($this->isActive() && $this->options['disable_registration'] && $this->locationIs('register.php')) { bb_die(__('Registration is disabled for this forum, please login using your LDAP username and password.')); } } /** * Disables password recovery for users who have LDAP passwords * * @return void * @author Sam Bauers **/ public function disableLDAPpasswordRecovery() { if ($this->isActive() && $this->locationIs('bb-reset-password.php')) { $user_login = user_sanitize($_POST['user_login']); if (!empty($user_login)) { $user = bb_get_user_by_name($user_login); if (substr($user->user_pass, 0, 5) == '^LDAP') { bb_die(__('Password recovery is not possible for this account because it uses an LDAP username and password to login. To change your LDAP password, please contact your system administrator.')); } } } } /** * Disables password editing for users who have LDAP passwords * * @return void * @author Sam Bauers **/ public function disableLDAPpasswordEditing() { global $bb_current_user; if ($this->isActive() && ($this->locationIs('profile.php') || $this->locationIs('profile-edit.php'))) { if (substr($bb_current_user->data->user_pass, 0, 5) == '^LDAP') { add_filter('bb_user_has_cap', array($this, 'removePasswordCapability'), 10, 2); } } } /** * Removes the change password capability for the current user * * @return array * @author Sam Bauers **/ public function removePasswordCapability($allcaps, $caps) { if ($caps[0] == 'change_password') { unset($allcaps['change_password']); } return $allcaps; } /** * Replacement for bb_check_login * * @return object * @author Sam Bauers **/ public function checkLogin($user, $pass, $already_md5 = false) { global $bbdb; $user = user_sanitize($user); if (!$already_md5) { $user_exists = bb_user_exists($user); if (!$user_exists) { // Check using LDAP if (!$this->options['disable_automatic_ldap_registration'] && $mail = $this->connectUser($user, $pass, true)) { // Create the new user in the local database if ($user_id = $this->newUser($user, $pass, $mail)) { return $bbdb->get_row("SELECT * FROM $bbdb->users WHERE `ID` = $user_id"); } else { bb_die(__('Failed to add new LDAP user to local database.')); } } else { return false; } } else { if (substr($user_exists->user_pass, 0, 5) == '^LDAP') { if ($this->connectUser($user, $pass)) { // Update their MD5 hash in case their password has changed $bbdb->query("UPDATE $bbdb->users SET user_pass = '^LDAP-" . md5($pass) . "' WHERE user_login = '$user'"); // Get their record from the local database return $bbdb->get_row("SELECT * FROM $bbdb->users WHERE user_login = '$user' AND SUBSTRING(SUBSTRING_INDEX(user_pass, '---', 1), 1, 5) = '^LDAP'"); } else { return false; } } else { $pass = user_sanitize(md5($pass)); return $bbdb->get_row("SELECT * FROM $bbdb->users WHERE user_login = '$user' AND SUBSTRING_INDEX(user_pass, '---', 1) = '$pass'"); } } } else { return $bbdb->get_row("SELECT * FROM $bbdb->users WHERE user_login = '$user' AND MD5( user_pass ) = '$pass'"); } } /** * Connects the user to the LDAP server * * @return mixed * @author Sam Bauers **/ private function connectUser($user, $pass, $register = false) { if ($this->server['port']) { $connection = ldap_connect($this->server['host'], $this->server['port']); } else { $connection = ldap_connect($this->server['host']); } if ($this->server['options']) { $options = explode('|', $this->server['options']); foreach ($options as $option) { $optionParts = explode(':', $option); ldap_set_option($connection, $optionParts[0], $optionParts[1]); } } if ($this->server['tls']) { // TLS requires ldap protocol version 3 ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3); $tlsStart = ldap_start_tls($connection); } else { $tlsStart = true; } if ($connection && $tlsStart) { $uid = 'uid=' . stripslashes(addslashes($user)); $bindString = $uid . ',' . $this->server['domain']; $result = ldap_bind($connection, $bindString, stripslashes(addslashes($pass))); if ($result) { $mail = true; if ($register && $this->options['enable_email_retrieval_from_ldap']) { if ($search = ldap_search($connection, $this->server['domain'], '(' . $uid . ')', array('mail'))) { if ($entry = ldap_first_entry($connection, $search)) { $attributes = ldap_get_attributes($connection, $entry); $mail = $attributes['mail'][0]; } } } ldap_unbind($result); ldap_close($connection); return $mail; } else { ldap_close($connection); return FALSE; } } else { bb_die(__('Could not connect to LDAP authentication service.')); } } /** * Creates a new user with an LDAP password * * @return integer * @author Sam Bauers **/ private function newUser($user_login, $user_pass, $user_email) { global $bbdb; global $bb_table_prefix; $now = bb_current_time('mysql'); $password = '^LDAP-' . md5($user_pass); if ($user_email !== true) { $email = $user_email; } $bbdb->query("INSERT INTO $bbdb->users (user_login, user_pass, user_email, user_registered) VALUES ('$user_login', '$password', '$email', '$now')"); $user_id = $bbdb->insert_id; bb_update_usermeta($user_id, $bb_table_prefix . 'capabilities', array('member' => true)); do_action('ldap_authentication_new_user', $user_id); return $user_id; } } // END class LDAP_Authentication // Initialise the class $ldap_authentication = new LDAP_Authentication(); // If active, then add filters via API if ($ldap_authentication->isActive()) { add_action('bb_init', array($ldap_authentication, 'disableRegistration')); add_action('bb_init', array($ldap_authentication, 'disableLDAPpasswordRecovery')); add_action('bb_init', array($ldap_authentication, 'disableLDAPpasswordEditing')); /** * Alias that hooks into LDAP_Authentication class checkLogin function * * This is a pluggable function, so it must sit outside the class like this * * @return object * @author Sam Bauers **/ function bb_check_login($user, $pass, $already_md5 = false) { global $ldap_authentication; return $ldap_authentication->checkLogin($user, $pass, $already_md5); } } /** * The admin pages below are handled outside of the class due to constraints * in the architecture of the admin menu generation routine in bbPress */ // Add filters for the admin area add_action('bb_admin_menu_generator', 'ldap_authentication_admin_page_add'); add_action('bb_admin-header.php','ldap_authentication_admin_page_process'); /** * Adds in an item to the $bb_admin_submenu array * * @return void * @author Sam Bauers **/ function ldap_authentication_admin_page_add() { if (function_exists('bb_admin_add_submenu')) { // Build 794+ bb_admin_add_submenu(__('LDAP authentication'), 'use_keys', 'ldap_authentication_admin_page'); } else { global $bb_submenu; $submenu = array(__('LDAP authentication'), 'use_keys', 'ldap_authentication_admin_page'); if (isset($bb_submenu['plugins.php'])) { // Build 740-793 $bb_submenu['plugins.php'][] = $submenu; } else { // Build 277-739 $bb_submenu['site.php'][] = $submenu; } } } /** * Writes an admin page for the plugin * * @return string * @author Sam Bauers **/ function ldap_authentication_admin_page() { $enabled = bb_get_option('ldap_authentication_enabled'); $options = bb_get_option('ldap_authentication_options'); $server = bb_get_option('ldap_authentication_server'); if ($enabled) { $enabled_checked = ' checked="checked"'; } if ($options['enable_email_retrieval_from_ldap']) { $enable_email_retrieval_from_ldap_checked = ' checked="checked"'; } if ($options['disable_automatic_ldap_registration']) { $disable_automatic_ldap_registration_checked = ' checked="checked"'; } if ($options['disable_registration']) { $disable_registration_checked = ' checked="checked"'; } if ($server['tls']) { $tls_checked = ' checked="checked"'; } ?>