1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22class CWebUser {
23
24	public static $data = null;
25
26	/**
27	 * Flag used to not to extend session lifetime in checkAuthentication.
28	 */
29	static $extend_session = true;
30
31	/**
32	 * Disable automatic session extension.
33	 */
34	public static function disableSessionExtension() {
35		self::$extend_session = false;
36	}
37
38	/**
39	 * Tries to login a user and populates self::$data on success.
40	 *
41	 * @param string $login     user login
42	 * @param string $password  user password
43	 *
44	 * @throws Exception if user cannot be logged in
45	 *
46	 * @return bool
47	 */
48	public static function login(string $login, string $password): bool {
49		try {
50			self::$data = API::User()->login([
51				'username' => $login,
52				'password' => $password,
53				'userData' => true
54			]);
55
56			if (!self::$data) {
57				throw new Exception();
58			}
59
60			API::getWrapper()->auth = self::$data['sessionid'];
61
62			if (self::$data['gui_access'] == GROUP_GUI_ACCESS_DISABLED) {
63				error(_('GUI access disabled.'));
64				throw new Exception();
65			}
66
67			$result = (bool) self::$data;
68
69			if (isset(self::$data['attempt_failed']) && self::$data['attempt_failed']) {
70				CProfile::init();
71				CProfile::update('web.login.attempt.failed', self::$data['attempt_failed'], PROFILE_TYPE_INT);
72				CProfile::update('web.login.attempt.ip', self::$data['attempt_ip'], PROFILE_TYPE_STR);
73				CProfile::update('web.login.attempt.clock', self::$data['attempt_clock'], PROFILE_TYPE_INT);
74				$result &= CProfile::flush();
75			}
76
77			return $result;
78		}
79		catch (Exception $e) {
80			self::setDefault();
81			return false;
82		}
83	}
84
85	/**
86	 * Log-out the current user.
87	 */
88	public static function logout(): void {
89		if (API::User()->logout([])) {
90			self::$data = null;
91			session_destroy();
92		}
93	}
94
95	public static function checkAuthentication(string $sessionid): bool {
96		try {
97			self::$data = API::User()->checkAuthentication([
98				'sessionid' => $sessionid,
99				'extend' => self::$extend_session
100			]);
101
102			if (empty(self::$data)) {
103				CMessageHelper::clear();
104				self::$data = API::User()->login([
105					'username' => ZBX_GUEST_USER,
106					'password' => '',
107					'userData' => true
108				]);
109
110				if (empty(self::$data)) {
111					throw new Exception();
112				}
113			}
114
115			if (self::$data['gui_access'] == GROUP_GUI_ACCESS_DISABLED) {
116				throw new Exception();
117			}
118
119			return true;
120		}
121		catch (Exception $e) {
122			return false;
123		}
124	}
125
126	/**
127	 * Checks access of authenticated user to specific access rule.
128	 *
129	 * @static
130	 *
131	 * @param string $rule_name  Rule name.
132	 *
133	 * @return bool  Returns true if user has access to specified rule, false - otherwise.
134	 */
135	public static function checkAccess(string $rule_name): bool {
136		if (empty(self::$data) || self::$data['roleid'] == 0) {
137			return false;
138		}
139
140		return CRoleHelper::checkAccess($rule_name, self::$data['roleid']);
141	}
142
143	/**
144	 * Sets user data defaults.
145	 *
146	 * @static
147	 */
148	public static function setDefault(): void {
149		self::$data = [
150			'sessionid' => CEncryptHelper::generateKey(),
151			'username' => ZBX_GUEST_USER,
152			'userid' => 0,
153			'lang' => CSettingsHelper::getGlobal(CSettingsHelper::DEFAULT_LANG),
154			'type' => 0,
155			'gui_access' => GROUP_GUI_ACCESS_SYSTEM,
156			'debug_mode' => false,
157			'roleid' => 0,
158			'autologin' => 0
159		];
160	}
161
162	/**
163	 * Returns the type of the current user.
164	 *
165	 * @static
166	 *
167	 * @return int
168	 */
169	public static function getType() {
170		return self::$data ? self::$data['type'] : 0;
171	}
172
173	/**
174	 * Returns true if debug mode is enabled.
175	 *
176	 * @return bool
177	 */
178	public static function getDebugMode() {
179		return (self::$data && self::$data['debug_mode']);
180	}
181
182	/**
183	 * Returns true if the current user is logged in.
184	 *
185	 * @return bool
186	 */
187	public static function isLoggedIn() {
188		return (self::$data && self::$data['userid']);
189	}
190
191	/**
192	 * Returns true if the user is not logged in or logged in as Guest.
193	 *
194	 * @return bool
195	 */
196	public static function isGuest() {
197		return (self::$data && self::$data['username'] == ZBX_GUEST_USER);
198	}
199
200	/**
201	 * Return true if guest user has access to frontend.
202	 *
203	 * @return bool
204	 */
205	public static function isGuestAllowed() {
206		$guest = DB::select('users', [
207			'output' => ['userid'],
208			'filter' => ['username' => ZBX_GUEST_USER]
209		]);
210
211		return check_perm2system($guest[0]['userid'])
212			&& getUserGuiAccess($guest[0]['userid']) != GROUP_GUI_ACCESS_DISABLED;
213	}
214
215	/**
216	 * Returns refresh rate in seconds.
217	 *
218	 * @return int
219	 */
220	public static function getRefresh() {
221		return timeUnitToSeconds(self::$data['refresh']);
222	}
223
224	/**
225	 * Returns interface language attribute value for HTML lang tag.
226	 *
227	 * @return string
228	 */
229	public static function getLang() {
230		return (self::$data) ? substr(self::$data['lang'], 0, strpos(self::$data['lang'], '_')) : 'en';
231	}
232
233	/**
234	 * Get user ip address.
235	 *
236	 * @return string
237	 */
238	public static function getIp(): string {
239		return (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) && $_SERVER['HTTP_X_FORWARDED_FOR'] !== '')
240			? $_SERVER['HTTP_X_FORWARDED_FOR']
241			: $_SERVER['REMOTE_ADDR'];
242	}
243}
244