Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
39.66% covered (danger)
39.66%
46 / 116
16.67% covered (danger)
16.67%
1 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
apache
39.66% covered (danger)
39.66%
46 / 116
16.67% covered (danger)
16.67%
1 / 6
227.77
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 init
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 login
36.36% covered (danger)
36.36%
20 / 55
0.00% covered (danger)
0.00%
0 / 1
35.77
 autologin
51.85% covered (warning)
51.85%
14 / 27
0.00% covered (danger)
0.00%
0 / 1
18.04
 user_row
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 validate_session
50.00% covered (danger)
50.00%
3 / 6
0.00% covered (danger)
0.00%
0 / 1
6.00
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14namespace phpbb\auth\provider;
15
16use phpbb\config\config;
17use phpbb\db\driver\driver_interface;
18use phpbb\language\language;
19use phpbb\request\request_interface;
20use phpbb\request\type_cast_helper;
21use phpbb\user;
22
23/**
24* Apache authentication provider for phpBB3
25*/
26class apache extends base
27{
28    /** @var config phpBB config */
29    protected $config;
30
31    /** @var driver_interface Database object */
32    protected $db;
33
34    /** @var language Language object */
35    protected $language;
36
37    /** @var request_interface Request object */
38    protected $request;
39
40    /** @var user User object */
41    protected $user;
42
43    /** @var string Relative path to phpBB root */
44    protected $phpbb_root_path;
45
46    /** @var string PHP file extension */
47    protected $php_ext;
48
49    /**
50     * Apache Authentication Constructor
51     *
52     * @param    config                 $config        Config object
53     * @param    driver_interface     $db        Database object
54     * @param    language            $language Language object
55     * @param    request_interface     $request        Request object
56     * @param    user                 $user        User object
57     * @param    string                 $phpbb_root_path        Relative path to phpBB root
58     * @param    string                 $php_ext        PHP file extension
59     */
60    public function __construct(config $config, driver_interface $db, language $language, request_interface $request, user $user, $phpbb_root_path, $php_ext)
61    {
62        $this->config = $config;
63        $this->db = $db;
64        $this->language = $language;
65        $this->request = $request;
66        $this->user = $user;
67        $this->phpbb_root_path = $phpbb_root_path;
68        $this->php_ext = $php_ext;
69    }
70
71    /**
72     * {@inheritdoc}
73     */
74    public function init()
75    {
76        if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER) || $this->user->data['username'] !== html_entity_decode($this->request->server('PHP_AUTH_USER'), ENT_COMPAT))
77        {
78            return $this->language->lang('APACHE_SETUP_BEFORE_USE');
79        }
80        return false;
81    }
82
83    /**
84     * {@inheritdoc}
85     */
86    public function login($username, $password)
87    {
88        // do not allow empty password
89        if (!$password)
90        {
91            return array(
92                'status'    => LOGIN_ERROR_PASSWORD,
93                'error_msg'    => 'NO_PASSWORD_SUPPLIED',
94                'user_row'    => array('user_id' => ANONYMOUS),
95            );
96        }
97
98        if (!$username)
99        {
100            return array(
101                'status'    => LOGIN_ERROR_USERNAME,
102                'error_msg'    => 'LOGIN_ERROR_USERNAME',
103                'user_row'    => array('user_id' => ANONYMOUS),
104            );
105        }
106
107        if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER))
108        {
109            return array(
110                'status'        => LOGIN_ERROR_EXTERNAL_AUTH,
111                'error_msg'        => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE',
112                'user_row'        => array('user_id' => ANONYMOUS),
113            );
114        }
115
116        $php_auth_user = html_entity_decode($this->request->server('PHP_AUTH_USER'), ENT_COMPAT);
117        $php_auth_pw = html_entity_decode($this->request->server('PHP_AUTH_PW'), ENT_COMPAT);
118
119        if (!empty($php_auth_user) && !empty($php_auth_pw))
120        {
121            if ($php_auth_user !== $username)
122            {
123                return array(
124                    'status'    => LOGIN_ERROR_USERNAME,
125                    'error_msg'    => 'LOGIN_ERROR_USERNAME',
126                    'user_row'    => array('user_id' => ANONYMOUS),
127                );
128            }
129
130            $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
131                FROM ' . USERS_TABLE . "
132                WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'";
133            $result = $this->db->sql_query($sql);
134            $row = $this->db->sql_fetchrow($result);
135            $this->db->sql_freeresult($result);
136
137            if ($row)
138            {
139                // User inactive...
140                if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
141                {
142                    return array(
143                        'status'        => LOGIN_ERROR_ACTIVE,
144                        'error_msg'        => 'ACTIVE_ERROR',
145                        'user_row'        => $row,
146                    );
147                }
148
149                // Successful login...
150                return array(
151                    'status'        => LOGIN_SUCCESS,
152                    'error_msg'        => false,
153                    'user_row'        => $row,
154                );
155            }
156
157            // this is the user's first login so create an empty profile
158            return array(
159                'status'        => LOGIN_SUCCESS_CREATE_PROFILE,
160                'error_msg'        => false,
161                'user_row'        => $this->user_row($php_auth_user),
162            );
163        }
164
165        // Not logged into apache
166        return array(
167            'status'        => LOGIN_ERROR_EXTERNAL_AUTH,
168            'error_msg'        => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE',
169            'user_row'        => array('user_id' => ANONYMOUS),
170        );
171    }
172
173    /**
174     * {@inheritdoc}
175     */
176    public function autologin()
177    {
178        if (!$this->request->is_set('PHP_AUTH_USER', request_interface::SERVER))
179        {
180            return array();
181        }
182
183        $php_auth_user = html_entity_decode($this->request->server('PHP_AUTH_USER'), ENT_COMPAT);
184        $php_auth_pw = html_entity_decode($this->request->server('PHP_AUTH_PW'), ENT_COMPAT);
185
186        if (!empty($php_auth_user) && !empty($php_auth_pw))
187        {
188            $type_cast_helper = new type_cast_helper();
189            $type_cast_helper->set_var($php_auth_user, $php_auth_user, 'string', true);
190
191            $sql = 'SELECT *
192                FROM ' . USERS_TABLE . "
193                WHERE username = '" . $this->db->sql_escape($php_auth_user) . "'";
194            $result = $this->db->sql_query($sql);
195            $row = $this->db->sql_fetchrow($result);
196            $this->db->sql_freeresult($result);
197
198            if ($row)
199            {
200                return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row;
201            }
202
203            if (!function_exists('user_add'))
204            {
205                include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
206            }
207
208            // create the user if he does not exist yet
209            user_add($this->user_row($php_auth_user));
210
211            $sql = 'SELECT *
212                FROM ' . USERS_TABLE . "
213                WHERE username_clean = '" . $this->db->sql_escape(utf8_clean_string($php_auth_user)) . "'";
214            $result = $this->db->sql_query($sql);
215            $row = $this->db->sql_fetchrow($result);
216            $this->db->sql_freeresult($result);
217
218            if ($row)
219            {
220                return $row;
221            }
222        }
223
224        return array();
225    }
226
227    /**
228     * This function generates an array which can be passed to the user_add
229     * function in order to create a user
230     *
231     * @param     string    $username     The username of the new user.
232     *
233     * @return     array                 Contains data that can be passed directly to
234     *                                the user_add function.
235     */
236    private function user_row($username)
237    {
238        // first retrieve default group id
239        $sql = 'SELECT group_id
240            FROM ' . GROUPS_TABLE . "
241            WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "'
242                AND group_type = " . GROUP_SPECIAL;
243        $result = $this->db->sql_query($sql);
244        $row = $this->db->sql_fetchrow($result);
245        $this->db->sql_freeresult($result);
246
247        if (!$row)
248        {
249            trigger_error('NO_GROUP');
250        }
251
252        // generate user account data
253        return array(
254            'username'        => $username,
255            'user_password'    => '',
256            'user_email'    => '',
257            'group_id'        => (int) $row['group_id'],
258            'user_type'        => USER_NORMAL,
259            'user_ip'        => $this->user->ip,
260            'user_new'        => ($this->config['new_member_post_limit']) ? 1 : 0,
261        );
262    }
263
264    /**
265     * {@inheritdoc}
266     */
267    public function validate_session($user)
268    {
269        // Check if PHP_AUTH_USER is set and handle this case
270        if ($this->request->is_set('PHP_AUTH_USER', request_interface::SERVER))
271        {
272            $php_auth_user = $this->request->server('PHP_AUTH_USER');
273
274            return ($php_auth_user === $user['username']) ? true : false;
275        }
276
277        // PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not)
278        if ($user['user_type'] == USER_IGNORE)
279        {
280            return true;
281        }
282
283        return false;
284    }
285}