Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (danger)
50.00%
1 / 2
CRAP
43.59% covered (danger)
43.59%
51 / 117
db
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (danger)
50.00%
1 / 2
137.19
43.59% covered (danger)
43.59%
51 / 117
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
9 / 9
 login
0.00% covered (danger)
0.00%
0 / 1
155.46
38.89% covered (danger)
38.89%
42 / 108
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/
namespace phpbb\auth\provider;
/**
 * Database authentication provider for phpBB3
 * This is for authentication via the integrated user table
 */
class db extends \phpbb\auth\provider\base
{
    /**
    * phpBB passwords manager
    *
    * @var \phpbb\passwords\manager
    */
    protected $passwords_manager;
    /**
    * DI container
    *
    * @var \Symfony\Component\DependencyInjection\ContainerInterface
    */
    protected $phpbb_container;
    /**
     * Database Authentication Constructor
     *
     * @param    \phpbb\db\driver\driver_interface        $db
     * @param    \phpbb\config\config         $config
     * @param    \phpbb\passwords\manager    $passwords_manager
     * @param    \phpbb\request\request        $request
     * @param    \phpbb\user            $user
     * @param    \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container DI container
     * @param    string                $phpbb_root_path
     * @param    string                $php_ext
     */
    public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request $request, \phpbb\user $user, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, $phpbb_root_path, $php_ext)
    {
        $this->db = $db;
        $this->config = $config;
        $this->passwords_manager = $passwords_manager;
        $this->request = $request;
        $this->user = $user;
        $this->phpbb_root_path = $phpbb_root_path;
        $this->php_ext = $php_ext;
        $this->phpbb_container = $phpbb_container;
    }
    /**
     * {@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 *
            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);
            $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)
        {
            /* @var $captcha_factory \phpbb\captcha\factory */
            $captcha_factory = $this->phpbb_container->get('captcha.factory');
            $captcha = $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();
            }
        }
        // Check password ...
        if ($this->passwords_manager->check($password, $row['user_password'], $row))
        {
            // Check for old password hash...
            if ($this->passwords_manager->convert_flag || strlen($row['user_password']) == 32)
            {
                $hash = $this->passwords_manager->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) . "'
                    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'        => 'LOGIN_ERROR_PASSWORD',
            'user_row'        => $row,
        );
    }
}