diff options
author | Nils Adermann <naderman@naderman.de> | 2013-07-14 01:32:34 -0400 |
---|---|---|
committer | Nils Adermann <naderman@naderman.de> | 2013-07-14 01:32:34 -0400 |
commit | 7030578bbe9e11c18b5becaf8b06e670e3c2e3cd (patch) | |
tree | a260c846cb47713e72de11cfb9803d981ea6faaf /phpBB/phpbb/auth/provider | |
parent | 4186c05bb4b97374392031a10b796e77b857afaf (diff) | |
download | forums-7030578bbe9e11c18b5becaf8b06e670e3c2e3cd.tar forums-7030578bbe9e11c18b5becaf8b06e670e3c2e3cd.tar.gz forums-7030578bbe9e11c18b5becaf8b06e670e3c2e3cd.tar.bz2 forums-7030578bbe9e11c18b5becaf8b06e670e3c2e3cd.tar.xz forums-7030578bbe9e11c18b5becaf8b06e670e3c2e3cd.zip |
[ticket/11698] Moving all autoloadable files to phpbb/
PHPBB3-11698
Diffstat (limited to 'phpBB/phpbb/auth/provider')
-rw-r--r-- | phpBB/phpbb/auth/provider/apache.php | 259 | ||||
-rw-r--r-- | phpBB/phpbb/auth/provider/base.php | 72 | ||||
-rw-r--r-- | phpBB/phpbb/auth/provider/db.php | 297 | ||||
-rw-r--r-- | phpBB/phpbb/auth/provider/index.htm | 10 | ||||
-rw-r--r-- | phpBB/phpbb/auth/provider/interface.php | 105 | ||||
-rw-r--r-- | phpBB/phpbb/auth/provider/ldap.php | 346 |
6 files changed, 1089 insertions, 0 deletions
diff --git a/phpBB/phpbb/auth/provider/apache.php b/phpBB/phpbb/auth/provider/apache.php new file mode 100644 index 0000000000..2e80436f78 --- /dev/null +++ b/phpBB/phpbb/auth/provider/apache.php @@ -0,0 +1,259 @@ +<?php +/** +* +* @package auth +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** + * Apache authentication provider for phpBB3 + * + * @package auth + */ +class phpbb_auth_provider_apache extends phpbb_auth_provider_base +{ + /** + * Apache Authentication Constructor + * + * @param phpbb_db_driver $db + * @param phpbb_config $config + * @param phpbb_request $request + * @param phpbb_user $user + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(phpbb_db_driver $db, phpbb_config $config, phpbb_request $request, phpbb_user $user, $phpbb_root_path, $php_ext) + { + $this->db = $db; + $this->config = $config; + $this->request = $request; + $this->user = $user; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * {@inheritdoc} + */ + public function init() + { + if (!$this->request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER) || $this->user->data['username'] !== htmlspecialchars_decode($this->request->server('PHP_AUTH_USER'))) + { + return $this->user->lang['APACHE_SETUP_BEFORE_USE']; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function login($username, $password) + { + // do not allow empty password + if (!$password) + { + return array( + 'status' => LOGIN_ERROR_PASSWORD, + 'error_msg' => 'NO_PASSWORD_SUPPLIED', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!$username) + { + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!$this->request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER)) + { + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + $php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')); + $php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW')); + + if (!empty($php_auth_user) && !empty($php_auth_pw)) + { + if ($php_auth_user !== $username) + { + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type + FROM ' . USERS_TABLE . " + WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if ($row) + { + // User inactive... + if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) + { + return array( + 'status' => LOGIN_ERROR_ACTIVE, + 'error_msg' => 'ACTIVE_ERROR', + 'user_row' => $row, + ); + } + + // Successful login... + return array( + 'status' => LOGIN_SUCCESS, + 'error_msg' => false, + 'user_row' => $row, + ); + } + + // this is the user's first login so create an empty profile + return array( + 'status' => LOGIN_SUCCESS_CREATE_PROFILE, + 'error_msg' => false, + 'user_row' => user_row_apache($php_auth_user, $php_auth_pw), + ); + } + + // Not logged into apache + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + /** + * {@inheritdoc} + */ + public function autologin() + { + if (!$this->request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER)) + { + return array(); + } + + $php_auth_user = htmlspecialchars_decode($this->request->server('PHP_AUTH_USER')); + $php_auth_pw = htmlspecialchars_decode($this->request->server('PHP_AUTH_PW')); + + if (!empty($php_auth_user) && !empty($php_auth_pw)) + { + set_var($php_auth_user, $php_auth_user, 'string', true); + set_var($php_auth_pw, $php_auth_pw, 'string', true); + + $sql = 'SELECT * + FROM ' . USERS_TABLE . " + WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if ($row) + { + return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row; + } + + if (!function_exists('user_add')) + { + include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext); + } + + // create the user if he does not exist yet + user_add(user_row_apache($php_auth_user, $php_auth_pw)); + + $sql = 'SELECT * + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($php_auth_user)) . "'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if ($row) + { + return $row; + } + } + + return array(); + } + + /** + * This function generates an array which can be passed to the user_add + * function in order to create a user + * + * @param string $username The username of the new user. + * @param string $password The password of the new user. + * @return array Contains data that can be passed directly to + * the user_add function. + */ + private function user_row($username, $password) + { + // first retrieve default group id + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "' + AND group_type = " . GROUP_SPECIAL; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (!$row) + { + trigger_error('NO_GROUP'); + } + + // generate user account data + return array( + 'username' => $username, + 'user_password' => phpbb_hash($password), + 'user_email' => '', + 'group_id' => (int) $row['group_id'], + 'user_type' => USER_NORMAL, + 'user_ip' => $this->user->ip, + 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, + ); + } + + /** + * {@inheritdoc} + */ + public function validate_session($user) + { + // Check if PHP_AUTH_USER is set and handle this case + if ($this->request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER)) + { + $php_auth_user = $this->request->server('PHP_AUTH_USER'); + + return ($php_auth_user === $user['username']) ? true : false; + } + + // PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not) + if ($user['user_type'] == USER_IGNORE) + { + return true; + } + + return false; + } +} diff --git a/phpBB/phpbb/auth/provider/base.php b/phpBB/phpbb/auth/provider/base.php new file mode 100644 index 0000000000..7eaf8bb2d3 --- /dev/null +++ b/phpBB/phpbb/auth/provider/base.php @@ -0,0 +1,72 @@ +<?php +/** +* +* @package auth +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Base authentication provider class that all other providers should implement +* +* @package auth +*/ +abstract class phpbb_auth_provider_base implements phpbb_auth_provider_interface +{ + /** + * {@inheritdoc} + */ + public function init() + { + return; + } + + /** + * {@inheritdoc} + */ + public function autologin() + { + return; + } + + /** + * {@inheritdoc} + */ + public function acp() + { + return; + } + + /** + * {@inheritdoc} + */ + public function get_acp_template($new_config) + { + return; + } + + /** + * {@inheritdoc} + */ + public function logout($data, $new_session) + { + return; + } + + /** + * {@inheritdoc} + */ + public function validate_session($user) + { + return; + } +} diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php new file mode 100644 index 0000000000..0934c56d9b --- /dev/null +++ b/phpBB/phpbb/auth/provider/db.php @@ -0,0 +1,297 @@ +<?php +/** +* +* @package auth +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** + * Database authentication provider for phpBB3 + * + * This is for authentication via the integrated user table + * + * @package auth + */ +class phpbb_auth_provider_db extends phpbb_auth_provider_base +{ + + /** + * Database Authentication Constructor + * + * @param phpbb_db_driver $db + * @param phpbb_config $config + * @param phpbb_request $request + * @param phpbb_user $user + * @param string $phpbb_root_path + * @param string $php_ext + */ + public function __construct(phpbb_db_driver $db, phpbb_config $config, phpbb_request $request, phpbb_user $user, $phpbb_root_path, $php_ext) + { + $this->db = $db; + $this->config = $config; + $this->request = $request; + $this->user = $user; + $this->phpbb_root_path = $phpbb_root_path; + $this->php_ext = $php_ext; + } + + /** + * {@inheritdoc} + */ + public function login($username, $password) + { + // Auth plugins get the password untrimmed. + // For compatibility we trim() here. + $password = trim($password); + + // do not allow empty password + if (!$password) + { + return array( + 'status' => LOGIN_ERROR_PASSWORD, + 'error_msg' => 'NO_PASSWORD_SUPPLIED', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!$username) + { + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + $username_clean = utf8_clean_string($username); + + $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $this->db->sql_escape($username_clean) . "'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (($this->user->ip && !$this->config['ip_login_limit_use_forwarded']) || + ($this->user->forwarded_for && $this->config['ip_login_limit_use_forwarded'])) + { + $sql = 'SELECT COUNT(*) AS attempts + FROM ' . LOGIN_ATTEMPT_TABLE . ' + WHERE attempt_time > ' . (time() - (int) $this->config['ip_login_limit_time']); + if ($this->config['ip_login_limit_use_forwarded']) + { + $sql .= " AND attempt_forwarded_for = '" . $this->db->sql_escape($this->user->forwarded_for) . "'"; + } + else + { + $sql .= " AND attempt_ip = '" . $this->db->sql_escape($this->user->ip) . "' "; + } + + $result = $this->db->sql_query($sql); + $attempts = (int) $this->db->sql_fetchfield('attempts'); + $this->db->sql_freeresult($result); + + $attempt_data = array( + 'attempt_ip' => $this->user->ip, + 'attempt_browser' => trim(substr($this->user->browser, 0, 149)), + 'attempt_forwarded_for' => $this->user->forwarded_for, + 'attempt_time' => time(), + 'user_id' => ($row) ? (int) $row['user_id'] : 0, + 'username' => $username, + 'username_clean' => $username_clean, + ); + $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $this->db->sql_build_array('INSERT', $attempt_data); + $result = $this->db->sql_query($sql); + } + else + { + $attempts = 0; + } + + if (!$row) + { + if ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']) + { + return array( + 'status' => LOGIN_ERROR_ATTEMPTS, + 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + $show_captcha = ($this->config['max_login_attempts'] && $row['user_login_attempts'] >= $this->config['max_login_attempts']) || + ($this->config['ip_login_limit_max'] && $attempts >= $this->config['ip_login_limit_max']); + + // If there are too many login attempts, we need to check for a confirm image + // Every auth module is able to define what to do by itself... + if ($show_captcha) + { + // Visual Confirmation handling + if (!class_exists('phpbb_captcha_factory', false)) + { + include ($this->phpbb_root_path . 'includes/captcha/captcha_factory.' . $this->php_ext); + } + + $captcha = phpbb_captcha_factory::get_instance($this->config['captcha_plugin']); + $captcha->init(CONFIRM_LOGIN); + $vc_response = $captcha->validate($row); + if ($vc_response) + { + return array( + 'status' => LOGIN_ERROR_ATTEMPTS, + 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', + 'user_row' => $row, + ); + } + else + { + $captcha->reset(); + } + + } + + // If the password convert flag is set we need to convert it + if ($row['user_pass_convert']) + { + // enable super globals to get literal value + // this is needed to prevent unicode normalization + $super_globals_disabled = $this->request->super_globals_disabled(); + if ($super_globals_disabled) + { + $this->request->enable_super_globals(); + } + + // in phpBB2 passwords were used exactly as they were sent, with addslashes applied + $password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : ''; + $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format; + $password_new_format = $this->request->variable('password', '', true); + + if ($super_globals_disabled) + { + $this->request->disable_super_globals(); + } + + if ($password == $password_new_format) + { + if (!function_exists('utf8_to_cp1252')) + { + include($this->phpbb_root_path . 'includes/utf/data/recode_basic.' . $this->php_ext); + } + + // cp1252 is phpBB2's default encoding, characters outside ASCII range might work when converted into that encoding + // plain md5 support left in for conversions from other systems. + if ((strlen($row['user_password']) == 34 && (phpbb_check_hash(md5($password_old_format), $row['user_password']) || phpbb_check_hash(md5(utf8_to_cp1252($password_old_format)), $row['user_password']))) + || (strlen($row['user_password']) == 32 && (md5($password_old_format) == $row['user_password'] || md5(utf8_to_cp1252($password_old_format)) == $row['user_password']))) + { + $hash = phpbb_hash($password_new_format); + + // Update the password in the users table to the new format and remove user_pass_convert flag + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_password = \'' . $this->db->sql_escape($hash) . '\', + user_pass_convert = 0 + WHERE user_id = ' . $row['user_id']; + $this->db->sql_query($sql); + + $row['user_pass_convert'] = 0; + $row['user_password'] = $hash; + } + else + { + // Although we weren't able to convert this password we have to + // increase login attempt count to make sure this cannot be exploited + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_login_attempts = user_login_attempts + 1 + WHERE user_id = ' . (int) $row['user_id'] . ' + AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; + $this->db->sql_query($sql); + + return array( + 'status' => LOGIN_ERROR_PASSWORD_CONVERT, + 'error_msg' => 'LOGIN_ERROR_PASSWORD_CONVERT', + 'user_row' => $row, + ); + } + } + } + + // Check password ... + if (!$row['user_pass_convert'] && phpbb_check_hash($password, $row['user_password'])) + { + // Check for old password hash... + if (strlen($row['user_password']) == 32) + { + $hash = phpbb_hash($password); + + // Update the password in the users table to the new format + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_password = '" . $this->db->sql_escape($hash) . "', + user_pass_convert = 0 + WHERE user_id = {$row['user_id']}"; + $this->db->sql_query($sql); + + $row['user_password'] = $hash; + } + + $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . ' + WHERE user_id = ' . $row['user_id']; + $this->db->sql_query($sql); + + if ($row['user_login_attempts'] != 0) + { + // Successful, reset login attempts (the user passed all stages) + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_login_attempts = 0 + WHERE user_id = ' . $row['user_id']; + $this->db->sql_query($sql); + } + + // User inactive... + if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) + { + return array( + 'status' => LOGIN_ERROR_ACTIVE, + 'error_msg' => 'ACTIVE_ERROR', + 'user_row' => $row, + ); + } + + // Successful login... set user_login_attempts to zero... + return array( + 'status' => LOGIN_SUCCESS, + 'error_msg' => false, + 'user_row' => $row, + ); + } + + // Password incorrect - increase login attempts + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_login_attempts = user_login_attempts + 1 + WHERE user_id = ' . (int) $row['user_id'] . ' + AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX; + $this->db->sql_query($sql); + + // Give status about wrong password... + return array( + 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, + 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD', + 'user_row' => $row, + ); + } +} diff --git a/phpBB/phpbb/auth/provider/index.htm b/phpBB/phpbb/auth/provider/index.htm new file mode 100644 index 0000000000..ee1f723a7d --- /dev/null +++ b/phpBB/phpbb/auth/provider/index.htm @@ -0,0 +1,10 @@ +<html> +<head> +<title></title> +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> +</head> + +<body bgcolor="#FFFFFF" text="#000000"> + +</body> +</html> diff --git a/phpBB/phpbb/auth/provider/interface.php b/phpBB/phpbb/auth/provider/interface.php new file mode 100644 index 0000000000..47043bc107 --- /dev/null +++ b/phpBB/phpbb/auth/provider/interface.php @@ -0,0 +1,105 @@ +<?php +/** +* +* @package auth +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** + * The interface authentication provider classes have to implement. + * + * @package auth + */ +interface phpbb_auth_provider_interface +{ + /** + * Checks whether the user is currently identified to the authentication + * provider. + * Called in acp_board while setting authentication plugins. + * Changing to an authentication provider will not be permitted in acp_board + * if there is an error. + * + * @return boolean|string False if the user is identified, otherwise an + * error message, or null if not implemented. + */ + public function init(); + + /** + * Performs login. + * + * @param string $username The name of the user being authenticated. + * @param string $password The password of the user. + * @return array An associative array of the format: + * array( + * 'status' => status constant + * 'error_msg' => string + * 'user_row' => array + * ) + */ + public function login($username, $password); + + /** + * Autologin function + * + * @return array|null containing the user row, empty if no auto login + * should take place, or null if not impletmented. + */ + public function autologin(); + + /** + * This function is used to output any required fields in the authentication + * admin panel. It also defines any required configuration table fields. + * + * @return array|null Returns null if not implemented or an array of the + * configuration fields of the provider. + */ + public function acp(); + + /** + * This function updates the template with variables related to the acp + * options with whatever configuraton values are passed to it as an array. + * It then returns the name of the acp file related to this authentication + * provider. + * @param array $new_config Contains the new configuration values that + * have been set in acp_board. + * @return array|null Returns null if not implemented or an array with + * the template file name and an array of the vars + * that the template needs that must conform to the + * following example: + * array( + * 'TEMPLATE_FILE' => string, + * 'TEMPLATE_VARS' => array(...), + * ) + */ + public function get_acp_template($new_config); + + /** + * Performs additional actions during logout. + * + * @param array $data An array corresponding to + * phpbb_session::data + * @param boolean $new_session True for a new session, false for no new + * session. + */ + public function logout($data, $new_session); + + /** + * The session validation function checks whether the user is still logged + * into phpBB. + * + * @param array $user + * @return boolean true if the given user is authenticated, false if the + * session should be closed, or null if not implemented. + */ + public function validate_session($user); +} diff --git a/phpBB/phpbb/auth/provider/ldap.php b/phpBB/phpbb/auth/provider/ldap.php new file mode 100644 index 0000000000..0196529408 --- /dev/null +++ b/phpBB/phpbb/auth/provider/ldap.php @@ -0,0 +1,346 @@ +<?php +/** +* +* @package auth +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** + * Database authentication provider for phpBB3 + * + * This is for authentication via the integrated user table + * + * @package auth + */ +class phpbb_auth_provider_ldap extends phpbb_auth_provider_base +{ + /** + * LDAP Authentication Constructor + * + * @param phpbb_db_driver $db + * @param phpbb_config $config + * @param phpbb_user $user + */ + public function __construct(phpbb_db_driver $db, phpbb_config $config, phpbb_user $user) + { + $this->db = $db; + $this->config = $config; + $this->user = $user; + } + + /** + * {@inheritdoc} + */ + public function init() + { + if (!@extension_loaded('ldap')) + { + return $this->user->lang['LDAP_NO_LDAP_EXTENSION']; + } + + $this->config['ldap_port'] = (int) $this->config['ldap_port']; + if ($this->config['ldap_port']) + { + $ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']); + } + else + { + $ldap = @ldap_connect($this->config['ldap_server']); + } + + if (!$ldap) + { + return $this->user->lang['LDAP_NO_SERVER_CONNECTION']; + } + + @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); + @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); + + if ($this->config['ldap_user'] || $this->config['ldap_password']) + { + if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) + { + return $this->user->lang['LDAP_INCORRECT_USER_PASSWORD']; + } + } + + // ldap_connect only checks whether the specified server is valid, so the connection might still fail + $search = @ldap_search( + $ldap, + htmlspecialchars_decode($this->config['ldap_base_dn']), + $this->ldap_user_filter($this->user->data['username']), + (empty($this->config['ldap_email'])) ? + array(htmlspecialchars_decode($this->config['ldap_uid'])) : + array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])), + 0, + 1 + ); + + if ($search === false) + { + return $this->user->lang['LDAP_SEARCH_FAILED']; + } + + $result = @ldap_get_entries($ldap, $search); + + @ldap_close($ldap); + + + if (!is_array($result) || sizeof($result) < 2) + { + return sprintf($this->user->lang['LDAP_NO_IDENTITY'], $this->user->data['username']); + } + + if (!empty($this->config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($this->config['ldap_email'])])) + { + return $this->user->lang['LDAP_NO_EMAIL']; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function login($username, $password) + { + // do not allow empty password + if (!$password) + { + return array( + 'status' => LOGIN_ERROR_PASSWORD, + 'error_msg' => 'NO_PASSWORD_SUPPLIED', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!$username) + { + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + if (!@extension_loaded('ldap')) + { + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'LDAP_NO_LDAP_EXTENSION', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + $this->config['ldap_port'] = (int) $this->config['ldap_port']; + if ($this->config['ldap_port']) + { + $ldap = @ldap_connect($this->config['ldap_server'], $this->config['ldap_port']); + } + else + { + $ldap = @ldap_connect($this->config['ldap_server']); + } + + if (!$ldap) + { + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3); + @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0); + + if ($this->config['ldap_user'] || $this->config['ldap_password']) + { + if (!@ldap_bind($ldap, htmlspecialchars_decode($this->config['ldap_user']), htmlspecialchars_decode($this->config['ldap_password']))) + { + return array( + 'status' => LOGIN_ERROR_EXTERNAL_AUTH, + 'error_msg' => 'LDAP_NO_SERVER_CONNECTION', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + } + + $search = @ldap_search( + $ldap, + htmlspecialchars_decode($this->config['ldap_base_dn']), + $this->ldap_user_filter($username), + (empty($this->config['ldap_email'])) ? + array(htmlspecialchars_decode($this->config['ldap_uid'])) : + array(htmlspecialchars_decode($this->config['ldap_uid']), htmlspecialchars_decode($this->config['ldap_email'])), + 0, + 1 + ); + + $ldap_result = @ldap_get_entries($ldap, $search); + + if (is_array($ldap_result) && sizeof($ldap_result) > 1) + { + if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password))) + { + @ldap_close($ldap); + + $sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type + FROM ' . USERS_TABLE . " + WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'"; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if ($row) + { + unset($ldap_result); + + // User inactive... + if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) + { + return array( + 'status' => LOGIN_ERROR_ACTIVE, + 'error_msg' => 'ACTIVE_ERROR', + 'user_row' => $row, + ); + } + + // Successful login... set user_login_attempts to zero... + return array( + 'status' => LOGIN_SUCCESS, + 'error_msg' => false, + 'user_row' => $row, + ); + } + else + { + // retrieve default group id + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "' + AND group_type = " . GROUP_SPECIAL; + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (!$row) + { + trigger_error('NO_GROUP'); + } + + // generate user account data + $ldap_user_row = array( + 'username' => $username, + 'user_password' => phpbb_hash($password), + 'user_email' => (!empty($this->config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($this->config['ldap_email'])][0]) : '', + 'group_id' => (int) $row['group_id'], + 'user_type' => USER_NORMAL, + 'user_ip' => $this->user->ip, + 'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0, + ); + + unset($ldap_result); + + // this is the user's first login so create an empty profile + return array( + 'status' => LOGIN_SUCCESS_CREATE_PROFILE, + 'error_msg' => false, + 'user_row' => $ldap_user_row, + ); + } + } + else + { + unset($ldap_result); + @ldap_close($ldap); + + // Give status about wrong password... + return array( + 'status' => LOGIN_ERROR_PASSWORD, + 'error_msg' => 'LOGIN_ERROR_PASSWORD', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + } + + @ldap_close($ldap); + + return array( + 'status' => LOGIN_ERROR_USERNAME, + 'error_msg' => 'LOGIN_ERROR_USERNAME', + 'user_row' => array('user_id' => ANONYMOUS), + ); + } + + /** + * {@inheritdoc} + */ + + public function acp() + { + // These are fields required in the config table + return array( + 'ldap_server', 'ldap_port', 'ldap_base_dn', 'ldap_uid', 'ldap_user_filter', 'ldap_email', 'ldap_user', 'ldap_password', + ); + } + + /** + * {@inheritdoc} + */ + public function get_acp_template($new_config) + { + return array( + 'TEMPLATE_FILE' => 'auth_provider_ldap.html', + 'TEMPLATE_VARS' => array( + 'AUTH_LDAP_DN' => $new_config['ldap_base_dn'], + 'AUTH_LDAP_EMAIL' => $new_config['ldap_email'], + 'AUTH_LDAP_PASSORD' => $new_config['ldap_password'], + 'AUTH_LDAP_PORT' => $new_config['ldap_port'], + 'AUTH_LDAP_SERVER' => $new_config['ldap_server'], + 'AUTH_LDAP_UID' => $new_config['ldap_uid'], + 'AUTH_LDAP_USER' => $new_config['ldap_user'], + 'AUTH_LDAP_USER_FILTER' => $new_config['ldap_user_filter'], + ), + ); + } + + /** + * Generates a filter string for ldap_search to find a user + * + * @param $username string Username identifying the searched user + * + * @return string A filter string for ldap_search + */ + private function ldap_user_filter($username) + { + $filter = '(' . $this->config['ldap_uid'] . '=' . $this->ldap_escape(htmlspecialchars_decode($username)) . ')'; + if ($this->config['ldap_user_filter']) + { + $_filter = ($this->config['ldap_user_filter'][0] == '(' && substr($this->config['ldap_user_filter'], -1) == ')') ? $this->config['ldap_user_filter'] : "({$this->config['ldap_user_filter']})"; + $filter = "(&{$filter}{$_filter})"; + } + return $filter; + } + + /** + * Escapes an LDAP AttributeValue + * + * @param string $string The string to be escaped + * @return string The escaped string + */ + private function ldap_escape($string) + { + return str_replace(array('*', '\\', '(', ')'), array('\\*', '\\\\', '\\(', '\\)'), $string); + } +} |