1<?php declare(strict_types = 1);
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
22/**
23 * Class containing methods for operations with authentication parameters.
24 */
25class CAuthentication extends CApiService {
26
27	public const ACCESS_RULES = [
28		'get' => ['min_user_type' => USER_TYPE_SUPER_ADMIN],
29		'update' => ['min_user_type' => USER_TYPE_SUPER_ADMIN]
30	];
31
32	/**
33	 * @var string
34	 */
35	protected $tableName = 'config';
36
37	/**
38	 * @var string
39	 */
40	protected $tableAlias = 'c';
41
42	/**
43	 * @var array
44	 */
45	private $output_fields = ['authentication_type', 'http_auth_enabled', 'http_login_form', 'http_strip_domains',
46		'http_case_sensitive', 'ldap_configured', 'ldap_host', 'ldap_port', 'ldap_base_dn', 'ldap_search_attribute',
47		'ldap_bind_dn', 'ldap_case_sensitive', 'ldap_bind_password', 'saml_auth_enabled', 'saml_idp_entityid',
48		'saml_sso_url', 'saml_slo_url', 'saml_username_attribute', 'saml_sp_entityid', 'saml_nameid_format',
49		'saml_sign_messages', 'saml_sign_assertions', 'saml_sign_authn_requests', 'saml_sign_logout_requests',
50		'saml_sign_logout_responses', 'saml_encrypt_nameid', 'saml_encrypt_assertions', 'saml_case_sensitive'
51	];
52
53	/**
54	 * Get authentication parameters.
55	 *
56	 * @param array $options
57	 *
58	 * @throws APIException if the input is invalid.
59	 *
60	 * @return array
61	 */
62	public function get(array $options): array {
63		$api_input_rules = ['type' => API_OBJECT, 'fields' => [
64			'output' =>	['type' => API_OUTPUT, 'in' => implode(',', $this->output_fields),
65				'default' => API_OUTPUT_EXTEND]
66		]];
67		if (!CApiInputValidator::validate($api_input_rules, $options, '/', $error)) {
68			self::exception(ZBX_API_ERROR_PARAMETERS, $error);
69		}
70
71		if ($options['output'] === API_OUTPUT_EXTEND) {
72			$options['output'] = $this->output_fields;
73		}
74
75		$db_auth = [];
76
77		$result = DBselect($this->createSelectQuery($this->tableName(), $options));
78		while ($row = DBfetch($result)) {
79			$db_auth[] = $row;
80		}
81		$db_auth = $this->unsetExtraFields($db_auth, ['configid'], []);
82
83		return $db_auth[0];
84	}
85
86	/**
87	 * Update authentication parameters.
88	 *
89	 * @param array  $auth
90	 *
91	 * @return array
92	 */
93	public function update(array $auth): array {
94		$db_auth = $this->validateUpdate($auth);
95
96		$upd_config = [];
97
98		// strings
99		$field_names = ['http_strip_domains', 'ldap_host', 'ldap_base_dn', 'ldap_search_attribute', 'ldap_bind_dn',
100			'ldap_bind_password'
101		];
102		foreach ($field_names as $field_name) {
103			if (array_key_exists($field_name, $auth) && $auth[$field_name] !== $db_auth[$field_name]) {
104				$upd_config[$field_name] = $auth[$field_name];
105			}
106		}
107
108		// integers
109		$field_names = ['authentication_type', 'http_auth_enabled', 'http_login_form', 'http_case_sensitive',
110			'ldap_configured', 'ldap_port', 'ldap_case_sensitive', 'saml_auth_enabled', 'saml_idp_entityid',
111			'saml_sso_url', 'saml_slo_url', 'saml_username_attribute', 'saml_sp_entityid', 'saml_nameid_format',
112			'saml_sign_messages', 'saml_sign_assertions', 'saml_sign_authn_requests', 'saml_sign_logout_requests',
113			'saml_sign_logout_responses', 'saml_encrypt_nameid', 'saml_encrypt_assertions', 'saml_case_sensitive'
114		];
115		foreach ($field_names as $field_name) {
116			if (array_key_exists($field_name, $auth) && $auth[$field_name] != $db_auth[$field_name]) {
117				$upd_config[$field_name] = $auth[$field_name];
118			}
119		}
120
121		if ($upd_config) {
122			DB::update('config', [
123				'values' => $upd_config,
124				'where' => ['configid' => $db_auth['configid']]
125			]);
126		}
127
128		$this->addAuditBulk(AUDIT_ACTION_UPDATE, AUDIT_RESOURCE_AUTHENTICATION,
129			[['configid' => $db_auth['configid']] + $auth], [$db_auth['configid'] => $db_auth]
130		);
131
132		return array_keys($auth);
133	}
134
135	/**
136	 * Validate updated authentication parameters.
137	 *
138	 * @param array  $auth
139	 *
140	 * @throws APIException if the input is invalid.
141	 *
142	 * @return array
143	 */
144	protected function validateUpdate(array $auth): array {
145		$api_input_rules = ['type' => API_OBJECT, 'flags' => API_NOT_EMPTY, 'fields' => [
146			'authentication_type' =>		['type' => API_INT32, 'in' => ZBX_AUTH_INTERNAL.','.ZBX_AUTH_LDAP],
147			'http_auth_enabled' =>			['type' => API_INT32, 'in' => ZBX_AUTH_HTTP_DISABLED.','.ZBX_AUTH_HTTP_ENABLED],
148			'http_login_form' =>			['type' => API_INT32, 'in' => ZBX_AUTH_FORM_ZABBIX.','.ZBX_AUTH_FORM_HTTP],
149			'http_strip_domains' =>			['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('config', 'http_strip_domains')],
150			'http_case_sensitive' =>		['type' => API_INT32, 'in' => ZBX_AUTH_CASE_INSENSITIVE.','.ZBX_AUTH_CASE_SENSITIVE],
151			'ldap_configured' =>			['type' => API_INT32, 'in' => ZBX_AUTH_LDAP_DISABLED.','.ZBX_AUTH_LDAP_ENABLED],
152			'ldap_host' =>					['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'ldap_host')],
153			'ldap_port' =>					['type' => API_INT32, 'in' => '0:65535'],
154			'ldap_base_dn' =>				['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'ldap_base_dn')],
155			'ldap_search_attribute' =>		['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'ldap_search_attribute')],
156			'ldap_bind_dn' =>				['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('config', 'ldap_bind_dn')],
157			'ldap_case_sensitive' =>		['type' => API_INT32, 'in' => ZBX_AUTH_CASE_INSENSITIVE.','.ZBX_AUTH_CASE_SENSITIVE],
158			'ldap_bind_password' =>			['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('config', 'ldap_bind_password')],
159			'saml_auth_enabled' =>			['type' => API_INT32, 'in' => ZBX_AUTH_HTTP_DISABLED.','.ZBX_AUTH_HTTP_ENABLED],
160			'saml_idp_entityid' =>			['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'saml_idp_entityid')],
161			'saml_sso_url' =>				['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'saml_sso_url')],
162			'saml_slo_url' =>				['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('config', 'saml_slo_url')],
163			'saml_username_attribute' =>	['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'saml_username_attribute')],
164			'saml_sp_entityid' =>			['type' => API_STRING_UTF8, 'flags' => API_NOT_EMPTY, 'length' => DB::getFieldLength('config', 'saml_sp_entityid')],
165			'saml_nameid_format' =>			['type' => API_STRING_UTF8, 'length' => DB::getFieldLength('config', 'saml_nameid_format')],
166			'saml_sign_messages' =>			['type' => API_INT32, 'in' => '0,1'],
167			'saml_sign_assertions' =>		['type' => API_INT32, 'in' => '0,1'],
168			'saml_sign_authn_requests' =>	['type' => API_INT32, 'in' => '0,1'],
169			'saml_sign_logout_requests' =>	['type' => API_INT32, 'in' => '0,1'],
170			'saml_sign_logout_responses' =>	['type' => API_INT32, 'in' => '0,1'],
171			'saml_encrypt_nameid' =>		['type' => API_INT32, 'in' => '0,1'],
172			'saml_encrypt_assertions' =>	['type' => API_INT32, 'in' => '0,1'],
173			'saml_case_sensitive' =>		['type' => API_INT32, 'in' => ZBX_AUTH_CASE_INSENSITIVE.','.ZBX_AUTH_CASE_SENSITIVE]
174		]];
175		if (!CApiInputValidator::validate($api_input_rules, $auth, '/', $error)) {
176			self::exception(ZBX_API_ERROR_PARAMETERS, $error);
177		}
178
179		// Check permissions.
180		if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
181			self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!'));
182		}
183
184		$output_fields = $this->output_fields;
185		$output_fields[] = 'configid';
186
187		return DB::select('config', ['output' => $output_fields])[0];
188	}
189}
190